aboutsummaryrefslogtreecommitdiff
path: root/networking/udhcp/dhcpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/udhcp/dhcpc.c')
-rw-r--r--networking/udhcp/dhcpc.c142
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
42static 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 */
69enum {
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 */
347static void init_packet(struct dhcp_packet *packet, char type) 408static 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 */
786static void perform_renew(void) 860static 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;