Changeset 904 in MondoRescue for trunk/mindi-busybox/networking/zcip.c
- Timestamp:
- Oct 25, 2006, 1:51:57 AM (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/mindi-busybox/networking/zcip.c
r821 r904 15 15 */ 16 16 17 // #defineDEBUG17 //#define DEBUG 18 18 19 19 // TODO: … … 43 43 struct arp_packet { 44 44 struct ether_header hdr; 45 // FIXME this part is netinet/if_ether.h "struct ether_arp" 46 struct arphdr arp; 47 struct ether_addr source_addr; 48 struct in_addr source_ip; 49 struct ether_addr target_addr; 50 struct in_addr target_ip; 45 struct ether_arp arp; 51 46 } ATTRIBUTE_PACKED; 52 47 … … 68 63 }; 69 64 70 static const struct in_addr null_ip = { 0 }; 71 static const struct ether_addr null_addr = { {0, 0, 0, 0, 0, 0} }; 72 73 static int verbose = 0; 65 /* States during the configuration process. */ 66 enum { 67 PROBE = 0, 68 RATE_LIMIT_PROBE, 69 ANNOUNCE, 70 MONITOR, 71 DEFEND 72 }; 73 74 /* Implicitly zero-initialized */ 75 static const struct in_addr null_ip; 76 static const struct ether_addr null_addr; 77 static int verbose; 74 78 75 79 #define DBG(fmt,args...) \ … … 100 104 { 101 105 struct arp_packet p; 106 memset(&p, 0, sizeof(p)); 102 107 103 108 // ether header … … 107 112 108 113 // arp request 109 p.arp.ar _hrd = htons(ARPHRD_ETHER);110 p.arp.ar _pro = htons(ETHERTYPE_IP);111 p.arp.ar _hln = ETH_ALEN;112 p.arp.ar _pln = 4;113 p.arp.ar _op = htons(op);114 memcpy(&p. source_addr, source_addr, ETH_ALEN);115 memcpy(&p. source_ip, &source_ip, sizeof (p.source_ip));116 memcpy(&p. target_addr, target_addr, ETH_ALEN);117 memcpy(&p. target_ip, &target_ip, sizeof (p.target_ip));114 p.arp.arp_hrd = htons(ARPHRD_ETHER); 115 p.arp.arp_pro = htons(ETHERTYPE_IP); 116 p.arp.arp_hln = ETH_ALEN; 117 p.arp.arp_pln = 4; 118 p.arp.arp_op = htons(op); 119 memcpy(&p.arp.arp_sha, source_addr, ETH_ALEN); 120 memcpy(&p.arp.arp_spa, &source_ip, sizeof (p.arp.arp_spa)); 121 memcpy(&p.arp.arp_tha, target_addr, ETH_ALEN); 122 memcpy(&p.arp.arp_tpa, &target_ip, sizeof (p.arp.arp_tpa)); 118 123 119 124 // send it … … 196 201 int ready = 0; 197 202 suseconds_t timeout = 0; // milliseconds 198 time_t defend = 0;199 203 unsigned conflicts = 0; 200 204 unsigned nprobes = 0; 201 205 unsigned nclaims = 0; 202 206 int t; 207 int state = PROBE; 203 208 204 209 // parse commandline: prog [options] ifname script … … 307 312 fds[0].revents = 0; 308 313 314 int source_ip_conflict = 0; 315 int target_ip_conflict = 0; 316 309 317 // poll, being ready to adjust current timeout 310 318 if (!timeout) { … … 314 322 // ones we'd care about. 315 323 } 324 // set tv1 to the point in time when we timeout 316 325 gettimeofday(&tv1, NULL); 317 326 tv1.tv_usec += (timeout % 1000) * 1000; … … 326 335 switch (poll(fds, 1, timeout)) { 327 336 328 // timeout s trigger protocol transitions337 // timeout 329 338 case 0: 330 // probes 331 if (nprobes < PROBE_NUM) { 332 nprobes++; 333 VDBG("probe/%d %s@%s\n", 334 nprobes, intf, inet_ntoa(ip)); 335 (void)arp(fd, &saddr, ARPOP_REQUEST, 336 &addr, null_ip, 337 &null_addr, ip); 339 VDBG("state = %d\n", state); 340 switch (state) { 341 case PROBE: 342 // timeouts in the PROBE state means no conflicting ARP packets 343 // have been received, so we can progress through the states 338 344 if (nprobes < PROBE_NUM) { 345 nprobes++; 346 VDBG("probe/%d %s@%s\n", 347 nprobes, intf, inet_ntoa(ip)); 348 (void)arp(fd, &saddr, ARPOP_REQUEST, 349 &addr, null_ip, 350 &null_addr, ip); 339 351 timeout = PROBE_MIN * 1000; 340 352 timeout += ms_rdelay(PROBE_MAX 341 353 - PROBE_MIN); 342 } else 343 timeout = ANNOUNCE_WAIT * 1000; 344 } 345 // then announcements 346 else if (nclaims < ANNOUNCE_NUM) { 347 nclaims++; 354 } 355 else { 356 // Switch to announce state. 357 state = ANNOUNCE; 358 nclaims = 0; 359 VDBG("announce/%d %s@%s\n", 360 nclaims, intf, inet_ntoa(ip)); 361 (void)arp(fd, &saddr, ARPOP_REQUEST, 362 &addr, ip, 363 &addr, ip); 364 timeout = ANNOUNCE_INTERVAL * 1000; 365 } 366 break; 367 case RATE_LIMIT_PROBE: 368 // timeouts in the RATE_LIMIT_PROBE state means no conflicting ARP packets 369 // have been received, so we can move immediately to the announce state 370 state = ANNOUNCE; 371 nclaims = 0; 348 372 VDBG("announce/%d %s@%s\n", 349 373 nclaims, intf, inet_ntoa(ip)); … … 351 375 &addr, ip, 352 376 &addr, ip); 377 timeout = ANNOUNCE_INTERVAL * 1000; 378 break; 379 case ANNOUNCE: 380 // timeouts in the ANNOUNCE state means no conflicting ARP packets 381 // have been received, so we can progress through the states 353 382 if (nclaims < ANNOUNCE_NUM) { 383 nclaims++; 384 VDBG("announce/%d %s@%s\n", 385 nclaims, intf, inet_ntoa(ip)); 386 (void)arp(fd, &saddr, ARPOP_REQUEST, 387 &addr, ip, 388 &addr, ip); 354 389 timeout = ANNOUNCE_INTERVAL * 1000; 355 } else { 390 } 391 else { 392 // Switch to monitor state. 393 state = MONITOR; 356 394 // link is ok to use earlier 395 // FIXME update filters 357 396 run(script, "config", intf, &ip); 358 397 ready = 1; 359 398 conflicts = 0; 360 timeout = -1; 399 timeout = -1; // Never timeout in the monitor state. 361 400 362 401 // NOTE: all other exit paths … … 364 403 if (quit) 365 404 return EXIT_SUCCESS; 366 // FIXME update filters 367 } 368 } 369 break; 370 405 } 406 break; 407 case DEFEND: 408 // We won! No ARP replies, so just go back to monitor. 409 state = MONITOR; 410 timeout = -1; 411 conflicts = 0; 412 break; 413 default: 414 // Invalid, should never happen. Restart the whole protocol. 415 state = PROBE; 416 pick(&ip); 417 timeout = 0; 418 nprobes = 0; 419 nclaims = 0; 420 break; 421 } // switch (state) 422 break; // case 0 (timeout) 371 423 // packets arriving 372 424 case 1: 373 // maybe adjust timeout 425 // We need to adjust the timeout in case we didn't receive 426 // a conflicting packet. 374 427 if (timeout > 0) { 375 428 struct timeval tv2; … … 377 430 gettimeofday(&tv2, NULL); 378 431 if (timercmp(&tv1, &tv2, <)) { 432 // Current time is greater than the expected timeout time. 433 // Should never happen. 434 VDBG("missed an expected timeout\n"); 379 435 timeout = 0; 380 436 } else { 437 VDBG("adjusting timeout\n"); 381 438 timersub(&tv1, &tv2, &tv1); 382 439 timeout = 1000 * tv1.tv_sec … … 384 441 } 385 442 } 443 386 444 if ((fds[0].revents & POLLIN) == 0) { 387 445 if (fds[0].revents & POLLERR) { … … 397 455 continue; 398 456 } 457 399 458 // read ARP packet 400 459 if (recv(fd, &p, sizeof (p), 0) < 0) { … … 405 464 continue; 406 465 407 VDBG("%s recv arp type=%d, op=%d,\n", 466 #ifdef DEBUG 467 { 468 struct ether_addr * sha = (struct ether_addr *) p.arp.arp_sha; 469 struct ether_addr * tha = (struct ether_addr *) p.arp.arp_tha; 470 struct in_addr * spa = (struct in_addr *) p.arp.arp_spa; 471 struct in_addr * tpa = (struct in_addr *) p.arp.arp_tpa; 472 VDBG("%s recv arp type=%d, op=%d,\n", 408 473 intf, ntohs(p.hdr.ether_type), 409 ntohs(p.arp.ar_op)); 410 VDBG("\tsource=%s %s\n", 411 ether_ntoa(&p.source_addr), 412 inet_ntoa(p.source_ip)); 413 VDBG("\ttarget=%s %s\n", 414 ether_ntoa(&p.target_addr), 415 inet_ntoa(p.target_ip)); 416 if (p.arp.ar_op != htons(ARPOP_REQUEST) 417 && p.arp.ar_op != htons(ARPOP_REPLY)) 474 ntohs(p.arp.arp_op)); 475 VDBG("\tsource=%s %s\n", 476 ether_ntoa(sha), 477 inet_ntoa(*spa)); 478 VDBG("\ttarget=%s %s\n", 479 ether_ntoa(tha), 480 inet_ntoa(*tpa)); 481 } 482 #endif 483 if (p.arp.arp_op != htons(ARPOP_REQUEST) 484 && p.arp.arp_op != htons(ARPOP_REPLY)) 418 485 continue; 419 486 420 // some cases are always conflicts 421 if ((p.source_ip.s_addr == ip.s_addr) 422 && (memcmp(&addr, &p.source_addr, 423 ETH_ALEN) != 0)) { 424 collision: 425 VDBG("%s ARP conflict from %s\n", intf, 426 ether_ntoa(&p.source_addr)); 427 if (ready) { 428 time_t now = time(0); 429 430 if ((defend + DEFEND_INTERVAL) 431 < now) { 432 defend = now; 433 (void)arp(fd, &saddr, 434 ARPOP_REQUEST, 435 &addr, ip, 436 &addr, ip); 437 VDBG("%s defend\n", intf); 438 timeout = -1; 439 continue; 487 if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0 && 488 memcmp(&addr, &p.arp.arp_sha, ETH_ALEN) != 0) { 489 source_ip_conflict = 1; 490 } 491 if (memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0 && 492 p.arp.arp_op == htons(ARPOP_REQUEST) && 493 memcmp(&addr, &p.arp.arp_tha, ETH_ALEN) != 0) { 494 target_ip_conflict = 1; 495 } 496 497 VDBG("state = %d, source ip conflict = %d, target ip conflict = %d\n", 498 state, source_ip_conflict, target_ip_conflict); 499 switch (state) { 500 case PROBE: 501 case ANNOUNCE: 502 // When probing or announcing, check for source IP conflicts 503 // and other hosts doing ARP probes (target IP conflicts). 504 if (source_ip_conflict || target_ip_conflict) { 505 conflicts++; 506 if (conflicts >= MAX_CONFLICTS) { 507 VDBG("%s ratelimit\n", intf); 508 timeout = RATE_LIMIT_INTERVAL * 1000; 509 state = RATE_LIMIT_PROBE; 440 510 } 441 defend = now; 511 512 // restart the whole protocol 513 pick(&ip); 514 timeout = 0; 515 nprobes = 0; 516 nclaims = 0; 517 } 518 break; 519 case MONITOR: 520 // If a conflict, we try to defend with a single ARP probe. 521 if (source_ip_conflict) { 522 VDBG("monitor conflict -- defending\n"); 523 state = DEFEND; 524 timeout = DEFEND_INTERVAL * 1000; 525 (void)arp(fd, &saddr, 526 ARPOP_REQUEST, 527 &addr, ip, 528 &addr, ip); 529 } 530 break; 531 case DEFEND: 532 // Well, we tried. Start over (on conflict). 533 if (source_ip_conflict) { 534 state = PROBE; 535 VDBG("defend conflict -- starting over\n"); 442 536 ready = 0; 443 537 run(script, "deconfig", intf, &ip); 444 // FIXME rm filters: setsockopt(fd, 445 // SO_DETACH_FILTER, ...) 446 } 447 conflicts++; 448 if (conflicts >= MAX_CONFLICTS) { 449 VDBG("%s ratelimit\n", intf); 450 sleep(RATE_LIMIT_INTERVAL); 451 } 452 // restart the whole protocol 538 539 // restart the whole protocol 540 pick(&ip); 541 timeout = 0; 542 nprobes = 0; 543 nclaims = 0; 544 } 545 break; 546 default: 547 // Invalid, should never happen. Restart the whole protocol. 548 VDBG("invalid state -- starting over\n"); 549 state = PROBE; 453 550 pick(&ip); 454 551 timeout = 0; 455 552 nprobes = 0; 456 553 nclaims = 0; 457 } 458 // two hosts probing one address is a collision too 459 else if (p.target_ip.s_addr == ip.s_addr 460 && nclaims == 0 461 && p.arp.ar_op == htons(ARPOP_REQUEST) 462 && memcmp(&addr, &p.target_addr, 463 ETH_ALEN) != 0) { 464 goto collision; 465 } 466 break; 467 554 break; 555 } // switch state 556 557 break; // case 1 (packets arriving) 468 558 default: 469 559 why = "poll"; 470 560 goto bad; 471 } 561 } // switch poll 472 562 } 473 563 bad:
Note:
See TracChangeset
for help on using the changeset viewer.