diff options
Diffstat (limited to 'networking/udhcp/dhcpc.c')
-rw-r--r-- | networking/udhcp/dhcpc.c | 294 |
1 files changed, 235 insertions, 59 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 27d6ad1a8..78aabedf2 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -346,31 +346,28 @@ static ALWAYS_INLINE uint32_t random_xid(void) | |||
346 | /* Initialize the packet with the proper defaults */ | 346 | /* Initialize the packet with the proper defaults */ |
347 | static void init_packet(struct dhcp_packet *packet, char type) | 347 | static void init_packet(struct dhcp_packet *packet, char type) |
348 | { | 348 | { |
349 | /* Fill in: op, htype, hlen, cookie fields; message type option: */ | ||
349 | udhcp_init_header(packet, type); | 350 | udhcp_init_header(packet, type); |
351 | |||
352 | packet->xid = random_xid(); | ||
353 | |||
350 | memcpy(packet->chaddr, client_config.client_mac, 6); | 354 | memcpy(packet->chaddr, client_config.client_mac, 6); |
351 | if (client_config.clientid) | 355 | if (client_config.clientid) |
352 | udhcp_add_binary_option(packet, client_config.clientid); | 356 | udhcp_add_binary_option(packet, client_config.clientid); |
353 | if (client_config.hostname) | ||
354 | udhcp_add_binary_option(packet, client_config.hostname); | ||
355 | if (client_config.fqdn) | ||
356 | udhcp_add_binary_option(packet, client_config.fqdn); | ||
357 | if (type != DHCPDECLINE | ||
358 | && type != DHCPRELEASE | ||
359 | && client_config.vendorclass | ||
360 | ) { | ||
361 | udhcp_add_binary_option(packet, client_config.vendorclass); | ||
362 | } | ||
363 | } | 357 | } |
364 | 358 | ||
365 | static void add_client_options(struct dhcp_packet *packet) | 359 | static void add_client_options(struct dhcp_packet *packet) |
366 | { | 360 | { |
361 | uint8_t c; | ||
362 | int i, end, len; | ||
363 | |||
364 | udhcp_add_simple_option(packet, DHCP_MAX_SIZE, htons(IP_UDP_DHCP_SIZE)); | ||
365 | |||
367 | /* Add a "param req" option with the list of options we'd like to have | 366 | /* Add a "param req" option with the list of options we'd like to have |
368 | * from stubborn DHCP servers. Pull the data from the struct in common.c. | 367 | * from stubborn DHCP servers. Pull the data from the struct in common.c. |
369 | * No bounds checking because it goes towards the head of the packet. */ | 368 | * No bounds checking because it goes towards the head of the packet. */ |
370 | uint8_t c; | 369 | end = udhcp_end_option(packet->options); |
371 | int end = udhcp_end_option(packet->options); | 370 | len = 0; |
372 | int i, len = 0; | ||
373 | |||
374 | for (i = 0; (c = dhcp_optflags[i].code) != 0; i++) { | 371 | for (i = 0; (c = dhcp_optflags[i].code) != 0; i++) { |
375 | if (( (dhcp_optflags[i].flags & OPTION_REQ) | 372 | if (( (dhcp_optflags[i].flags & OPTION_REQ) |
376 | && !client_config.no_default_options | 373 | && !client_config.no_default_options |
@@ -387,6 +384,13 @@ static void add_client_options(struct dhcp_packet *packet) | |||
387 | packet->options[end + OPT_DATA + len] = DHCP_END; | 384 | packet->options[end + OPT_DATA + len] = DHCP_END; |
388 | } | 385 | } |
389 | 386 | ||
387 | if (client_config.vendorclass) | ||
388 | udhcp_add_binary_option(packet, client_config.vendorclass); | ||
389 | if (client_config.hostname) | ||
390 | udhcp_add_binary_option(packet, client_config.hostname); | ||
391 | if (client_config.fqdn) | ||
392 | udhcp_add_binary_option(packet, client_config.fqdn); | ||
393 | |||
390 | /* Add -x options if any */ | 394 | /* Add -x options if any */ |
391 | { | 395 | { |
392 | struct option_set *curr = client_config.options; | 396 | struct option_set *curr = client_config.options; |
@@ -428,17 +432,25 @@ static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet) | |||
428 | } | 432 | } |
429 | 433 | ||
430 | /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ | 434 | /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ |
431 | static int send_discover(uint32_t xid, uint32_t requested) | 435 | /* NOINLINE: limit stack usage in caller */ |
436 | static NOINLINE int send_discover(uint32_t xid, uint32_t requested) | ||
432 | { | 437 | { |
433 | struct dhcp_packet packet; | 438 | struct dhcp_packet packet; |
434 | 439 | ||
440 | /* Fill in: op, htype, hlen, cookie, chaddr fields, | ||
441 | * random xid field (we override it below), | ||
442 | * client-id option (unless -C), message type option: | ||
443 | */ | ||
435 | init_packet(&packet, DHCPDISCOVER); | 444 | init_packet(&packet, DHCPDISCOVER); |
445 | |||
436 | packet.xid = xid; | 446 | packet.xid = xid; |
437 | if (requested) | 447 | if (requested) |
438 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); | 448 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); |
439 | /* Explicitly saying that we want RFC-compliant packets helps | 449 | |
440 | * some buggy DHCP servers to NOT send bigger packets */ | 450 | /* Add options: maxsize, |
441 | udhcp_add_simple_option(&packet, DHCP_MAX_SIZE, htons(576)); | 451 | * optionally: hostname, fqdn, vendorclass, |
452 | * "param req" option according to -O, options specified with -x | ||
453 | */ | ||
442 | add_client_options(&packet); | 454 | add_client_options(&packet); |
443 | 455 | ||
444 | bb_info_msg("Sending discover..."); | 456 | bb_info_msg("Sending discover..."); |
@@ -449,15 +461,39 @@ static int send_discover(uint32_t xid, uint32_t requested) | |||
449 | /* RFC 2131 3.1 paragraph 3: | 461 | /* RFC 2131 3.1 paragraph 3: |
450 | * "The client _broadcasts_ a DHCPREQUEST message..." | 462 | * "The client _broadcasts_ a DHCPREQUEST message..." |
451 | */ | 463 | */ |
452 | static int send_select(uint32_t xid, uint32_t server, uint32_t requested) | 464 | /* NOINLINE: limit stack usage in caller */ |
465 | static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requested) | ||
453 | { | 466 | { |
454 | struct dhcp_packet packet; | 467 | struct dhcp_packet packet; |
455 | struct in_addr addr; | 468 | struct in_addr addr; |
456 | 469 | ||
470 | /* | ||
471 | * RFC 2131 4.3.2 DHCPREQUEST message | ||
472 | * ... | ||
473 | * If the DHCPREQUEST message contains a 'server identifier' | ||
474 | * option, the message is in response to a DHCPOFFER message. | ||
475 | * Otherwise, the message is a request to verify or extend an | ||
476 | * existing lease. If the client uses a 'client identifier' | ||
477 | * in a DHCPREQUEST message, it MUST use that same 'client identifier' | ||
478 | * in all subsequent messages. If the client included a list | ||
479 | * of requested parameters in a DHCPDISCOVER message, it MUST | ||
480 | * include that list in all subsequent messages. | ||
481 | */ | ||
482 | /* Fill in: op, htype, hlen, cookie, chaddr fields, | ||
483 | * random xid field (we override it below), | ||
484 | * client-id option (unless -C), message type option: | ||
485 | */ | ||
457 | init_packet(&packet, DHCPREQUEST); | 486 | init_packet(&packet, DHCPREQUEST); |
487 | |||
458 | packet.xid = xid; | 488 | packet.xid = xid; |
459 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); | 489 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); |
490 | |||
460 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); | 491 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); |
492 | |||
493 | /* Add options: maxsize, | ||
494 | * optionally: hostname, fqdn, vendorclass, | ||
495 | * "param req" option according to -O, and options specified with -x | ||
496 | */ | ||
461 | add_client_options(&packet); | 497 | add_client_options(&packet); |
462 | 498 | ||
463 | addr.s_addr = requested; | 499 | addr.s_addr = requested; |
@@ -466,13 +502,38 @@ static int send_select(uint32_t xid, uint32_t server, uint32_t requested) | |||
466 | } | 502 | } |
467 | 503 | ||
468 | /* Unicast or broadcast a DHCP renew message */ | 504 | /* Unicast or broadcast a DHCP renew message */ |
469 | static int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) | 505 | /* NOINLINE: limit stack usage in caller */ |
506 | static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) | ||
470 | { | 507 | { |
471 | struct dhcp_packet packet; | 508 | struct dhcp_packet packet; |
472 | 509 | ||
510 | /* | ||
511 | * RFC 2131 4.3.2 DHCPREQUEST message | ||
512 | * ... | ||
513 | * DHCPREQUEST generated during RENEWING state: | ||
514 | * | ||
515 | * 'server identifier' MUST NOT be filled in, 'requested IP address' | ||
516 | * option MUST NOT be filled in, 'ciaddr' MUST be filled in with | ||
517 | * client's IP address. In this situation, the client is completely | ||
518 | * configured, and is trying to extend its lease. This message will | ||
519 | * be unicast, so no relay agents will be involved in its | ||
520 | * transmission. Because 'giaddr' is therefore not filled in, the | ||
521 | * DHCP server will trust the value in 'ciaddr', and use it when | ||
522 | * replying to the client. | ||
523 | */ | ||
524 | /* Fill in: op, htype, hlen, cookie, chaddr fields, | ||
525 | * random xid field (we override it below), | ||
526 | * client-id option (unless -C), message type option: | ||
527 | */ | ||
473 | init_packet(&packet, DHCPREQUEST); | 528 | init_packet(&packet, DHCPREQUEST); |
529 | |||
474 | packet.xid = xid; | 530 | packet.xid = xid; |
475 | packet.ciaddr = ciaddr; | 531 | packet.ciaddr = ciaddr; |
532 | |||
533 | /* Add options: maxsize, | ||
534 | * optionally: hostname, fqdn, vendorclass, | ||
535 | * "param req" option according to -O, and options specified with -x | ||
536 | */ | ||
476 | add_client_options(&packet); | 537 | add_client_options(&packet); |
477 | 538 | ||
478 | bb_info_msg("Sending renew..."); | 539 | bb_info_msg("Sending renew..."); |
@@ -485,13 +546,25 @@ static int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) | |||
485 | 546 | ||
486 | #if ENABLE_FEATURE_UDHCPC_ARPING | 547 | #if ENABLE_FEATURE_UDHCPC_ARPING |
487 | /* Broadcast a DHCP decline message */ | 548 | /* Broadcast a DHCP decline message */ |
488 | static int send_decline(uint32_t xid, uint32_t server, uint32_t requested) | 549 | /* NOINLINE: limit stack usage in caller */ |
550 | static NOINLINE int send_decline(uint32_t xid, uint32_t server, uint32_t requested) | ||
489 | { | 551 | { |
490 | struct dhcp_packet packet; | 552 | struct dhcp_packet packet; |
491 | 553 | ||
554 | /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, | ||
555 | * client-id option (unless -C), message type option: | ||
556 | */ | ||
492 | init_packet(&packet, DHCPDECLINE); | 557 | init_packet(&packet, DHCPDECLINE); |
558 | |||
559 | /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client, | ||
560 | * but in case the server is buggy and wants DHCPDECLINE's xid | ||
561 | * to match the xid which started entire handshake, | ||
562 | * we use the same xid we used in initial DHCPDISCOVER: | ||
563 | */ | ||
493 | packet.xid = xid; | 564 | packet.xid = xid; |
565 | /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */ | ||
494 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); | 566 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); |
567 | |||
495 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); | 568 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); |
496 | 569 | ||
497 | bb_info_msg("Sending decline..."); | 570 | bb_info_msg("Sending decline..."); |
@@ -504,8 +577,12 @@ static int send_release(uint32_t server, uint32_t ciaddr) | |||
504 | { | 577 | { |
505 | struct dhcp_packet packet; | 578 | struct dhcp_packet packet; |
506 | 579 | ||
580 | /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, | ||
581 | * client-id option (unless -C), message type option: | ||
582 | */ | ||
507 | init_packet(&packet, DHCPRELEASE); | 583 | init_packet(&packet, DHCPRELEASE); |
508 | packet.xid = random_xid(); | 584 | |
585 | /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */ | ||
509 | packet.ciaddr = ciaddr; | 586 | packet.ciaddr = ciaddr; |
510 | 587 | ||
511 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); | 588 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); |
@@ -515,6 +592,7 @@ static int send_release(uint32_t server, uint32_t ciaddr) | |||
515 | } | 592 | } |
516 | 593 | ||
517 | /* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ | 594 | /* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ |
595 | /* NOINLINE: limit stack usage in caller */ | ||
518 | static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | 596 | static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) |
519 | { | 597 | { |
520 | int bytes; | 598 | int bytes; |
@@ -765,12 +843,97 @@ static void client_background(void) | |||
765 | } | 843 | } |
766 | #endif | 844 | #endif |
767 | 845 | ||
846 | //usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 | ||
847 | //usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ | ||
848 | //usage:#else | ||
849 | //usage:# define IF_UDHCP_VERBOSE(...) | ||
850 | //usage:#endif | ||
851 | //usage:#define udhcpc_trivial_usage | ||
852 | //usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oCR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" | ||
853 | //usage: " [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") | ||
854 | //usage:#define udhcpc_full_usage "\n" | ||
855 | //usage: IF_LONG_OPTS( | ||
856 | //usage: "\n -i,--interface IFACE Interface to use (default eth0)" | ||
857 | //usage: "\n -p,--pidfile FILE Create pidfile" | ||
858 | //usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" | ||
859 | //usage: "\n -t,--retries N Send up to N discover packets" | ||
860 | //usage: "\n -T,--timeout N Pause between packets (default 3 seconds)" | ||
861 | //usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)" | ||
862 | //usage: "\n -f,--foreground Run in foreground" | ||
863 | //usage: USE_FOR_MMU( | ||
864 | //usage: "\n -b,--background Background if lease is not obtained" | ||
865 | //usage: ) | ||
866 | //usage: "\n -n,--now Exit if lease is not obtained" | ||
867 | //usage: "\n -q,--quit Exit after obtaining lease" | ||
868 | //usage: "\n -R,--release Release IP on exit" | ||
869 | //usage: "\n -S,--syslog Log to syslog too" | ||
870 | //usage: IF_FEATURE_UDHCP_PORT( | ||
871 | //usage: "\n -P,--client-port N Use port N (default 68)" | ||
872 | //usage: ) | ||
873 | //usage: IF_FEATURE_UDHCPC_ARPING( | ||
874 | //usage: "\n -a,--arping Use arping to validate offered address" | ||
875 | //usage: ) | ||
876 | //usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)" | ||
877 | //usage: "\n -o,--no-default-options Don't request any options (unless -O is given)" | ||
878 | //usage: "\n -r,--request IP Request this IP address" | ||
879 | //usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" | ||
880 | //usage: "\n Examples of string, numeric, and hex byte opts:" | ||
881 | //usage: "\n -x hostname:bbox - option 12" | ||
882 | //usage: "\n -x lease:3600 - option 51 (lease time)" | ||
883 | //usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" | ||
884 | //usage: "\n -F,--fqdn NAME Ask server to update DNS mapping for NAME" | ||
885 | //usage: "\n -H,-h,--hostname NAME Send NAME as client hostname (default none)" | ||
886 | //usage: "\n -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')" | ||
887 | //usage: "\n -C,--clientid-none Don't send MAC as client identifier" | ||
888 | //usage: IF_UDHCP_VERBOSE( | ||
889 | //usage: "\n -v Verbose" | ||
890 | //usage: ) | ||
891 | //usage: ) | ||
892 | //usage: IF_NOT_LONG_OPTS( | ||
893 | //usage: "\n -i IFACE Interface to use (default eth0)" | ||
894 | //usage: "\n -p FILE Create pidfile" | ||
895 | //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" | ||
896 | //usage: "\n -t N Send up to N discover packets" | ||
897 | //usage: "\n -T N Pause between packets (default 3 seconds)" | ||
898 | //usage: "\n -A N Wait N seconds (default 20) after failure" | ||
899 | //usage: "\n -f Run in foreground" | ||
900 | //usage: USE_FOR_MMU( | ||
901 | //usage: "\n -b Background if lease is not obtained" | ||
902 | //usage: ) | ||
903 | //usage: "\n -n Exit if lease is not obtained" | ||
904 | //usage: "\n -q Exit after obtaining lease" | ||
905 | //usage: "\n -R Release IP on exit" | ||
906 | //usage: "\n -S Log to syslog too" | ||
907 | //usage: IF_FEATURE_UDHCP_PORT( | ||
908 | //usage: "\n -P N Use port N (default 68)" | ||
909 | //usage: ) | ||
910 | //usage: IF_FEATURE_UDHCPC_ARPING( | ||
911 | //usage: "\n -a Use arping to validate offered address" | ||
912 | //usage: ) | ||
913 | //usage: "\n -O OPT Request option OPT from server (cumulative)" | ||
914 | //usage: "\n -o Don't request any options (unless -O is given)" | ||
915 | //usage: "\n -r IP Request this IP address" | ||
916 | //usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" | ||
917 | //usage: "\n Examples of string, numeric, and hex byte opts:" | ||
918 | //usage: "\n -x hostname:bbox - option 12" | ||
919 | //usage: "\n -x lease:3600 - option 51 (lease time)" | ||
920 | //usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" | ||
921 | //usage: "\n -F NAME Ask server to update DNS mapping for NAME" | ||
922 | //usage: "\n -H,-h NAME Send NAME as client hostname (default none)" | ||
923 | //usage: "\n -V VENDOR Vendor identifier (default 'udhcp VERSION')" | ||
924 | //usage: "\n -C Don't send MAC as client identifier" | ||
925 | //usage: IF_UDHCP_VERBOSE( | ||
926 | //usage: "\n -v Verbose" | ||
927 | //usage: ) | ||
928 | //usage: ) | ||
929 | |||
768 | int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 930 | int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
769 | int udhcpc_main(int argc UNUSED_PARAM, char **argv) | 931 | int udhcpc_main(int argc UNUSED_PARAM, char **argv) |
770 | { | 932 | { |
771 | uint8_t *temp, *message; | 933 | uint8_t *temp, *message; |
772 | const char *str_c, *str_V, *str_h, *str_F, *str_r; | 934 | const char *str_V, *str_h, *str_F, *str_r; |
773 | IF_FEATURE_UDHCP_PORT(char *str_P;) | 935 | IF_FEATURE_UDHCP_PORT(char *str_P;) |
936 | void *clientid_mac_ptr; | ||
774 | llist_t *list_O = NULL; | 937 | llist_t *list_O = NULL; |
775 | llist_t *list_x = NULL; | 938 | llist_t *list_x = NULL; |
776 | int tryagain_timeout = 20; | 939 | int tryagain_timeout = 20; |
@@ -792,7 +955,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
792 | 955 | ||
793 | #if ENABLE_LONG_OPTS | 956 | #if ENABLE_LONG_OPTS |
794 | static const char udhcpc_longopts[] ALIGN1 = | 957 | static const char udhcpc_longopts[] ALIGN1 = |
795 | "clientid\0" Required_argument "c" | ||
796 | "clientid-none\0" No_argument "C" | 958 | "clientid-none\0" No_argument "C" |
797 | "vendorclass\0" Required_argument "V" | 959 | "vendorclass\0" Required_argument "V" |
798 | "hostname\0" Required_argument "H" | 960 | "hostname\0" Required_argument "H" |
@@ -818,29 +980,28 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
818 | ; | 980 | ; |
819 | #endif | 981 | #endif |
820 | enum { | 982 | enum { |
821 | OPT_c = 1 << 0, | 983 | OPT_C = 1 << 0, |
822 | OPT_C = 1 << 1, | 984 | OPT_V = 1 << 1, |
823 | OPT_V = 1 << 2, | 985 | OPT_H = 1 << 2, |
824 | OPT_H = 1 << 3, | 986 | OPT_h = 1 << 3, |
825 | OPT_h = 1 << 4, | 987 | OPT_F = 1 << 4, |
826 | OPT_F = 1 << 5, | 988 | OPT_i = 1 << 5, |
827 | OPT_i = 1 << 6, | 989 | OPT_n = 1 << 6, |
828 | OPT_n = 1 << 7, | 990 | OPT_p = 1 << 7, |
829 | OPT_p = 1 << 8, | 991 | OPT_q = 1 << 8, |
830 | OPT_q = 1 << 9, | 992 | OPT_R = 1 << 9, |
831 | OPT_R = 1 << 10, | 993 | OPT_r = 1 << 10, |
832 | OPT_r = 1 << 11, | 994 | OPT_s = 1 << 11, |
833 | OPT_s = 1 << 12, | 995 | OPT_T = 1 << 12, |
834 | OPT_T = 1 << 13, | 996 | OPT_t = 1 << 13, |
835 | OPT_t = 1 << 14, | 997 | OPT_S = 1 << 14, |
836 | OPT_S = 1 << 15, | 998 | OPT_A = 1 << 15, |
837 | OPT_A = 1 << 16, | 999 | OPT_O = 1 << 16, |
838 | OPT_O = 1 << 17, | 1000 | OPT_o = 1 << 17, |
839 | OPT_o = 1 << 18, | 1001 | OPT_x = 1 << 18, |
840 | OPT_x = 1 << 19, | 1002 | OPT_f = 1 << 19, |
841 | OPT_f = 1 << 20, | ||
842 | /* The rest has variable bit positions, need to be clever */ | 1003 | /* The rest has variable bit positions, need to be clever */ |
843 | OPTBIT_f = 20, | 1004 | OPTBIT_f = 19, |
844 | USE_FOR_MMU( OPTBIT_b,) | 1005 | USE_FOR_MMU( OPTBIT_b,) |
845 | IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) | 1006 | IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) |
846 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) | 1007 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) |
@@ -849,7 +1010,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
849 | IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) | 1010 | IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) |
850 | }; | 1011 | }; |
851 | 1012 | ||
852 | /* Default options. */ | 1013 | /* Default options */ |
853 | IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;) | 1014 | IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;) |
854 | IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;) | 1015 | IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;) |
855 | client_config.interface = "eth0"; | 1016 | client_config.interface = "eth0"; |
@@ -857,19 +1018,19 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
857 | str_V = "udhcp "BB_VER; | 1018 | str_V = "udhcp "BB_VER; |
858 | 1019 | ||
859 | /* Parse command line */ | 1020 | /* Parse command line */ |
860 | /* Cc: mutually exclusive; O,x: list; -T,-t,-A take numeric param */ | 1021 | /* O,x: list; -T,-t,-A take numeric param */ |
861 | opt_complementary = "c--C:C--c:O::x::T+:t+:A+" | 1022 | opt_complementary = "O::x::T+:t+:A+" |
862 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 | 1023 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 |
863 | ":vv" | 1024 | ":vv" |
864 | #endif | 1025 | #endif |
865 | ; | 1026 | ; |
866 | IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) | 1027 | IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) |
867 | opt = getopt32(argv, "c:CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:f" | 1028 | opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:f" |
868 | USE_FOR_MMU("b") | 1029 | USE_FOR_MMU("b") |
869 | IF_FEATURE_UDHCPC_ARPING("a") | 1030 | IF_FEATURE_UDHCPC_ARPING("a") |
870 | IF_FEATURE_UDHCP_PORT("P:") | 1031 | IF_FEATURE_UDHCP_PORT("P:") |
871 | "v" | 1032 | "v" |
872 | , &str_c, &str_V, &str_h, &str_h, &str_F | 1033 | , &str_V, &str_h, &str_h, &str_F |
873 | , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ | 1034 | , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ |
874 | , &client_config.script /* s */ | 1035 | , &client_config.script /* s */ |
875 | , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ | 1036 | , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ |
@@ -931,13 +1092,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
931 | return 1; | 1092 | return 1; |
932 | } | 1093 | } |
933 | 1094 | ||
934 | if (opt & OPT_c) { | 1095 | clientid_mac_ptr = NULL; |
935 | client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0); | 1096 | if (!(opt & OPT_C) && !udhcp_find_option(client_config.options, DHCP_CLIENT_ID)) { |
936 | } else if (!(opt & OPT_C)) { | 1097 | /* not suppressed and not set, set the default client ID */ |
937 | /* not set and not suppressed, set the default client ID */ | ||
938 | client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); | 1098 | client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); |
939 | client_config.clientid[OPT_DATA] = 1; /* type: ethernet */ | 1099 | client_config.clientid[OPT_DATA] = 1; /* type: ethernet */ |
940 | memcpy(client_config.clientid + OPT_DATA+1, client_config.client_mac, 6); | 1100 | clientid_mac_ptr = client_config.clientid + OPT_DATA+1; |
1101 | memcpy(clientid_mac_ptr, client_config.client_mac, 6); | ||
941 | } | 1102 | } |
942 | if (str_V[0] != '\0') | 1103 | if (str_V[0] != '\0') |
943 | client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); | 1104 | client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); |
@@ -1015,6 +1176,21 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1015 | * resend discover/renew/whatever | 1176 | * resend discover/renew/whatever |
1016 | */ | 1177 | */ |
1017 | if (retval == 0) { | 1178 | if (retval == 0) { |
1179 | /* When running on a bridge, the ifindex may have changed | ||
1180 | * (e.g. if member interfaces were added/removed | ||
1181 | * or if the status of the bridge changed). | ||
1182 | * Refresh ifindex and client_mac: | ||
1183 | */ | ||
1184 | if (udhcp_read_interface(client_config.interface, | ||
1185 | &client_config.ifindex, | ||
1186 | NULL, | ||
1187 | client_config.client_mac) | ||
1188 | ) { | ||
1189 | return 1; /* iface is gone? */ | ||
1190 | } | ||
1191 | if (clientid_mac_ptr) | ||
1192 | memcpy(clientid_mac_ptr, client_config.client_mac, 6); | ||
1193 | |||
1018 | /* We will restart the wait in any case */ | 1194 | /* We will restart the wait in any case */ |
1019 | already_waited_sec = 0; | 1195 | already_waited_sec = 0; |
1020 | 1196 | ||
@@ -1174,7 +1350,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1174 | 1350 | ||
1175 | /* Ignore packets that aren't for us */ | 1351 | /* Ignore packets that aren't for us */ |
1176 | if (packet.hlen != 6 | 1352 | if (packet.hlen != 6 |
1177 | || memcmp(packet.chaddr, client_config.client_mac, 6) | 1353 | || memcmp(packet.chaddr, client_config.client_mac, 6) != 0 |
1178 | ) { | 1354 | ) { |
1179 | //FIXME: need to also check that last 10 bytes are zero | 1355 | //FIXME: need to also check that last 10 bytes are zero |
1180 | log1("chaddr does not match, ignoring packet"); // log2? | 1356 | log1("chaddr does not match, ignoring packet"); // log2? |
@@ -1194,13 +1370,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1194 | /* TODO: why we don't just fetch server's IP from IP header? */ | 1370 | /* TODO: why we don't just fetch server's IP from IP header? */ |
1195 | temp = udhcp_get_option(&packet, DHCP_SERVER_ID); | 1371 | temp = udhcp_get_option(&packet, DHCP_SERVER_ID); |
1196 | if (!temp) { | 1372 | if (!temp) { |
1197 | bb_error_msg("no server ID in message"); | 1373 | bb_error_msg("no server ID, ignoring packet"); |
1198 | continue; | 1374 | continue; |
1199 | /* still selecting - this server looks bad */ | 1375 | /* still selecting - this server looks bad */ |
1200 | } | 1376 | } |
1201 | /* it IS unaligned sometimes, don't "optimize" */ | 1377 | /* it IS unaligned sometimes, don't "optimize" */ |
1202 | move_from_unaligned32(server_addr, temp); | 1378 | move_from_unaligned32(server_addr, temp); |
1203 | xid = packet.xid; | 1379 | /*xid = packet.xid; - already is */ |
1204 | requested_ip = packet.yiaddr; | 1380 | requested_ip = packet.yiaddr; |
1205 | 1381 | ||
1206 | /* enter requesting state */ | 1382 | /* enter requesting state */ |