diff options
Diffstat (limited to 'networking/udhcp/dhcpc.c')
-rw-r--r-- | networking/udhcp/dhcpc.c | 142 |
1 files changed, 83 insertions, 59 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index d97a404fa..ca82d37e6 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -38,6 +38,67 @@ | |||
38 | /* struct client_config_t client_config is in bb_common_bufsiz1 */ | 38 | /* struct client_config_t client_config is in bb_common_bufsiz1 */ |
39 | 39 | ||
40 | 40 | ||
41 | #if ENABLE_LONG_OPTS | ||
42 | static const char udhcpc_longopts[] ALIGN1 = | ||
43 | "clientid-none\0" No_argument "C" | ||
44 | "vendorclass\0" Required_argument "V" | ||
45 | "hostname\0" Required_argument "H" | ||
46 | "fqdn\0" Required_argument "F" | ||
47 | "interface\0" Required_argument "i" | ||
48 | "now\0" No_argument "n" | ||
49 | "pidfile\0" Required_argument "p" | ||
50 | "quit\0" No_argument "q" | ||
51 | "release\0" No_argument "R" | ||
52 | "request\0" Required_argument "r" | ||
53 | "script\0" Required_argument "s" | ||
54 | "timeout\0" Required_argument "T" | ||
55 | "version\0" No_argument "v" | ||
56 | "retries\0" Required_argument "t" | ||
57 | "tryagain\0" Required_argument "A" | ||
58 | "syslog\0" No_argument "S" | ||
59 | "request-option\0" Required_argument "O" | ||
60 | "no-default-options\0" No_argument "o" | ||
61 | "foreground\0" No_argument "f" | ||
62 | "background\0" No_argument "b" | ||
63 | "broadcast\0" No_argument "B" | ||
64 | IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a") | ||
65 | IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P") | ||
66 | ; | ||
67 | #endif | ||
68 | /* Must match getopt32 option string order */ | ||
69 | enum { | ||
70 | OPT_C = 1 << 0, | ||
71 | OPT_V = 1 << 1, | ||
72 | OPT_H = 1 << 2, | ||
73 | OPT_h = 1 << 3, | ||
74 | OPT_F = 1 << 4, | ||
75 | OPT_i = 1 << 5, | ||
76 | OPT_n = 1 << 6, | ||
77 | OPT_p = 1 << 7, | ||
78 | OPT_q = 1 << 8, | ||
79 | OPT_R = 1 << 9, | ||
80 | OPT_r = 1 << 10, | ||
81 | OPT_s = 1 << 11, | ||
82 | OPT_T = 1 << 12, | ||
83 | OPT_t = 1 << 13, | ||
84 | OPT_S = 1 << 14, | ||
85 | OPT_A = 1 << 15, | ||
86 | OPT_O = 1 << 16, | ||
87 | OPT_o = 1 << 17, | ||
88 | OPT_x = 1 << 18, | ||
89 | OPT_f = 1 << 19, | ||
90 | OPT_B = 1 << 20, | ||
91 | /* The rest has variable bit positions, need to be clever */ | ||
92 | OPTBIT_B = 20, | ||
93 | USE_FOR_MMU( OPTBIT_b,) | ||
94 | IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) | ||
95 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) | ||
96 | USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,) | ||
97 | IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,) | ||
98 | IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) | ||
99 | }; | ||
100 | |||
101 | |||
41 | /*** Script execution code ***/ | 102 | /*** Script execution code ***/ |
42 | 103 | ||
43 | /* get a rough idea of how long an option will be (rounding up...) */ | 104 | /* get a rough idea of how long an option will be (rounding up...) */ |
@@ -346,11 +407,19 @@ static ALWAYS_INLINE uint32_t random_xid(void) | |||
346 | /* Initialize the packet with the proper defaults */ | 407 | /* Initialize the packet with the proper defaults */ |
347 | static void init_packet(struct dhcp_packet *packet, char type) | 408 | static void init_packet(struct dhcp_packet *packet, char type) |
348 | { | 409 | { |
410 | uint16_t secs; | ||
411 | |||
349 | /* Fill in: op, htype, hlen, cookie fields; message type option: */ | 412 | /* Fill in: op, htype, hlen, cookie fields; message type option: */ |
350 | udhcp_init_header(packet, type); | 413 | udhcp_init_header(packet, type); |
351 | 414 | ||
352 | packet->xid = random_xid(); | 415 | packet->xid = random_xid(); |
353 | 416 | ||
417 | client_config.last_secs = monotonic_sec(); | ||
418 | if (client_config.first_secs == 0) | ||
419 | client_config.first_secs = client_config.last_secs; | ||
420 | secs = client_config.last_secs - client_config.first_secs; | ||
421 | packet->secs = htons(secs); | ||
422 | |||
354 | memcpy(packet->chaddr, client_config.client_mac, 6); | 423 | memcpy(packet->chaddr, client_config.client_mac, 6); |
355 | if (client_config.clientid) | 424 | if (client_config.clientid) |
356 | udhcp_add_binary_option(packet, client_config.clientid); | 425 | udhcp_add_binary_option(packet, client_config.clientid); |
@@ -391,6 +460,10 @@ static void add_client_options(struct dhcp_packet *packet) | |||
391 | if (client_config.fqdn) | 460 | if (client_config.fqdn) |
392 | udhcp_add_binary_option(packet, client_config.fqdn); | 461 | udhcp_add_binary_option(packet, client_config.fqdn); |
393 | 462 | ||
463 | /* Request broadcast replies if we have no IP addr */ | ||
464 | if ((option_mask32 & OPT_B) && packet->ciaddr == 0) | ||
465 | packet->flags |= htons(BROADCAST_FLAG); | ||
466 | |||
394 | /* Add -x options if any */ | 467 | /* Add -x options if any */ |
395 | { | 468 | { |
396 | struct option_set *curr = client_config.options; | 469 | struct option_set *curr = client_config.options; |
@@ -783,6 +856,7 @@ static void change_listen_mode(int new_mode) | |||
783 | /* else LISTEN_NONE: sockfd stays closed */ | 856 | /* else LISTEN_NONE: sockfd stays closed */ |
784 | } | 857 | } |
785 | 858 | ||
859 | /* Called only on SIGUSR1 */ | ||
786 | static void perform_renew(void) | 860 | static void perform_renew(void) |
787 | { | 861 | { |
788 | bb_info_msg("Performing a DHCP renew"); | 862 | bb_info_msg("Performing a DHCP renew"); |
@@ -853,13 +927,14 @@ static void client_background(void) | |||
853 | //usage:# define IF_UDHCP_VERBOSE(...) | 927 | //usage:# define IF_UDHCP_VERBOSE(...) |
854 | //usage:#endif | 928 | //usage:#endif |
855 | //usage:#define udhcpc_trivial_usage | 929 | //usage:#define udhcpc_trivial_usage |
856 | //usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oCR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" | 930 | //usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" |
857 | //usage: " [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") | 931 | //usage: " [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") |
858 | //usage:#define udhcpc_full_usage "\n" | 932 | //usage:#define udhcpc_full_usage "\n" |
859 | //usage: IF_LONG_OPTS( | 933 | //usage: IF_LONG_OPTS( |
860 | //usage: "\n -i,--interface IFACE Interface to use (default eth0)" | 934 | //usage: "\n -i,--interface IFACE Interface to use (default eth0)" |
861 | //usage: "\n -p,--pidfile FILE Create pidfile" | 935 | //usage: "\n -p,--pidfile FILE Create pidfile" |
862 | //usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" | 936 | //usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" |
937 | //usage: "\n -B,--broadcast Request broadcast replies" | ||
863 | //usage: "\n -t,--retries N Send up to N discover packets" | 938 | //usage: "\n -t,--retries N Send up to N discover packets" |
864 | //usage: "\n -T,--timeout N Pause between packets (default 3 seconds)" | 939 | //usage: "\n -T,--timeout N Pause between packets (default 3 seconds)" |
865 | //usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)" | 940 | //usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)" |
@@ -897,6 +972,7 @@ static void client_background(void) | |||
897 | //usage: "\n -i IFACE Interface to use (default eth0)" | 972 | //usage: "\n -i IFACE Interface to use (default eth0)" |
898 | //usage: "\n -p FILE Create pidfile" | 973 | //usage: "\n -p FILE Create pidfile" |
899 | //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" | 974 | //usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" |
975 | //usage: "\n -B Request broadcast replies" | ||
900 | //usage: "\n -t N Send up to N discover packets" | 976 | //usage: "\n -t N Send up to N discover packets" |
901 | //usage: "\n -T N Pause between packets (default 3 seconds)" | 977 | //usage: "\n -T N Pause between packets (default 3 seconds)" |
902 | //usage: "\n -A N Wait N seconds (default 20) after failure" | 978 | //usage: "\n -A N Wait N seconds (default 20) after failure" |
@@ -961,63 +1037,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
961 | struct dhcp_packet packet; | 1037 | struct dhcp_packet packet; |
962 | fd_set rfds; | 1038 | fd_set rfds; |
963 | 1039 | ||
964 | #if ENABLE_LONG_OPTS | ||
965 | static const char udhcpc_longopts[] ALIGN1 = | ||
966 | "clientid-none\0" No_argument "C" | ||
967 | "vendorclass\0" Required_argument "V" | ||
968 | "hostname\0" Required_argument "H" | ||
969 | "fqdn\0" Required_argument "F" | ||
970 | "interface\0" Required_argument "i" | ||
971 | "now\0" No_argument "n" | ||
972 | "pidfile\0" Required_argument "p" | ||
973 | "quit\0" No_argument "q" | ||
974 | "release\0" No_argument "R" | ||
975 | "request\0" Required_argument "r" | ||
976 | "script\0" Required_argument "s" | ||
977 | "timeout\0" Required_argument "T" | ||
978 | "version\0" No_argument "v" | ||
979 | "retries\0" Required_argument "t" | ||
980 | "tryagain\0" Required_argument "A" | ||
981 | "syslog\0" No_argument "S" | ||
982 | "request-option\0" Required_argument "O" | ||
983 | "no-default-options\0" No_argument "o" | ||
984 | "foreground\0" No_argument "f" | ||
985 | "background\0" No_argument "b" | ||
986 | IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a") | ||
987 | IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P") | ||
988 | ; | ||
989 | #endif | ||
990 | enum { | ||
991 | OPT_C = 1 << 0, | ||
992 | OPT_V = 1 << 1, | ||
993 | OPT_H = 1 << 2, | ||
994 | OPT_h = 1 << 3, | ||
995 | OPT_F = 1 << 4, | ||
996 | OPT_i = 1 << 5, | ||
997 | OPT_n = 1 << 6, | ||
998 | OPT_p = 1 << 7, | ||
999 | OPT_q = 1 << 8, | ||
1000 | OPT_R = 1 << 9, | ||
1001 | OPT_r = 1 << 10, | ||
1002 | OPT_s = 1 << 11, | ||
1003 | OPT_T = 1 << 12, | ||
1004 | OPT_t = 1 << 13, | ||
1005 | OPT_S = 1 << 14, | ||
1006 | OPT_A = 1 << 15, | ||
1007 | OPT_O = 1 << 16, | ||
1008 | OPT_o = 1 << 17, | ||
1009 | OPT_x = 1 << 18, | ||
1010 | OPT_f = 1 << 19, | ||
1011 | /* The rest has variable bit positions, need to be clever */ | ||
1012 | OPTBIT_f = 19, | ||
1013 | USE_FOR_MMU( OPTBIT_b,) | ||
1014 | IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) | ||
1015 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) | ||
1016 | USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,) | ||
1017 | IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,) | ||
1018 | IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) | ||
1019 | }; | ||
1020 | |||
1021 | /* Default options */ | 1040 | /* Default options */ |
1022 | IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;) | 1041 | IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;) |
1023 | IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;) | 1042 | IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;) |
@@ -1033,7 +1052,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1033 | #endif | 1052 | #endif |
1034 | ; | 1053 | ; |
1035 | IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) | 1054 | IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) |
1036 | opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:f" | 1055 | opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB" |
1037 | USE_FOR_MMU("b") | 1056 | USE_FOR_MMU("b") |
1038 | IF_FEATURE_UDHCPC_ARPING("a") | 1057 | IF_FEATURE_UDHCPC_ARPING("a") |
1039 | IF_FEATURE_UDHCP_PORT("P:") | 1058 | IF_FEATURE_UDHCP_PORT("P:") |
@@ -1250,6 +1269,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1250 | case BOUND: | 1269 | case BOUND: |
1251 | /* 1/2 lease passed, enter renewing state */ | 1270 | /* 1/2 lease passed, enter renewing state */ |
1252 | state = RENEWING; | 1271 | state = RENEWING; |
1272 | client_config.first_secs = 0; /* make secs field count from 0 */ | ||
1253 | change_listen_mode(LISTEN_KERNEL); | 1273 | change_listen_mode(LISTEN_KERNEL); |
1254 | log1("Entering renew state"); | 1274 | log1("Entering renew state"); |
1255 | /* fall right through */ | 1275 | /* fall right through */ |
@@ -1289,6 +1309,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1289 | bb_info_msg("Lease lost, entering init state"); | 1309 | bb_info_msg("Lease lost, entering init state"); |
1290 | udhcp_run_script(NULL, "deconfig"); | 1310 | udhcp_run_script(NULL, "deconfig"); |
1291 | state = INIT_SELECTING; | 1311 | state = INIT_SELECTING; |
1312 | client_config.first_secs = 0; /* make secs field count from 0 */ | ||
1292 | /*timeout = 0; - already is */ | 1313 | /*timeout = 0; - already is */ |
1293 | packet_num = 0; | 1314 | packet_num = 0; |
1294 | continue; | 1315 | continue; |
@@ -1305,6 +1326,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1305 | /* note: udhcp_sp_read checks FD_ISSET before reading */ | 1326 | /* note: udhcp_sp_read checks FD_ISSET before reading */ |
1306 | switch (udhcp_sp_read(&rfds)) { | 1327 | switch (udhcp_sp_read(&rfds)) { |
1307 | case SIGUSR1: | 1328 | case SIGUSR1: |
1329 | client_config.first_secs = 0; /* make secs field count from 0 */ | ||
1308 | perform_renew(); | 1330 | perform_renew(); |
1309 | if (state == RENEW_REQUESTED) | 1331 | if (state == RENEW_REQUESTED) |
1310 | goto case_RENEW_REQUESTED; | 1332 | goto case_RENEW_REQUESTED; |
@@ -1436,6 +1458,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1436 | udhcp_run_script(NULL, "deconfig"); | 1458 | udhcp_run_script(NULL, "deconfig"); |
1437 | change_listen_mode(LISTEN_RAW); | 1459 | change_listen_mode(LISTEN_RAW); |
1438 | state = INIT_SELECTING; | 1460 | state = INIT_SELECTING; |
1461 | client_config.first_secs = 0; /* make secs field count from 0 */ | ||
1439 | requested_ip = 0; | 1462 | requested_ip = 0; |
1440 | timeout = tryagain_timeout; | 1463 | timeout = tryagain_timeout; |
1441 | packet_num = 0; | 1464 | packet_num = 0; |
@@ -1483,6 +1506,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1483 | change_listen_mode(LISTEN_RAW); | 1506 | change_listen_mode(LISTEN_RAW); |
1484 | sleep(3); /* avoid excessive network traffic */ | 1507 | sleep(3); /* avoid excessive network traffic */ |
1485 | state = INIT_SELECTING; | 1508 | state = INIT_SELECTING; |
1509 | client_config.first_secs = 0; /* make secs field count from 0 */ | ||
1486 | requested_ip = 0; | 1510 | requested_ip = 0; |
1487 | timeout = 0; | 1511 | timeout = 0; |
1488 | packet_num = 0; | 1512 | packet_num = 0; |