diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2015-08-04 14:30:31 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2015-08-04 14:30:31 +0200 |
commit | e3475838354d6bba414ab8cdc2211313ad29dc9d (patch) | |
tree | d69db28b9ba48596afd2e1df8e6fe28d04c52f65 | |
parent | 99e30be38bc167a3b5729154a27ccdb15bbaadb2 (diff) | |
download | busybox-w32-e3475838354d6bba414ab8cdc2211313ad29dc9d.tar.gz busybox-w32-e3475838354d6bba414ab8cdc2211313ad29dc9d.tar.bz2 busybox-w32-e3475838354d6bba414ab8cdc2211313ad29dc9d.zip |
zcip: another code shrink
function old new delta
send_arp_request - 185 +185
zcip_main 1273 1272 -1
pick_nip 40 - -40
arp 185 - -185
------------------------------------------------------------------------------
(add/remove: 1/2 grow/shrink: 0/1 up/down: 185/-226) Total: -41 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/zcip.c | 307 |
1 files changed, 148 insertions, 159 deletions
diff --git a/networking/zcip.c b/networking/zcip.c index 5877a8317..a167c7e91 100644 --- a/networking/zcip.c +++ b/networking/zcip.c | |||
@@ -90,7 +90,7 @@ enum { | |||
90 | 90 | ||
91 | struct globals { | 91 | struct globals { |
92 | struct sockaddr iface_sockaddr; | 92 | struct sockaddr iface_sockaddr; |
93 | struct ether_addr eth_addr; | 93 | struct ether_addr our_ethaddr; |
94 | uint32_t localnet_ip; | 94 | uint32_t localnet_ip; |
95 | } FIX_ALIASING; | 95 | } FIX_ALIASING; |
96 | #define G (*(struct globals*)&bb_common_bufsiz1) | 96 | #define G (*(struct globals*)&bb_common_bufsiz1) |
@@ -121,14 +121,14 @@ static const char *nip_to_a(uint32_t nip) | |||
121 | /** | 121 | /** |
122 | * Broadcast an ARP packet. | 122 | * Broadcast an ARP packet. |
123 | */ | 123 | */ |
124 | static void arp( | 124 | static void send_arp_request( |
125 | /* int op, - always ARPOP_REQUEST */ | 125 | /* int op, - always ARPOP_REQUEST */ |
126 | /* const struct ether_addr *source_eth, - always &G.eth_addr */ | 126 | /* const struct ether_addr *source_eth, - always &G.our_ethaddr */ |
127 | uint32_t source_nip, | 127 | uint32_t source_nip, |
128 | const struct ether_addr *target_eth, uint32_t target_nip) | 128 | const struct ether_addr *target_eth, uint32_t target_nip) |
129 | { | 129 | { |
130 | enum { op = ARPOP_REQUEST }; | 130 | enum { op = ARPOP_REQUEST }; |
131 | #define source_eth (&G.eth_addr) | 131 | #define source_eth (&G.our_ethaddr) |
132 | 132 | ||
133 | struct arp_packet p; | 133 | struct arp_packet p; |
134 | memset(&p, 0, sizeof(p)); | 134 | memset(&p, 0, sizeof(p)); |
@@ -205,35 +205,34 @@ static ALWAYS_INLINE unsigned random_delay_ms(unsigned secs) | |||
205 | int zcip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 205 | int zcip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
206 | int zcip_main(int argc UNUSED_PARAM, char **argv) | 206 | int zcip_main(int argc UNUSED_PARAM, char **argv) |
207 | { | 207 | { |
208 | int state; | ||
209 | char *r_opt; | 208 | char *r_opt; |
210 | const char *l_opt = "169.254.0.0"; | 209 | const char *l_opt = "169.254.0.0"; |
210 | int state; | ||
211 | int nsent; | ||
211 | unsigned opts; | 212 | unsigned opts; |
212 | 213 | ||
213 | // ugly trick, but I want these zeroed in one go | 214 | // Ugly trick, but I want these zeroed in one go |
214 | struct { | 215 | struct { |
215 | const struct ether_addr null_addr; | 216 | const struct ether_addr null_ethaddr; |
216 | struct ifreq ifr; | 217 | struct ifreq ifr; |
217 | uint32_t chosen_nip; | 218 | uint32_t chosen_nip; |
219 | int conflicts; | ||
218 | int timeout_ms; // must be signed | 220 | int timeout_ms; // must be signed |
219 | unsigned conflicts; | ||
220 | unsigned nsent; | ||
221 | int verbose; | 221 | int verbose; |
222 | } L; | 222 | } L; |
223 | #define null_addr (L.null_addr ) | 223 | #define null_ethaddr (L.null_ethaddr) |
224 | #define ifr (L.ifr ) | 224 | #define ifr (L.ifr ) |
225 | #define chosen_nip (L.chosen_nip) | 225 | #define chosen_nip (L.chosen_nip ) |
226 | #define timeout_ms (L.timeout_ms) | 226 | #define conflicts (L.conflicts ) |
227 | #define conflicts (L.conflicts ) | 227 | #define timeout_ms (L.timeout_ms ) |
228 | #define nsent (L.nsent ) | 228 | #define verbose (L.verbose ) |
229 | #define verbose (L.verbose ) | ||
230 | 229 | ||
231 | memset(&L, 0, sizeof(L)); | 230 | memset(&L, 0, sizeof(L)); |
232 | INIT_G(); | 231 | INIT_G(); |
233 | 232 | ||
234 | #define FOREGROUND (opts & 1) | 233 | #define FOREGROUND (opts & 1) |
235 | #define QUIT (opts & 2) | 234 | #define QUIT (opts & 2) |
236 | // parse commandline: prog [options] ifname script | 235 | // Parse commandline: prog [options] ifname script |
237 | // exactly 2 args; -v accumulates and implies -f | 236 | // exactly 2 args; -v accumulates and implies -f |
238 | opt_complementary = "=2:vv:vf"; | 237 | opt_complementary = "=2:vv:vf"; |
239 | opts = getopt32(argv, "fqr:l:v", &r_opt, &l_opt, &verbose); | 238 | opts = getopt32(argv, "fqr:l:v", &r_opt, &l_opt, &verbose); |
@@ -242,7 +241,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) | |||
242 | if (!FOREGROUND) | 241 | if (!FOREGROUND) |
243 | bb_daemonize_or_rexec(0 /*was: DAEMON_CHDIR_ROOT*/, argv); | 242 | bb_daemonize_or_rexec(0 /*was: DAEMON_CHDIR_ROOT*/, argv); |
244 | #endif | 243 | #endif |
245 | // open an ARP socket | 244 | // Open an ARP socket |
246 | // (need to do it before openlog to prevent openlog from taking | 245 | // (need to do it before openlog to prevent openlog from taking |
247 | // fd 3 (sock_fd==3)) | 246 | // fd 3 (sock_fd==3)) |
248 | xmove_fd(xsocket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)), sock_fd); | 247 | xmove_fd(xsocket(AF_PACKET, SOCK_PACKET, htons(ETH_P_ARP)), sock_fd); |
@@ -282,26 +281,26 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) | |||
282 | 281 | ||
283 | xsetenv("interface", argv_intf); | 282 | xsetenv("interface", argv_intf); |
284 | 283 | ||
285 | // initialize the interface (modprobe, ifup, etc) | 284 | // Initialize the interface (modprobe, ifup, etc) |
286 | if (run(argv, "init", 0)) | 285 | if (run(argv, "init", 0)) |
287 | return EXIT_FAILURE; | 286 | return EXIT_FAILURE; |
288 | 287 | ||
289 | // initialize G.iface_sockaddr | 288 | // Initialize G.iface_sockaddr |
290 | // G.iface_sockaddr is: { u16 sa_family; u8 sa_data[14]; } | 289 | // G.iface_sockaddr is: { u16 sa_family; u8 sa_data[14]; } |
291 | //memset(&G.iface_sockaddr, 0, sizeof(G.iface_sockaddr)); | 290 | //memset(&G.iface_sockaddr, 0, sizeof(G.iface_sockaddr)); |
292 | //TODO: are we leaving sa_family == 0 (AF_UNSPEC)?! | 291 | //TODO: are we leaving sa_family == 0 (AF_UNSPEC)?! |
293 | safe_strncpy(G.iface_sockaddr.sa_data, argv_intf, sizeof(G.iface_sockaddr.sa_data)); | 292 | safe_strncpy(G.iface_sockaddr.sa_data, argv_intf, sizeof(G.iface_sockaddr.sa_data)); |
294 | 293 | ||
295 | // bind to the interface's ARP socket | 294 | // Bind to the interface's ARP socket |
296 | xbind(sock_fd, &G.iface_sockaddr, sizeof(G.iface_sockaddr)); | 295 | xbind(sock_fd, &G.iface_sockaddr, sizeof(G.iface_sockaddr)); |
297 | 296 | ||
298 | // get the interface's ethernet address | 297 | // Get the interface's ethernet address |
299 | //memset(&ifr, 0, sizeof(ifr)); | 298 | //memset(&ifr, 0, sizeof(ifr)); |
300 | strncpy_IFNAMSIZ(ifr.ifr_name, argv_intf); | 299 | strncpy_IFNAMSIZ(ifr.ifr_name, argv_intf); |
301 | xioctl(sock_fd, SIOCGIFHWADDR, &ifr); | 300 | xioctl(sock_fd, SIOCGIFHWADDR, &ifr); |
302 | memcpy(&G.eth_addr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); | 301 | memcpy(&G.our_ethaddr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); |
303 | 302 | ||
304 | // start with some stable ip address, either a function of | 303 | // Start with some stable ip address, either a function of |
305 | // the hardware address or else the last address we used. | 304 | // the hardware address or else the last address we used. |
306 | // we are taking low-order four bytes, as top-order ones | 305 | // we are taking low-order four bytes, as top-order ones |
307 | // aren't random enough. | 306 | // aren't random enough. |
@@ -309,17 +308,14 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) | |||
309 | // depending on when we detect conflicts. | 308 | // depending on when we detect conflicts. |
310 | { | 309 | { |
311 | uint32_t t; | 310 | uint32_t t; |
312 | move_from_unaligned32(t, ((char *)&G.eth_addr + 2)); | 311 | move_from_unaligned32(t, ((char *)&G.our_ethaddr + 2)); |
313 | srand(t); | 312 | srand(t); |
314 | } | 313 | } |
315 | if (chosen_nip == 0) | ||
316 | chosen_nip = pick_nip(); | ||
317 | |||
318 | // FIXME cases to handle: | 314 | // FIXME cases to handle: |
319 | // - zcip already running! | 315 | // - zcip already running! |
320 | // - link already has local address... just defend/update | 316 | // - link already has local address... just defend/update |
321 | 317 | ||
322 | // daemonize now; don't delay system startup | 318 | // Daemonize now; don't delay system startup |
323 | if (!FOREGROUND) { | 319 | if (!FOREGROUND) { |
324 | #if BB_MMU | 320 | #if BB_MMU |
325 | bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/); | 321 | bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/); |
@@ -327,14 +323,14 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) | |||
327 | bb_info_msg("start, interface %s", argv_intf); | 323 | bb_info_msg("start, interface %s", argv_intf); |
328 | } | 324 | } |
329 | 325 | ||
330 | // run the dynamic address negotiation protocol, | 326 | // Run the dynamic address negotiation protocol, |
331 | // restarting after address conflicts: | 327 | // restarting after address conflicts: |
332 | // - start with some address we want to try | 328 | // - start with some address we want to try |
333 | // - short random delay | 329 | // - short random delay |
334 | // - arp probes to see if another host uses it | 330 | // - arp probes to see if another host uses it |
335 | // 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff, ARP (0x0806): arp who-has 169.254.194.171 tell 0.0.0.0 | 331 | // 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff: arp who-has 169.254.194.171 tell 0.0.0.0 |
336 | // - arp announcements that we're claiming it | 332 | // - arp announcements that we're claiming it |
337 | // 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff, ARP (0x0806): arp who-has 169.254.194.171 (00:04:e2:64:23:c2) tell 169.254.194.171 | 333 | // 00:04:e2:64:23:c2 > ff:ff:ff:ff:ff:ff: arp who-has 169.254.194.171 (00:04:e2:64:23:c2) tell 169.254.194.171 |
338 | // - use it | 334 | // - use it |
339 | // - defend it, within limits | 335 | // - defend it, within limits |
340 | // exit if: | 336 | // exit if: |
@@ -342,73 +338,73 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) | |||
342 | // run "<script> config", then exit with exitcode 0 | 338 | // run "<script> config", then exit with exitcode 0 |
343 | // - poll error (when does this happen?) | 339 | // - poll error (when does this happen?) |
344 | // - read error (when does this happen?) | 340 | // - read error (when does this happen?) |
345 | // - sendto error (in arp()) (when does this happen?) | 341 | // - sendto error (in send_arp_request()) (when does this happen?) |
346 | // - revents & POLLERR (link down). run "<script> deconfig" first | 342 | // - revents & POLLERR (link down). run "<script> deconfig" first |
343 | if (chosen_nip == 0) { | ||
344 | new_nip_and_PROBE: | ||
345 | chosen_nip = pick_nip(); | ||
346 | } | ||
347 | nsent = 0; | ||
347 | state = PROBE; | 348 | state = PROBE; |
348 | while (1) { | 349 | while (1) { |
349 | struct pollfd fds[1]; | 350 | struct pollfd fds[1]; |
350 | unsigned deadline_us; | 351 | unsigned deadline_us; |
351 | struct arp_packet p; | 352 | struct arp_packet p; |
352 | int ip_conflict; | 353 | int ip_conflict; |
354 | int n; | ||
353 | 355 | ||
354 | fds[0].fd = sock_fd; | 356 | fds[0].fd = sock_fd; |
355 | fds[0].events = POLLIN; | 357 | fds[0].events = POLLIN; |
356 | fds[0].revents = 0; | 358 | fds[0].revents = 0; |
357 | 359 | ||
358 | // poll, being ready to adjust current timeout | 360 | // Poll, being ready to adjust current timeout |
359 | if (!timeout_ms) { | 361 | if (!timeout_ms) { |
360 | timeout_ms = random_delay_ms(PROBE_WAIT); | 362 | timeout_ms = random_delay_ms(PROBE_WAIT); |
361 | // FIXME setsockopt(sock_fd, SO_ATTACH_FILTER, ...) to | 363 | // FIXME setsockopt(sock_fd, SO_ATTACH_FILTER, ...) to |
362 | // make the kernel filter out all packets except | 364 | // make the kernel filter out all packets except |
363 | // ones we'd care about. | 365 | // ones we'd care about. |
364 | } | 366 | } |
365 | // set deadline_us to the point in time when we timeout | 367 | // Set deadline_us to the point in time when we timeout |
366 | deadline_us = MONOTONIC_US() + timeout_ms * 1000; | 368 | deadline_us = MONOTONIC_US() + timeout_ms * 1000; |
367 | 369 | ||
368 | VDBG("...wait %d %s nsent=%u\n", | 370 | VDBG("...wait %d %s nsent=%u\n", |
369 | timeout_ms, argv_intf, nsent); | 371 | timeout_ms, argv_intf, nsent); |
370 | 372 | ||
371 | switch (safe_poll(fds, 1, timeout_ms)) { | 373 | n = safe_poll(fds, 1, timeout_ms); |
372 | 374 | if (n < 0) { | |
373 | default: | ||
374 | //bb_perror_msg("poll"); - done in safe_poll | 375 | //bb_perror_msg("poll"); - done in safe_poll |
375 | return EXIT_FAILURE; | 376 | return EXIT_FAILURE; |
376 | 377 | } | |
377 | // timeout | 378 | if (n == 0) { // timed out? |
378 | case 0: | 379 | VDBG("state:%d\n", state); |
379 | VDBG("state = %d\n", state); | ||
380 | switch (state) { | 380 | switch (state) { |
381 | case PROBE: | 381 | case PROBE: |
382 | // timeouts in the PROBE state mean no conflicting ARP packets | 382 | // No conflicting ARP packets were seen: |
383 | // have been received, so we can progress through the states | 383 | // we can progress through the states |
384 | if (nsent < PROBE_NUM) { | 384 | if (nsent < PROBE_NUM) { |
385 | nsent++; | 385 | nsent++; |
386 | VDBG("probe/%u %s@%s\n", | 386 | VDBG("probe/%u %s@%s\n", |
387 | nsent, argv_intf, nip_to_a(chosen_nip)); | 387 | nsent, argv_intf, nip_to_a(chosen_nip)); |
388 | timeout_ms = PROBE_MIN * 1000; | 388 | timeout_ms = PROBE_MIN * 1000; |
389 | timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN); | 389 | timeout_ms += random_delay_ms(PROBE_MAX - PROBE_MIN); |
390 | arp(/* ARPOP_REQUEST, */ | 390 | send_arp_request(0, &null_ethaddr, chosen_nip); |
391 | /* &G.eth_addr, */ 0, | 391 | continue; |
392 | &null_addr, chosen_nip); | ||
393 | break; | ||
394 | } | 392 | } |
395 | // Switch to announce state | 393 | // Switch to announce state |
396 | nsent = 0; | 394 | nsent = 0; |
397 | state = ANNOUNCE; | 395 | state = ANNOUNCE; |
398 | goto send_announce; | 396 | goto send_announce; |
399 | case ANNOUNCE: | 397 | case ANNOUNCE: |
400 | // timeouts in the ANNOUNCE state mean no conflicting ARP packets | 398 | // No conflicting ARP packets were seen: |
401 | // have been received, so we can progress through the states | 399 | // we can progress through the states |
402 | if (nsent < ANNOUNCE_NUM) { | 400 | if (nsent < ANNOUNCE_NUM) { |
403 | send_announce: | 401 | send_announce: |
404 | nsent++; | 402 | nsent++; |
405 | VDBG("announce/%u %s@%s\n", | 403 | VDBG("announce/%u %s@%s\n", |
406 | nsent, argv_intf, nip_to_a(chosen_nip)); | 404 | nsent, argv_intf, nip_to_a(chosen_nip)); |
407 | timeout_ms = ANNOUNCE_INTERVAL * 1000; | 405 | timeout_ms = ANNOUNCE_INTERVAL * 1000; |
408 | arp(/* ARPOP_REQUEST, */ | 406 | send_arp_request(chosen_nip, &G.our_ethaddr, chosen_nip); |
409 | /* &G.eth_addr, */ chosen_nip, | 407 | continue; |
410 | &G.eth_addr, chosen_nip); | ||
411 | break; | ||
412 | } | 408 | } |
413 | // Switch to monitor state | 409 | // Switch to monitor state |
414 | // FIXME update filters | 410 | // FIXME update filters |
@@ -416,124 +412,117 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) | |||
416 | // NOTE: all other exit paths should deconfig... | 412 | // NOTE: all other exit paths should deconfig... |
417 | if (QUIT) | 413 | if (QUIT) |
418 | return EXIT_SUCCESS; | 414 | return EXIT_SUCCESS; |
419 | conflicts = 0; | 415 | // fall through: switch_to_MONITOR |
420 | timeout_ms = -1; // Never timeout in the monitor state. | 416 | default: |
421 | state = MONITOR; | 417 | // case DEFEND: |
422 | break; | 418 | // case MONITOR: (shouldn't happen, MONITOR timeout is infinite) |
423 | case DEFEND: | ||
424 | // Defend period ended with no ARP replies - we won | 419 | // Defend period ended with no ARP replies - we won |
425 | conflicts = 0; | 420 | timeout_ms = -1; // never timeout in monitor state |
426 | timeout_ms = -1; | ||
427 | state = MONITOR; | 421 | state = MONITOR; |
428 | break; | ||
429 | } // switch (state) | ||
430 | break; // case 0 (timeout) | ||
431 | |||
432 | // packets arriving, or link went down | ||
433 | case 1: | ||
434 | // We need to adjust the timeout in case we didn't receive | ||
435 | // a conflicting packet. | ||
436 | if (timeout_ms > 0) { | ||
437 | unsigned diff = deadline_us - MONOTONIC_US(); | ||
438 | if ((int)(diff) < 0) { | ||
439 | // Current time is greater than the expected timeout time. | ||
440 | diff = 0; | ||
441 | } | ||
442 | VDBG("adjusting timeout\n"); | ||
443 | timeout_ms = (diff / 1000) | 1; // never 0 | ||
444 | } | ||
445 | |||
446 | if ((fds[0].revents & POLLIN) == 0) { | ||
447 | if (fds[0].revents & POLLERR) { | ||
448 | // FIXME: links routinely go down; | ||
449 | // this shouldn't necessarily exit. | ||
450 | bb_error_msg("iface %s is down", argv_intf); | ||
451 | if (state >= MONITOR) { | ||
452 | // only if we are in MONITOR or DEFEND | ||
453 | run(argv, "deconfig", chosen_nip); | ||
454 | } | ||
455 | return EXIT_FAILURE; | ||
456 | } | ||
457 | continue; | 422 | continue; |
458 | } | 423 | } |
424 | } | ||
459 | 425 | ||
460 | // read ARP packet | 426 | // Packet arrived, or link went down. |
461 | if (safe_read(sock_fd, &p, sizeof(p)) < 0) { | 427 | // We need to adjust the timeout in case we didn't receive |
462 | bb_perror_msg_and_die(bb_msg_read_error); | 428 | // a conflicting packet. |
429 | if (timeout_ms > 0) { | ||
430 | unsigned diff = deadline_us - MONOTONIC_US(); | ||
431 | if ((int)(diff) < 0) { | ||
432 | // Current time is greater than the expected timeout time. | ||
433 | diff = 0; | ||
463 | } | 434 | } |
435 | VDBG("adjusting timeout\n"); | ||
436 | timeout_ms = (diff / 1000) | 1; // never 0 | ||
437 | } | ||
464 | 438 | ||
465 | if (p.eth.ether_type != htons(ETHERTYPE_ARP)) | 439 | if ((fds[0].revents & POLLIN) == 0) { |
466 | continue; | 440 | if (fds[0].revents & POLLERR) { |
467 | if (p.arp.arp_op != htons(ARPOP_REQUEST) | 441 | // FIXME: links routinely go down; |
468 | && p.arp.arp_op != htons(ARPOP_REPLY) | 442 | // this shouldn't necessarily exit. |
469 | ) { | 443 | bb_error_msg("iface %s is down", argv_intf); |
470 | continue; | 444 | if (state >= MONITOR) { |
445 | // Only if we are in MONITOR or DEFEND | ||
446 | run(argv, "deconfig", chosen_nip); | ||
447 | } | ||
448 | return EXIT_FAILURE; | ||
471 | } | 449 | } |
450 | continue; | ||
451 | } | ||
452 | |||
453 | // Read ARP packet | ||
454 | if (safe_read(sock_fd, &p, sizeof(p)) < 0) { | ||
455 | bb_perror_msg_and_die(bb_msg_read_error); | ||
456 | } | ||
457 | |||
458 | if (p.eth.ether_type != htons(ETHERTYPE_ARP)) | ||
459 | continue; | ||
460 | if (p.arp.arp_op != htons(ARPOP_REQUEST) | ||
461 | && p.arp.arp_op != htons(ARPOP_REPLY) | ||
462 | ) { | ||
463 | continue; | ||
464 | } | ||
472 | #ifdef DEBUG | 465 | #ifdef DEBUG |
473 | { | 466 | { |
474 | struct ether_addr *sha = (struct ether_addr *) p.arp.arp_sha; | 467 | struct ether_addr *sha = (struct ether_addr *) p.arp.arp_sha; |
475 | struct ether_addr *tha = (struct ether_addr *) p.arp.arp_tha; | 468 | struct ether_addr *tha = (struct ether_addr *) p.arp.arp_tha; |
476 | struct in_addr *spa = (struct in_addr *) p.arp.arp_spa; | 469 | struct in_addr *spa = (struct in_addr *) p.arp.arp_spa; |
477 | struct in_addr *tpa = (struct in_addr *) p.arp.arp_tpa; | 470 | struct in_addr *tpa = (struct in_addr *) p.arp.arp_tpa; |
478 | VDBG("source=%s %s\n", ether_ntoa(sha), inet_ntoa(*spa)); | 471 | VDBG("source=%s %s\n", ether_ntoa(sha), inet_ntoa(*spa)); |
479 | VDBG("target=%s %s\n", ether_ntoa(tha), inet_ntoa(*tpa)); | 472 | VDBG("target=%s %s\n", ether_ntoa(tha), inet_ntoa(*tpa)); |
480 | } | 473 | } |
481 | #endif | 474 | #endif |
482 | ip_conflict = 0; | 475 | ip_conflict = 0; |
483 | if (memcmp(&p.arp.arp_sha, &G.eth_addr, ETH_ALEN) != 0) { | 476 | if (memcmp(&p.arp.arp_sha, &G.our_ethaddr, ETH_ALEN) != 0) { |
484 | if (memcmp(p.arp.arp_spa, &chosen_nip, 4) == 0) { | 477 | if (memcmp(p.arp.arp_spa, &chosen_nip, 4) == 0) { |
485 | // A probe or reply with source_ip == chosen ip | 478 | // A probe or reply with source_ip == chosen ip |
486 | ip_conflict = 1; | 479 | ip_conflict = 1; |
487 | } | ||
488 | if (p.arp.arp_op == htons(ARPOP_REQUEST) | ||
489 | && memcmp(p.arp.arp_spa, &const_int_0, 4) == 0 | ||
490 | && memcmp(p.arp.arp_tpa, &chosen_nip, 4) == 0 | ||
491 | ) { | ||
492 | // A probe with source_ip == 0.0.0.0, target_ip == chosen ip: | ||
493 | // another host trying to claim this ip! | ||
494 | ip_conflict |= 2; | ||
495 | } | ||
496 | } | 480 | } |
497 | VDBG("state:%d ip_conflict:%d\n", state, ip_conflict); | 481 | if (p.arp.arp_op == htons(ARPOP_REQUEST) |
498 | if (!ip_conflict) | 482 | && memcmp(p.arp.arp_spa, &const_int_0, 4) == 0 |
499 | break; | 483 | && memcmp(p.arp.arp_tpa, &chosen_nip, 4) == 0 |
500 | 484 | ) { | |
501 | // Either src or target IP conflict exists | 485 | // A probe with source_ip == 0.0.0.0, target_ip == chosen ip: |
502 | if (state <= ANNOUNCE) { | 486 | // another host trying to claim this ip! |
503 | // PROBE or ANNOUNCE | 487 | ip_conflict |= 2; |
504 | conflicts++; | ||
505 | timeout_ms = PROBE_MIN * 1000 | ||
506 | + CONFLICT_MULTIPLIER * random_delay_ms(conflicts); | ||
507 | chosen_nip = pick_nip(); | ||
508 | nsent = 0; | ||
509 | state = PROBE; | ||
510 | break; | ||
511 | } | 488 | } |
512 | // MONITOR or DEFEND: only src IP conflict is a problem | 489 | } |
513 | if (ip_conflict & 1) { | 490 | VDBG("state:%d ip_conflict:%d\n", state, ip_conflict); |
514 | if (state == MONITOR) { | 491 | if (!ip_conflict) |
515 | // Src IP conflict, defend with a single ARP probe | 492 | continue; |
516 | VDBG("monitor conflict - defending\n"); | 493 | |
517 | timeout_ms = DEFEND_INTERVAL * 1000; | 494 | // Either src or target IP conflict exists |
518 | state = DEFEND; | 495 | if (state <= ANNOUNCE) { |
519 | arp(/* ARPOP_REQUEST, */ | 496 | // PROBE or ANNOUNCE |
520 | /* &G.eth_addr, */ chosen_nip, | 497 | conflicts++; |
521 | &G.eth_addr, chosen_nip); | 498 | timeout_ms = PROBE_MIN * 1000 |
522 | break; | 499 | + CONFLICT_MULTIPLIER * random_delay_ms(conflicts); |
523 | } | 500 | goto new_nip_and_PROBE; |
524 | // state == DEFEND | 501 | } |
525 | // Another src IP conflict, start over | 502 | |
526 | VDBG("defend conflict - starting over\n"); | 503 | // MONITOR or DEFEND: only src IP conflict is a problem |
527 | run(argv, "deconfig", chosen_nip); | 504 | if (ip_conflict & 1) { |
528 | 505 | if (state == MONITOR) { | |
529 | // restart the whole protocol | 506 | // Src IP conflict, defend with a single ARP probe |
530 | timeout_ms = 0; | 507 | VDBG("monitor conflict - defending\n"); |
531 | chosen_nip = pick_nip(); | 508 | timeout_ms = DEFEND_INTERVAL * 1000; |
532 | nsent = 0; | 509 | state = DEFEND; |
533 | state = PROBE; | 510 | send_arp_request(chosen_nip, &G.our_ethaddr, chosen_nip); |
511 | continue; | ||
534 | } | 512 | } |
535 | break; // case 1 (packet arrived) | 513 | // state == DEFEND |
536 | } // switch (poll) | 514 | // Another src IP conflict, start over |
515 | VDBG("defend conflict - starting over\n"); | ||
516 | run(argv, "deconfig", chosen_nip); | ||
517 | conflicts = 0; | ||
518 | timeout_ms = 0; | ||
519 | goto new_nip_and_PROBE; | ||
520 | } | ||
521 | // Note: if we only have a target IP conflict here (ip_conflict & 2), | ||
522 | // IOW: if we just saw this sort of ARP packet: | ||
523 | // aa:bb:cc:dd:ee:ff > xx:xx:xx:xx:xx:xx: arp who-has <chosen_nip> tell 0.0.0.0 | ||
524 | // we expect _kernel_ to respond to that, because <chosen_nip> | ||
525 | // is (expected to be) configured on this iface. | ||
537 | } // while (1) | 526 | } // while (1) |
538 | #undef argv_intf | 527 | #undef argv_intf |
539 | } | 528 | } |