Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/networking/zcip.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/networking/zcip.c
r1765 r2725 7 7 * Copyright (C) 2004 by David Brownell 8 8 * 9 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.9 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 10 10 */ 11 11 … … 24 24 // - link status monitoring (restart on link-up; stop on link-down) 25 25 26 #include <syslog.h>27 #include <poll.h>28 #include <sys/wait.h>29 26 #include <netinet/ether.h> 30 27 #include <net/ethernet.h> … … 35 32 36 33 #include "libbb.h" 34 #include <syslog.h> 37 35 38 36 /* We don't need more than 32 bits of the counter */ … … 40 38 41 39 struct arp_packet { 42 struct ether_header hdr;40 struct ether_header eth; 43 41 struct ether_arp arp; 44 } ATTRIBUTE_PACKED;42 } PACKED; 45 43 46 44 enum { … … 70 68 }; 71 69 72 #define VDBG(fmt,args...) \ 73 do { } while (0) 70 #define VDBG(...) do { } while (0) 71 72 73 enum { 74 sock_fd = 3 75 }; 76 77 struct globals { 78 struct sockaddr saddr; 79 struct ether_addr eth_addr; 80 } FIX_ALIASING; 81 #define G (*(struct globals*)&bb_common_bufsiz1) 82 #define saddr (G.saddr ) 83 #define eth_addr (G.eth_addr) 84 74 85 75 86 /** … … 77 88 * the first and last 256 addresses are reserved. 78 89 */ 79 static void pick(struct in_addr *ip)90 static uint32_t pick(void) 80 91 { 81 92 unsigned tmp; … … 84 95 tmp = rand() & IN_CLASSB_HOST; 85 96 } while (tmp > (IN_CLASSB_HOST - 0x0200)); 86 ip->s_addr =htonl((LINKLOCAL_ADDR + 0x0100) + tmp);97 return htonl((LINKLOCAL_ADDR + 0x0100) + tmp); 87 98 } 88 99 … … 90 101 * Broadcast an ARP packet. 91 102 */ 92 static void arp(int fd, struct sockaddr *saddr, int op, 93 const struct ether_addr *source_addr, struct in_addr source_ip, 94 const struct ether_addr *target_addr, struct in_addr target_ip) 103 static void arp( 104 /* int op, - always ARPOP_REQUEST */ 105 /* const struct ether_addr *source_eth, - always ð_addr */ 106 struct in_addr source_ip, 107 const struct ether_addr *target_eth, struct in_addr target_ip) 95 108 { 109 enum { op = ARPOP_REQUEST }; 110 #define source_eth (ð_addr) 111 96 112 struct arp_packet p; 97 113 memset(&p, 0, sizeof(p)); 98 114 99 115 // ether header 100 p. hdr.ether_type = htons(ETHERTYPE_ARP);101 memcpy(p. hdr.ether_shost, source_addr, ETH_ALEN);102 memset(p. hdr.ether_dhost, 0xff, ETH_ALEN);116 p.eth.ether_type = htons(ETHERTYPE_ARP); 117 memcpy(p.eth.ether_shost, source_eth, ETH_ALEN); 118 memset(p.eth.ether_dhost, 0xff, ETH_ALEN); 103 119 104 120 // arp request … … 108 124 p.arp.arp_pln = 4; 109 125 p.arp.arp_op = htons(op); 110 memcpy(&p.arp.arp_sha, source_ addr, ETH_ALEN);126 memcpy(&p.arp.arp_sha, source_eth, ETH_ALEN); 111 127 memcpy(&p.arp.arp_spa, &source_ip, sizeof(p.arp.arp_spa)); 112 memcpy(&p.arp.arp_tha, target_ addr, ETH_ALEN);128 memcpy(&p.arp.arp_tha, target_eth, ETH_ALEN); 113 129 memcpy(&p.arp.arp_tpa, &target_ip, sizeof(p.arp.arp_tpa)); 114 130 115 131 // send it 116 xsendto(fd, &p, sizeof(p), saddr, sizeof(*saddr)); 117 118 // Currently all callers ignore errors, that's why returns are 119 // commented out... 120 //return 0; 132 // Even though sock_fd is already bound to saddr, just send() 133 // won't work, because "socket is not connected" 134 // (and connect() won't fix that, "operation not supported"). 135 // Thus we sendto() to saddr. I wonder which sockaddr 136 // (from bind() or from sendto()?) kernel actually uses 137 // to determine iface to emit the packet from... 138 xsendto(sock_fd, &p, sizeof(p), &saddr, sizeof(saddr)); 139 #undef source_eth 121 140 } 122 141 123 142 /** 124 * Run a script. argv[2] is already NULL. 125 */ 126 static int run(char *argv[3], const char *intf, struct in_addr *ip) 143 * Run a script. 144 * argv[0]:intf argv[1]:script_name argv[2]:junk argv[3]:NULL 145 */ 146 static int run(char *argv[3], const char *param, struct in_addr *ip) 127 147 { 128 148 int status; 129 130 VDBG("%s run %s %s\n", intf, argv[0], argv[1]); 149 char *addr = addr; /* for gcc */ 150 const char *fmt = "%s %s %s" + 3; 151 152 argv[2] = (char*)param; 153 154 VDBG("%s run %s %s\n", argv[0], argv[1], argv[2]); 131 155 132 156 if (ip) { 133 char *addr = inet_ntoa(*ip);134 setenv("ip", addr, 1);135 bb_info_msg("%s %s %s", argv[1], intf, addr);157 addr = inet_ntoa(*ip); 158 xsetenv("ip", addr); 159 fmt -= 3; 136 160 } 137 138 status = wait4pid(spawn(argv)); 161 bb_info_msg(fmt, argv[2], argv[0], addr); 162 163 status = spawn_and_wait(argv + 1); 139 164 if (status < 0) { 140 bb_perror_msg("%s %s ", argv[1], intf);165 bb_perror_msg("%s %s %s" + 3, argv[2], argv[0]); 141 166 return -errno; 142 167 } 143 168 if (status != 0) 144 bb_error_msg("script %s %s failed, exitcode=%d", argv[ 0], argv[1], status);169 bb_error_msg("script %s %s failed, exitcode=%d", argv[1], argv[2], status & 0xff); 145 170 return status; 146 171 } … … 149 174 * Return milliseconds of random delay, up to "secs" seconds. 150 175 */ 151 static unsigned ALWAYS_INLINE ms_rdelay(unsigned secs)176 static ALWAYS_INLINE unsigned random_delay_ms(unsigned secs) 152 177 { 153 178 return rand() % (secs * 1000); … … 157 182 * main program 158 183 */ 159 int zcip_main(int argc, char **argv) ;160 int zcip_main(int argc , char **argv)184 int zcip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 185 int zcip_main(int argc UNUSED_PARAM, char **argv) 161 186 { 162 int state = PROBE; 163 struct ether_addr eth_addr; 164 const char *why; 165 int fd; 187 int state; 166 188 char *r_opt; 167 189 unsigned opts; 168 190 169 / * Ugly trick, but I want these zeroed in one go */191 // ugly trick, but I want these zeroed in one go 170 192 struct { 171 193 const struct in_addr null_ip; 172 194 const struct ether_addr null_addr; 173 struct sockaddr saddr;174 195 struct in_addr ip; 175 196 struct ifreq ifr; 176 char *intf;177 char *script_av[3];178 197 int timeout_ms; /* must be signed */ 179 198 unsigned conflicts; … … 185 204 #define null_ip (L.null_ip ) 186 205 #define null_addr (L.null_addr ) 187 #define saddr (L.saddr )188 206 #define ip (L.ip ) 189 207 #define ifr (L.ifr ) 190 #define intf (L.intf )191 #define script_av (L.script_av )192 208 #define timeout_ms (L.timeout_ms) 193 209 #define conflicts (L.conflicts ) … … 205 221 opt_complementary = "=2:vv:vf"; 206 222 opts = getopt32(argv, "fqr:v", &r_opt, &verbose); 223 #if !BB_MMU 224 // on NOMMU reexec early (or else we will rerun things twice) 225 if (!FOREGROUND) 226 bb_daemonize_or_rexec(0 /*was: DAEMON_CHDIR_ROOT*/, argv); 227 #endif 228 // open an ARP socket 229 // (need to do it before openlog to prevent openlog from taking 230 // fd 3 (sock_fd==3)) 231 xmove_fd(xsocket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)), sock_fd); 207 232 if (!FOREGROUND) { 208 / * Do it early, before all bb_xx_msg calls */233 // do it before all bb_xx_msg calls 209 234 openlog(applet_name, 0, LOG_DAEMON); 210 235 logmode |= LOGMODE_SYSLOG; … … 217 242 } 218 243 } 219 // On NOMMU reexec early (or else we will rerun things twice) 220 #if !BB_MMU 221 if (!FOREGROUND) 222 bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); 223 #endif 224 argc -= optind; 225 argv += optind; 226 227 intf = argv[0]; 228 script_av[0] = argv[1]; 229 setenv("interface", intf, 1); 244 argv += optind - 1; 245 246 /* Now: argv[0]:junk argv[1]:intf argv[2]:script argv[3]:NULL */ 247 /* We need to make space for script argument: */ 248 argv[0] = argv[1]; 249 argv[1] = argv[2]; 250 /* Now: argv[0]:intf argv[1]:script argv[2]:junk argv[3]:NULL */ 251 #define argv_intf (argv[0]) 252 253 xsetenv("interface", argv_intf); 230 254 231 255 // initialize the interface (modprobe, ifup, etc) 232 script_av[1] = (char*)"init"; 233 if (run(script_av, intf, NULL)) 256 if (run(argv, "init", NULL)) 234 257 return EXIT_FAILURE; 235 258 236 259 // initialize saddr 260 // saddr is: { u16 sa_family; u8 sa_data[14]; } 237 261 //memset(&saddr, 0, sizeof(saddr)); 238 safe_strncpy(saddr.sa_data, intf, sizeof(saddr.sa_data)); 239 240 // open an ARP socket 241 fd = xsocket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)); 262 //TODO: are we leaving sa_family == 0 (AF_UNSPEC)?! 263 safe_strncpy(saddr.sa_data, argv_intf, sizeof(saddr.sa_data)); 264 242 265 // bind to the interface's ARP socket 243 xbind( fd, &saddr, sizeof(saddr));266 xbind(sock_fd, &saddr, sizeof(saddr)); 244 267 245 268 // get the interface's ethernet address 246 269 //memset(&ifr, 0, sizeof(ifr)); 247 strncpy (ifr.ifr_name, intf, sizeof(ifr.ifr_name));248 xioctl( fd, SIOCGIFHWADDR, &ifr);270 strncpy_IFNAMSIZ(ifr.ifr_name, argv_intf); 271 xioctl(sock_fd, SIOCGIFHWADDR, &ifr); 249 272 memcpy(ð_addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); 250 273 251 274 // start with some stable ip address, either a function of 252 275 // the hardware address or else the last address we used. 276 // we are taking low-order four bytes, as top-order ones 277 // aren't random enough. 253 278 // NOTE: the sequence of addresses we try changes only 254 279 // depending on when we detect conflicts. 255 srand(*(unsigned*)&ifr.ifr_hwaddr.sa_data); 280 { 281 uint32_t t; 282 move_from_unaligned32(t, ((char *)ð_addr + 2)); 283 srand(t); 284 } 256 285 if (ip.s_addr == 0) 257 pick(&ip);286 ip.s_addr = pick(); 258 287 259 288 // FIXME cases to handle: … … 264 293 if (!FOREGROUND) { 265 294 #if BB_MMU 266 bb_daemonize( DAEMON_CHDIR_ROOT);295 bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/); 267 296 #endif 268 bb_info_msg("start, interface %s", intf);297 bb_info_msg("start, interface %s", argv_intf); 269 298 } 270 299 … … 273 302 // - start with some address we want to try 274 303 // - short random delay 275 // - arp probes to see if another host elseuses it304 // - arp probes to see if another host uses it 276 305 // - arp announcements that we're claiming it 277 306 // - use it 278 307 // - defend it, within limits 308 // exit if: 309 // - address is successfully obtained and -q was given: 310 // run "<script> config", then exit with exitcode 0 311 // - poll error (when does this happen?) 312 // - read error (when does this happen?) 313 // - sendto error (in arp()) (when does this happen?) 314 // - revents & POLLERR (link down). run "<script> deconfig" first 315 state = PROBE; 279 316 while (1) { 280 317 struct pollfd fds[1]; 281 318 unsigned deadline_us; 282 319 struct arp_packet p; 283 284 int source_ip_conflict = 0; 285 int target_ip_conflict = 0; 286 287 fds[0].fd = fd; 320 int source_ip_conflict; 321 int target_ip_conflict; 322 323 fds[0].fd = sock_fd; 288 324 fds[0].events = POLLIN; 289 325 fds[0].revents = 0; … … 291 327 // poll, being ready to adjust current timeout 292 328 if (!timeout_ms) { 293 timeout_ms = ms_rdelay(PROBE_WAIT);294 // FIXME setsockopt( fd, SO_ATTACH_FILTER, ...) to329 timeout_ms = random_delay_ms(PROBE_WAIT); 330 // FIXME setsockopt(sock_fd, SO_ATTACH_FILTER, ...) to 295 331 // make the kernel filter out all packets except 296 332 // ones we'd care about. … … 300 336 301 337 VDBG("...wait %d %s nprobes=%u, nclaims=%u\n", 302 timeout_ms, intf, nprobes, nclaims); 303 switch (poll(fds, 1, timeout_ms)) { 338 timeout_ms, argv_intf, nprobes, nclaims); 339 340 switch (safe_poll(fds, 1, timeout_ms)) { 341 342 default: 343 //bb_perror_msg("poll"); - done in safe_poll 344 return EXIT_FAILURE; 304 345 305 346 // timeout … … 313 354 nprobes++; 314 355 VDBG("probe/%u %s@%s\n", 315 nprobes, intf, inet_ntoa(ip));316 arp( fd, &saddr, ARPOP_REQUEST,317 ð_addr,null_ip,356 nprobes, argv_intf, inet_ntoa(ip)); 357 arp(/* ARPOP_REQUEST, */ 358 /* ð_addr, */ null_ip, 318 359 &null_addr, ip); 319 360 timeout_ms = PROBE_MIN * 1000; 320 timeout_ms += ms_rdelay(PROBE_MAX - PROBE_MIN);361 timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN); 321 362 } 322 363 else { … … 325 366 nclaims = 0; 326 367 VDBG("announce/%u %s@%s\n", 327 nclaims, intf, inet_ntoa(ip));328 arp( fd, &saddr, ARPOP_REQUEST,329 ð_addr,ip,368 nclaims, argv_intf, inet_ntoa(ip)); 369 arp(/* ARPOP_REQUEST, */ 370 /* ð_addr, */ ip, 330 371 ð_addr, ip); 331 372 timeout_ms = ANNOUNCE_INTERVAL * 1000; … … 338 379 nclaims = 0; 339 380 VDBG("announce/%u %s@%s\n", 340 nclaims, intf, inet_ntoa(ip));341 arp( fd, &saddr, ARPOP_REQUEST,342 ð_addr,ip,381 nclaims, argv_intf, inet_ntoa(ip)); 382 arp(/* ARPOP_REQUEST, */ 383 /* ð_addr, */ ip, 343 384 ð_addr, ip); 344 385 timeout_ms = ANNOUNCE_INTERVAL * 1000; … … 350 391 nclaims++; 351 392 VDBG("announce/%u %s@%s\n", 352 nclaims, intf, inet_ntoa(ip));353 arp( fd, &saddr, ARPOP_REQUEST,354 ð_addr,ip,393 nclaims, argv_intf, inet_ntoa(ip)); 394 arp(/* ARPOP_REQUEST, */ 395 /* ð_addr, */ ip, 355 396 ð_addr, ip); 356 397 timeout_ms = ANNOUNCE_INTERVAL * 1000; … … 361 402 // link is ok to use earlier 362 403 // FIXME update filters 363 script_av[1] = (char*)"config"; 364 run(script_av, intf, &ip); 404 run(argv, "config", &ip); 365 405 ready = 1; 366 406 conflicts = 0; … … 382 422 // Invalid, should never happen. Restart the whole protocol. 383 423 state = PROBE; 384 pick(&ip);424 ip.s_addr = pick(); 385 425 timeout_ms = 0; 386 426 nprobes = 0; … … 389 429 } // switch (state) 390 430 break; // case 0 (timeout) 391 // packets arriving 431 432 // packets arriving, or link went down 392 433 case 1: 393 434 // We need to adjust the timeout in case we didn't receive … … 402 443 } else { 403 444 VDBG("adjusting timeout\n"); 404 timeout_ms = diff / 1000; 405 if (!timeout_ms) timeout_ms = 1; 445 timeout_ms = (diff / 1000) | 1; /* never 0 */ 406 446 } 407 447 } … … 411 451 // FIXME: links routinely go down; 412 452 // this shouldn't necessarily exit. 413 bb_error_msg(" %s: poll error",intf);453 bb_error_msg("iface %s is down", argv_intf); 414 454 if (ready) { 415 script_av[1] = (char*)"deconfig"; 416 run(script_av, intf, &ip); 455 run(argv, "deconfig", &ip); 417 456 } 418 457 return EXIT_FAILURE; … … 422 461 423 462 // read ARP packet 424 if (recv(fd, &p, sizeof(p), 0) < 0) { 425 why = "recv"; 426 goto bad; 463 if (safe_read(sock_fd, &p, sizeof(p)) < 0) { 464 bb_perror_msg_and_die(bb_msg_read_error); 427 465 } 428 if (p. hdr.ether_type != htons(ETHERTYPE_ARP))466 if (p.eth.ether_type != htons(ETHERTYPE_ARP)) 429 467 continue; 430 431 468 #ifdef DEBUG 432 469 { 433 struct ether_addr * 434 struct ether_addr * 435 struct in_addr * 436 struct in_addr * 470 struct ether_addr *sha = (struct ether_addr *) p.arp.arp_sha; 471 struct ether_addr *tha = (struct ether_addr *) p.arp.arp_tha; 472 struct in_addr *spa = (struct in_addr *) p.arp.arp_spa; 473 struct in_addr *tpa = (struct in_addr *) p.arp.arp_tpa; 437 474 VDBG("%s recv arp type=%d, op=%d,\n", 438 intf, ntohs(p.hdr.ether_type),475 argv_intf, ntohs(p.eth.ether_type), 439 476 ntohs(p.arp.arp_op)); 440 477 VDBG("\tsource=%s %s\n", … … 447 484 #endif 448 485 if (p.arp.arp_op != htons(ARPOP_REQUEST) 449 486 && p.arp.arp_op != htons(ARPOP_REPLY)) 450 487 continue; 451 488 452 if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0 && 453 memcmp(ð_addr, &p.arp.arp_sha, ETH_ALEN) != 0) { 489 source_ip_conflict = 0; 490 target_ip_conflict = 0; 491 492 if (memcmp(p.arp.arp_spa, &ip.s_addr, sizeof(struct in_addr)) == 0 493 && memcmp(&p.arp.arp_sha, ð_addr, ETH_ALEN) != 0 494 ) { 454 495 source_ip_conflict = 1; 455 496 } 456 if (memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0 && 457 p.arp.arp_op == htons(ARPOP_REQUEST) && 458 memcmp(ð_addr, &p.arp.arp_tha, ETH_ALEN) != 0) { 497 if (p.arp.arp_op == htons(ARPOP_REQUEST) 498 && memcmp(p.arp.arp_tpa, &ip.s_addr, sizeof(struct in_addr)) == 0 499 && memcmp(&p.arp.arp_tha, ð_addr, ETH_ALEN) != 0 500 ) { 459 501 target_ip_conflict = 1; 460 502 } … … 470 512 conflicts++; 471 513 if (conflicts >= MAX_CONFLICTS) { 472 VDBG("%s ratelimit\n", intf);514 VDBG("%s ratelimit\n", argv_intf); 473 515 timeout_ms = RATE_LIMIT_INTERVAL * 1000; 474 516 state = RATE_LIMIT_PROBE; … … 476 518 477 519 // restart the whole protocol 478 pick(&ip);520 ip.s_addr = pick(); 479 521 timeout_ms = 0; 480 522 nprobes = 0; … … 488 530 state = DEFEND; 489 531 timeout_ms = DEFEND_INTERVAL * 1000; 490 arp(fd, &saddr, 491 ARPOP_REQUEST, 492 ð_addr, ip, 493 ð_addr, ip); 532 arp(/* ARPOP_REQUEST, */ 533 /* ð_addr, */ ip, 534 ð_addr, ip); 494 535 } 495 536 break; … … 500 541 VDBG("defend conflict -- starting over\n"); 501 542 ready = 0; 502 script_av[1] = (char*)"deconfig"; 503 run(script_av, intf, &ip); 543 run(argv, "deconfig", &ip); 504 544 505 545 // restart the whole protocol 506 pick(&ip);546 ip.s_addr = pick(); 507 547 timeout_ms = 0; 508 548 nprobes = 0; … … 514 554 VDBG("invalid state -- starting over\n"); 515 555 state = PROBE; 516 pick(&ip);556 ip.s_addr = pick(); 517 557 timeout_ms = 0; 518 558 nprobes = 0; … … 520 560 break; 521 561 } // switch state 522 523 562 break; // case 1 (packets arriving) 524 default:525 why = "poll";526 goto bad;527 563 } // switch poll 528 } 529 bad: 530 bb_perror_msg("%s, %s", intf, why); 531 return EXIT_FAILURE; 564 } // while (1) 565 #undef argv_intf 532 566 }
Note:
See TracChangeset
for help on using the changeset viewer.