aboutsummaryrefslogtreecommitdiff
path: root/networking/zcip.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-09-03 12:20:36 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-09-03 12:20:36 +0000
commit87d80dcc3e81d80caa11ed88fe6136ffe3e605dc (patch)
treef491514966641b63b74ba133b1a2177689fc6ba0 /networking/zcip.c
parent06ab5fb6b9d641ee184facb81eaee718e418d9b2 (diff)
downloadbusybox-w32-87d80dcc3e81d80caa11ed88fe6136ffe3e605dc.tar.gz
busybox-w32-87d80dcc3e81d80caa11ed88fe6136ffe3e605dc.tar.bz2
busybox-w32-87d80dcc3e81d80caa11ed88fe6136ffe3e605dc.zip
zcip: apply patch from
http://bugs.busybox.net/view.php?id=1005 zcip does not claim another IP after defending
Diffstat (limited to 'networking/zcip.c')
-rw-r--r--networking/zcip.c274
1 files changed, 182 insertions, 92 deletions
diff --git a/networking/zcip.c b/networking/zcip.c
index d49bb7669..8e6d8792d 100644
--- a/networking/zcip.c
+++ b/networking/zcip.c
@@ -15,7 +15,7 @@
15 * certainly be used. Its naming is built over multicast DNS. 15 * certainly be used. Its naming is built over multicast DNS.
16 */ 16 */
17 17
18// #define DEBUG 18//#define DEBUG
19 19
20// TODO: 20// TODO:
21// - more real-world usage/testing, especially daemon mode 21// - more real-world usage/testing, especially daemon mode
@@ -43,12 +43,7 @@
43 43
44struct arp_packet { 44struct arp_packet {
45 struct ether_header hdr; 45 struct ether_header hdr;
46 // FIXME this part is netinet/if_ether.h "struct ether_arp" 46 struct ether_arp arp;
47 struct arphdr arp;
48 struct ether_addr source_addr;
49 struct in_addr source_ip;
50 struct ether_addr target_addr;
51 struct in_addr target_ip;
52} ATTRIBUTE_PACKED; 47} ATTRIBUTE_PACKED;
53 48
54enum { 49enum {
@@ -68,10 +63,19 @@ enum {
68 DEFEND_INTERVAL = 10 63 DEFEND_INTERVAL = 10
69}; 64};
70 65
71static const struct in_addr null_ip = { 0 }; 66/* States during the configuration process. */
72static const struct ether_addr null_addr = { {0, 0, 0, 0, 0, 0} }; 67enum {
68 PROBE = 0,
69 RATE_LIMIT_PROBE,
70 ANNOUNCE,
71 MONITOR,
72 DEFEND
73};
73 74
74static int verbose = 0; 75/* Implicitly zero-initialized */
76static const struct in_addr null_ip;
77static const struct ether_addr null_addr;
78static int verbose;
75 79
76#define DBG(fmt,args...) \ 80#define DBG(fmt,args...) \
77 do { } while (0) 81 do { } while (0)
@@ -100,6 +104,7 @@ static int arp(int fd, struct sockaddr *saddr, int op,
100 const struct ether_addr *target_addr, struct in_addr target_ip) 104 const struct ether_addr *target_addr, struct in_addr target_ip)
101{ 105{
102 struct arp_packet p; 106 struct arp_packet p;
107 memset(&p, 0, sizeof(p));
103 108
104 // ether header 109 // ether header
105 p.hdr.ether_type = htons(ETHERTYPE_ARP); 110 p.hdr.ether_type = htons(ETHERTYPE_ARP);
@@ -107,15 +112,15 @@ static int arp(int fd, struct sockaddr *saddr, int op,
107 memset(p.hdr.ether_dhost, 0xff, ETH_ALEN); 112 memset(p.hdr.ether_dhost, 0xff, ETH_ALEN);
108 113
109 // arp request 114 // arp request
110 p.arp.ar_hrd = htons(ARPHRD_ETHER); 115 p.arp.arp_hrd = htons(ARPHRD_ETHER);
111 p.arp.ar_pro = htons(ETHERTYPE_IP); 116 p.arp.arp_pro = htons(ETHERTYPE_IP);
112 p.arp.ar_hln = ETH_ALEN; 117 p.arp.arp_hln = ETH_ALEN;
113 p.arp.ar_pln = 4; 118 p.arp.arp_pln = 4;
114 p.arp.ar_op = htons(op); 119 p.arp.arp_op = htons(op);
115 memcpy(&p.source_addr, source_addr, ETH_ALEN); 120 memcpy(&p.arp.arp_sha, source_addr, ETH_ALEN);
116 memcpy(&p.source_ip, &source_ip, sizeof (p.source_ip)); 121 memcpy(&p.arp.arp_spa, &source_ip, sizeof (p.arp.arp_spa));
117 memcpy(&p.target_addr, target_addr, ETH_ALEN); 122 memcpy(&p.arp.arp_tha, target_addr, ETH_ALEN);
118 memcpy(&p.target_ip, &target_ip, sizeof (p.target_ip)); 123 memcpy(&p.arp.arp_tpa, &target_ip, sizeof (p.arp.arp_tpa));
119 124
120 // send it 125 // send it
121 if (sendto(fd, &p, sizeof (p), 0, saddr, sizeof (*saddr)) < 0) { 126 if (sendto(fd, &p, sizeof (p), 0, saddr, sizeof (*saddr)) < 0) {
@@ -196,11 +201,11 @@ int zcip_main(int argc, char *argv[])
196 int fd; 201 int fd;
197 int ready = 0; 202 int ready = 0;
198 suseconds_t timeout = 0; // milliseconds 203 suseconds_t timeout = 0; // milliseconds
199 time_t defend = 0;
200 unsigned conflicts = 0; 204 unsigned conflicts = 0;
201 unsigned nprobes = 0; 205 unsigned nprobes = 0;
202 unsigned nclaims = 0; 206 unsigned nclaims = 0;
203 int t; 207 int t;
208 int state = PROBE;
204 209
205 // parse commandline: prog [options] ifname script 210 // parse commandline: prog [options] ifname script
206 while ((t = getopt(argc, argv, "fqr:v")) != EOF) { 211 while ((t = getopt(argc, argv, "fqr:v")) != EOF) {
@@ -307,6 +312,9 @@ fail:
307 fds[0].events = POLLIN; 312 fds[0].events = POLLIN;
308 fds[0].revents = 0; 313 fds[0].revents = 0;
309 314
315 int source_ip_conflict = 0;
316 int target_ip_conflict = 0;
317
310 // poll, being ready to adjust current timeout 318 // poll, being ready to adjust current timeout
311 if (!timeout) { 319 if (!timeout) {
312 timeout = ms_rdelay(PROBE_WAIT); 320 timeout = ms_rdelay(PROBE_WAIT);
@@ -314,6 +322,7 @@ fail:
314 // make the kernel filter out all packets except 322 // make the kernel filter out all packets except
315 // ones we'd care about. 323 // ones we'd care about.
316 } 324 }
325 // set tv1 to the point in time when we timeout
317 gettimeofday(&tv1, NULL); 326 gettimeofday(&tv1, NULL);
318 tv1.tv_usec += (timeout % 1000) * 1000; 327 tv1.tv_usec += (timeout % 1000) * 1000;
319 while (tv1.tv_usec > 1000000) { 328 while (tv1.tv_usec > 1000000) {
@@ -326,64 +335,113 @@ fail:
326 timeout, intf, nprobes, nclaims); 335 timeout, intf, nprobes, nclaims);
327 switch (poll(fds, 1, timeout)) { 336 switch (poll(fds, 1, timeout)) {
328 337
329 // timeouts trigger protocol transitions 338 // timeout
330 case 0: 339 case 0:
331 // probes 340 VDBG("state = %d\n", state);
332 if (nprobes < PROBE_NUM) { 341 switch (state) {
333 nprobes++; 342 case PROBE:
334 VDBG("probe/%d %s@%s\n", 343 // timeouts in the PROBE state means no conflicting ARP packets
335 nprobes, intf, inet_ntoa(ip)); 344 // have been received, so we can progress through the states
336 (void)arp(fd, &saddr, ARPOP_REQUEST,
337 &addr, null_ip,
338 &null_addr, ip);
339 if (nprobes < PROBE_NUM) { 345 if (nprobes < PROBE_NUM) {
346 nprobes++;
347 VDBG("probe/%d %s@%s\n",
348 nprobes, intf, inet_ntoa(ip));
349 (void)arp(fd, &saddr, ARPOP_REQUEST,
350 &addr, null_ip,
351 &null_addr, ip);
340 timeout = PROBE_MIN * 1000; 352 timeout = PROBE_MIN * 1000;
341 timeout += ms_rdelay(PROBE_MAX 353 timeout += ms_rdelay(PROBE_MAX
342 - PROBE_MIN); 354 - PROBE_MIN);
343 } else 355 }
344 timeout = ANNOUNCE_WAIT * 1000; 356 else {
345 } 357 // Switch to announce state.
346 // then announcements 358 state = ANNOUNCE;
347 else if (nclaims < ANNOUNCE_NUM) { 359 nclaims = 0;
348 nclaims++; 360 VDBG("announce/%d %s@%s\n",
361 nclaims, intf, inet_ntoa(ip));
362 (void)arp(fd, &saddr, ARPOP_REQUEST,
363 &addr, ip,
364 &addr, ip);
365 timeout = ANNOUNCE_INTERVAL * 1000;
366 }
367 break;
368 case RATE_LIMIT_PROBE:
369 // timeouts in the RATE_LIMIT_PROBE state means no conflicting ARP packets
370 // have been received, so we can move immediately to the announce state
371 state = ANNOUNCE;
372 nclaims = 0;
349 VDBG("announce/%d %s@%s\n", 373 VDBG("announce/%d %s@%s\n",
350 nclaims, intf, inet_ntoa(ip)); 374 nclaims, intf, inet_ntoa(ip));
351 (void)arp(fd, &saddr, ARPOP_REQUEST, 375 (void)arp(fd, &saddr, ARPOP_REQUEST,
352 &addr, ip, 376 &addr, ip,
353 &addr, ip); 377 &addr, ip);
378 timeout = ANNOUNCE_INTERVAL * 1000;
379 break;
380 case ANNOUNCE:
381 // timeouts in the ANNOUNCE state means no conflicting ARP packets
382 // have been received, so we can progress through the states
354 if (nclaims < ANNOUNCE_NUM) { 383 if (nclaims < ANNOUNCE_NUM) {
384 nclaims++;
385 VDBG("announce/%d %s@%s\n",
386 nclaims, intf, inet_ntoa(ip));
387 (void)arp(fd, &saddr, ARPOP_REQUEST,
388 &addr, ip,
389 &addr, ip);
355 timeout = ANNOUNCE_INTERVAL * 1000; 390 timeout = ANNOUNCE_INTERVAL * 1000;
356 } else { 391 }
392 else {
393 // Switch to monitor state.
394 state = MONITOR;
357 // link is ok to use earlier 395 // link is ok to use earlier
396 // FIXME update filters
358 run(script, "config", intf, &ip); 397 run(script, "config", intf, &ip);
359 ready = 1; 398 ready = 1;
360 conflicts = 0; 399 conflicts = 0;
361 timeout = -1; 400 timeout = -1; // Never timeout in the monitor state.
362 401
363 // NOTE: all other exit paths 402 // NOTE: all other exit paths
364 // should deconfig ... 403 // should deconfig ...
365 if (quit) 404 if (quit)
366 return EXIT_SUCCESS; 405 return EXIT_SUCCESS;
367 // FIXME update filters
368 } 406 }
369 } 407 break;
370 break; 408 case DEFEND:
371 409 // We won! No ARP replies, so just go back to monitor.
410 state = MONITOR;
411 timeout = -1;
412 conflicts = 0;
413 break;
414 default:
415 // Invalid, should never happen. Restart the whole protocol.
416 state = PROBE;
417 pick(&ip);
418 timeout = 0;
419 nprobes = 0;
420 nclaims = 0;
421 break;
422 } // switch (state)
423 break; // case 0 (timeout)
372 // packets arriving 424 // packets arriving
373 case 1: 425 case 1:
374 // maybe adjust timeout 426 // We need to adjust the timeout in case we didn't receive
427 // a conflicting packet.
375 if (timeout > 0) { 428 if (timeout > 0) {
376 struct timeval tv2; 429 struct timeval tv2;
377 430
378 gettimeofday(&tv2, NULL); 431 gettimeofday(&tv2, NULL);
379 if (timercmp(&tv1, &tv2, <)) { 432 if (timercmp(&tv1, &tv2, <)) {
433 // Current time is greater than the expected timeout time.
434 // Should never happen.
435 VDBG("missed an expected timeout\n");
380 timeout = 0; 436 timeout = 0;
381 } else { 437 } else {
438 VDBG("adjusting timeout\n");
382 timersub(&tv1, &tv2, &tv1); 439 timersub(&tv1, &tv2, &tv1);
383 timeout = 1000 * tv1.tv_sec 440 timeout = 1000 * tv1.tv_sec
384 + tv1.tv_usec / 1000; 441 + tv1.tv_usec / 1000;
385 } 442 }
386 } 443 }
444
387 if ((fds[0].revents & POLLIN) == 0) { 445 if ((fds[0].revents & POLLIN) == 0) {
388 if (fds[0].revents & POLLERR) { 446 if (fds[0].revents & POLLERR) {
389 // FIXME: links routinely go down; 447 // FIXME: links routinely go down;
@@ -397,6 +455,7 @@ fail:
397 } 455 }
398 continue; 456 continue;
399 } 457 }
458
400 // read ARP packet 459 // read ARP packet
401 if (recv(fd, &p, sizeof (p), 0) < 0) { 460 if (recv(fd, &p, sizeof (p), 0) < 0) {
402 why = "recv"; 461 why = "recv";
@@ -405,71 +464,102 @@ fail:
405 if (p.hdr.ether_type != htons(ETHERTYPE_ARP)) 464 if (p.hdr.ether_type != htons(ETHERTYPE_ARP))
406 continue; 465 continue;
407 466
408 VDBG("%s recv arp type=%d, op=%d,\n", 467#ifdef DEBUG
468 {
469 struct ether_addr * sha = (struct ether_addr *) p.arp.arp_sha;
470 struct ether_addr * tha = (struct ether_addr *) p.arp.arp_tha;
471 struct in_addr * spa = (struct in_addr *) p.arp.arp_spa;
472 struct in_addr * tpa = (struct in_addr *) p.arp.arp_tpa;
473 VDBG("%s recv arp type=%d, op=%d,\n",
409 intf, ntohs(p.hdr.ether_type), 474 intf, ntohs(p.hdr.ether_type),
410 ntohs(p.arp.ar_op)); 475 ntohs(p.arp.arp_op));
411 VDBG("\tsource=%s %s\n", 476 VDBG("\tsource=%s %s\n",
412 ether_ntoa(&p.source_addr), 477 ether_ntoa(sha),
413 inet_ntoa(p.source_ip)); 478 inet_ntoa(*spa));
414 VDBG("\ttarget=%s %s\n", 479 VDBG("\ttarget=%s %s\n",
415 ether_ntoa(&p.target_addr), 480 ether_ntoa(tha),
416 inet_ntoa(p.target_ip)); 481 inet_ntoa(*tpa));
417 if (p.arp.ar_op != htons(ARPOP_REQUEST) 482 }
418 && p.arp.ar_op != htons(ARPOP_REPLY)) 483#endif
484 if (p.arp.arp_op != htons(ARPOP_REQUEST)
485 && p.arp.arp_op != htons(ARPOP_REPLY))
419 continue; 486 continue;
420 487
421 // some cases are always conflicts 488 if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0 &&
422 if ((p.source_ip.s_addr == ip.s_addr) 489 memcmp(&addr, &p.arp.arp_sha, ETH_ALEN) != 0) {
423 && (memcmp(&addr, &p.source_addr, 490 source_ip_conflict = 1;
424 ETH_ALEN) != 0)) { 491 }
425collision: 492 if (memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0 &&
426 VDBG("%s ARP conflict from %s\n", intf, 493 p.arp.arp_op == htons(ARPOP_REQUEST) &&
427 ether_ntoa(&p.source_addr)); 494 memcmp(&addr, &p.arp.arp_tha, ETH_ALEN) != 0) {
428 if (ready) { 495 target_ip_conflict = 1;
429 time_t now = time(0); 496 }
430 497
431 if ((defend + DEFEND_INTERVAL) 498 VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n",
432 < now) { 499 state, source_ip_conflict, target_ip_conflict);
433 defend = now; 500 switch (state) {
434 (void)arp(fd, &saddr, 501 case PROBE:
435 ARPOP_REQUEST, 502 case ANNOUNCE:
436 &addr, ip, 503 // When probing or announcing, check for source IP conflicts
437 &addr, ip); 504 // and other hosts doing ARP probes (target IP conflicts).
438 VDBG("%s defend\n", intf); 505 if (source_ip_conflict || target_ip_conflict) {
439 timeout = -1; 506 conflicts++;
440 continue; 507 if (conflicts >= MAX_CONFLICTS) {
508 VDBG("%s ratelimit\n", intf);
509 timeout = RATE_LIMIT_INTERVAL * 1000;
510 state = RATE_LIMIT_PROBE;
441 } 511 }
442 defend = now; 512
513 // restart the whole protocol
514 pick(&ip);
515 timeout = 0;
516 nprobes = 0;
517 nclaims = 0;
518 }
519 break;
520 case MONITOR:
521 // If a conflict, we try to defend with a single ARP probe.
522 if (source_ip_conflict) {
523 VDBG("monitor conflict -- defending\n");
524 state = DEFEND;
525 timeout = DEFEND_INTERVAL * 1000;
526 (void)arp(fd, &saddr,
527 ARPOP_REQUEST,
528 &addr, ip,
529 &addr, ip);
530 }
531 break;
532 case DEFEND:
533 // Well, we tried. Start over (on conflict).
534 if (source_ip_conflict) {
535 state = PROBE;
536 VDBG("defend conflict -- starting over\n");
443 ready = 0; 537 ready = 0;
444 run(script, "deconfig", intf, &ip); 538 run(script, "deconfig", intf, &ip);
445 // FIXME rm filters: setsockopt(fd, 539
446 // SO_DETACH_FILTER, ...) 540 // restart the whole protocol
447 } 541 pick(&ip);
448 conflicts++; 542 timeout = 0;
449 if (conflicts >= MAX_CONFLICTS) { 543 nprobes = 0;
450 VDBG("%s ratelimit\n", intf); 544 nclaims = 0;
451 sleep(RATE_LIMIT_INTERVAL);
452 } 545 }
453 // restart the whole protocol 546 break;
547 default:
548 // Invalid, should never happen. Restart the whole protocol.
549 VDBG("invalid state -- starting over\n");
550 state = PROBE;
454 pick(&ip); 551 pick(&ip);
455 timeout = 0; 552 timeout = 0;
456 nprobes = 0; 553 nprobes = 0;
457 nclaims = 0; 554 nclaims = 0;
458 } 555 break;
459 // two hosts probing one address is a collision too 556 } // switch state
460 else if (p.target_ip.s_addr == ip.s_addr
461 && nclaims == 0
462 && p.arp.ar_op == htons(ARPOP_REQUEST)
463 && memcmp(&addr, &p.target_addr,
464 ETH_ALEN) != 0) {
465 goto collision;
466 }
467 break;
468 557
558 break; // case 1 (packets arriving)
469 default: 559 default:
470 why = "poll"; 560 why = "poll";
471 goto bad; 561 goto bad;
472 } 562 } // switch poll
473 } 563 }
474bad: 564bad:
475 if (foreground) 565 if (foreground)