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.c322
1 files changed, 168 insertions, 154 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 6666cbce6..4e3d8ca5e 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -55,8 +55,7 @@ struct tpacket_auxdata {
55#if ENABLE_LONG_OPTS 55#if ENABLE_LONG_OPTS
56static const char udhcpc_longopts[] ALIGN1 = 56static const char udhcpc_longopts[] ALIGN1 =
57 "clientid-none\0" No_argument "C" 57 "clientid-none\0" No_argument "C"
58 "vendorclass\0" Required_argument "V" 58 "vendorclass\0" Required_argument "V" //deprecated
59 "hostname\0" Required_argument "H"
60 "fqdn\0" Required_argument "F" 59 "fqdn\0" Required_argument "F"
61 "interface\0" Required_argument "i" 60 "interface\0" Required_argument "i"
62 "now\0" No_argument "n" 61 "now\0" No_argument "n"
@@ -84,27 +83,25 @@ static const char udhcpc_longopts[] ALIGN1 =
84enum { 83enum {
85 OPT_C = 1 << 0, 84 OPT_C = 1 << 0,
86 OPT_V = 1 << 1, 85 OPT_V = 1 << 1,
87 OPT_H = 1 << 2, 86 OPT_F = 1 << 2,
88 OPT_h = 1 << 3, 87 OPT_i = 1 << 3,
89 OPT_F = 1 << 4, 88 OPT_n = 1 << 4,
90 OPT_i = 1 << 5, 89 OPT_p = 1 << 5,
91 OPT_n = 1 << 6, 90 OPT_q = 1 << 6,
92 OPT_p = 1 << 7, 91 OPT_R = 1 << 7,
93 OPT_q = 1 << 8, 92 OPT_r = 1 << 8,
94 OPT_R = 1 << 9, 93 OPT_s = 1 << 9,
95 OPT_r = 1 << 10, 94 OPT_T = 1 << 10,
96 OPT_s = 1 << 11, 95 OPT_t = 1 << 11,
97 OPT_T = 1 << 12, 96 OPT_S = 1 << 12,
98 OPT_t = 1 << 13, 97 OPT_A = 1 << 13,
99 OPT_S = 1 << 14, 98 OPT_O = 1 << 14,
100 OPT_A = 1 << 15, 99 OPT_o = 1 << 15,
101 OPT_O = 1 << 16, 100 OPT_x = 1 << 16,
102 OPT_o = 1 << 17, 101 OPT_f = 1 << 17,
103 OPT_x = 1 << 18, 102 OPT_B = 1 << 18,
104 OPT_f = 1 << 19,
105 OPT_B = 1 << 20,
106/* The rest has variable bit positions, need to be clever */ 103/* The rest has variable bit positions, need to be clever */
107 OPTBIT_B = 20, 104 OPTBIT_B = 18,
108 USE_FOR_MMU( OPTBIT_b,) 105 USE_FOR_MMU( OPTBIT_b,)
109 IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) 106 IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
110 IF_FEATURE_UDHCP_PORT( OPTBIT_P,) 107 IF_FEATURE_UDHCP_PORT( OPTBIT_P,)
@@ -569,8 +566,8 @@ static void fill_envp(struct dhcp_packet *packet)
569 } 566 }
570} 567}
571 568
572/* Call a script with a par file and env vars */ 569/* Call a script with env vars */
573static void udhcp_run_script(struct dhcp_packet *packet, const char *name) 570static void d4_run_script(struct dhcp_packet *packet, const char *name)
574{ 571{
575 char *argv[3]; 572 char *argv[3];
576 573
@@ -588,6 +585,10 @@ static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
588 client_data.envp = NULL; 585 client_data.envp = NULL;
589} 586}
590 587
588static void d4_run_script_deconfig(void)
589{
590 d4_run_script(NULL, "deconfig");
591}
591 592
592/*** Sending/receiving packets ***/ 593/*** Sending/receiving packets ***/
593 594
@@ -613,8 +614,6 @@ static void init_packet(struct dhcp_packet *packet, char type)
613 packet->secs = (secs < 0xffff) ? htons(secs) : 0xffff; 614 packet->secs = (secs < 0xffff) ? htons(secs) : 0xffff;
614 615
615 memcpy(packet->chaddr, client_data.client_mac, 6); 616 memcpy(packet->chaddr, client_data.client_mac, 6);
616 if (client_data.clientid)
617 udhcp_add_binary_option(packet, client_data.clientid);
618} 617}
619 618
620static void add_client_options(struct dhcp_packet *packet) 619static void add_client_options(struct dhcp_packet *packet)
@@ -640,13 +639,6 @@ static void add_client_options(struct dhcp_packet *packet)
640 packet->options[end + OPT_DATA + len] = DHCP_END; 639 packet->options[end + OPT_DATA + len] = DHCP_END;
641 } 640 }
642 641
643 if (client_data.vendorclass)
644 udhcp_add_binary_option(packet, client_data.vendorclass);
645 if (client_data.hostname)
646 udhcp_add_binary_option(packet, client_data.hostname);
647 if (client_data.fqdn)
648 udhcp_add_binary_option(packet, client_data.fqdn);
649
650 /* Request broadcast replies if we have no IP addr */ 642 /* Request broadcast replies if we have no IP addr */
651 if ((option_mask32 & OPT_B) && packet->ciaddr == 0) 643 if ((option_mask32 & OPT_B) && packet->ciaddr == 0)
652 packet->flags |= htons(BROADCAST_FLAG); 644 packet->flags |= htons(BROADCAST_FLAG);
@@ -715,7 +707,7 @@ static NOINLINE int send_discover(uint32_t xid, uint32_t requested)
715 707
716 /* Fill in: op, htype, hlen, cookie, chaddr fields, 708 /* Fill in: op, htype, hlen, cookie, chaddr fields,
717 * random xid field (we override it below), 709 * random xid field (we override it below),
718 * client-id option (unless -C), message type option: 710 * message type option:
719 */ 711 */
720 init_packet(&packet, DHCPDISCOVER); 712 init_packet(&packet, DHCPDISCOVER);
721 713
@@ -724,7 +716,6 @@ static NOINLINE int send_discover(uint32_t xid, uint32_t requested)
724 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); 716 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
725 717
726 /* Add options: maxsize, 718 /* Add options: maxsize,
727 * optionally: hostname, fqdn, vendorclass,
728 * "param req" option according to -O, options specified with -x 719 * "param req" option according to -O, options specified with -x
729 */ 720 */
730 add_client_options(&packet); 721 add_client_options(&packet);
@@ -758,7 +749,7 @@ static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requeste
758 */ 749 */
759 /* Fill in: op, htype, hlen, cookie, chaddr fields, 750 /* Fill in: op, htype, hlen, cookie, chaddr fields,
760 * random xid field (we override it below), 751 * random xid field (we override it below),
761 * client-id option (unless -C), message type option: 752 * message type option:
762 */ 753 */
763 init_packet(&packet, DHCPREQUEST); 754 init_packet(&packet, DHCPREQUEST);
764 755
@@ -768,7 +759,6 @@ static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requeste
768 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 759 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
769 760
770 /* Add options: maxsize, 761 /* Add options: maxsize,
771 * optionally: hostname, fqdn, vendorclass,
772 * "param req" option according to -O, and options specified with -x 762 * "param req" option according to -O, and options specified with -x
773 */ 763 */
774 add_client_options(&packet); 764 add_client_options(&packet);
@@ -805,7 +795,7 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
805 */ 795 */
806 /* Fill in: op, htype, hlen, cookie, chaddr fields, 796 /* Fill in: op, htype, hlen, cookie, chaddr fields,
807 * random xid field (we override it below), 797 * random xid field (we override it below),
808 * client-id option (unless -C), message type option: 798 * message type option:
809 */ 799 */
810 init_packet(&packet, DHCPREQUEST); 800 init_packet(&packet, DHCPREQUEST);
811 801
@@ -813,7 +803,6 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
813 packet.ciaddr = ciaddr; 803 packet.ciaddr = ciaddr;
814 804
815 /* Add options: maxsize, 805 /* Add options: maxsize,
816 * optionally: hostname, fqdn, vendorclass,
817 * "param req" option according to -O, and options specified with -x 806 * "param req" option according to -O, and options specified with -x
818 */ 807 */
819 add_client_options(&packet); 808 add_client_options(&packet);
@@ -837,7 +826,7 @@ static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t req
837 struct dhcp_packet packet; 826 struct dhcp_packet packet;
838 827
839 /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, 828 /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields,
840 * client-id option (unless -C), message type option: 829 * message type option:
841 */ 830 */
842 init_packet(&packet, DHCPDECLINE); 831 init_packet(&packet, DHCPDECLINE);
843 832
@@ -854,6 +843,8 @@ static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t req
854 843
855 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 844 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
856 845
846//TODO: add client-id opt?
847
857 bb_simple_info_msg("broadcasting decline"); 848 bb_simple_info_msg("broadcasting decline");
858 return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY); 849 return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY);
859} 850}
@@ -865,9 +856,10 @@ ALWAYS_INLINE /* one caller, help compiler to use this fact */
865int send_release(uint32_t server, uint32_t ciaddr) 856int send_release(uint32_t server, uint32_t ciaddr)
866{ 857{
867 struct dhcp_packet packet; 858 struct dhcp_packet packet;
859 struct option_set *ci;
868 860
869 /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, 861 /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields,
870 * client-id option (unless -C), message type option: 862 * message type option:
871 */ 863 */
872 init_packet(&packet, DHCPRELEASE); 864 init_packet(&packet, DHCPRELEASE);
873 865
@@ -876,6 +868,14 @@ int send_release(uint32_t server, uint32_t ciaddr)
876 868
877 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 869 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
878 870
871 /* RFC 2131 section 3.1.6:
872 * If the client used a 'client identifier' when it obtained the lease,
873 * it MUST use the same 'client identifier' in the DHCPRELEASE message.
874 */
875 ci = udhcp_find_option(client_data.options, DHCP_CLIENT_ID);
876 if (ci)
877 udhcp_add_binary_option(&packet, ci->data);
878
879 bb_info_msg("sending %s", "release"); 879 bb_info_msg("sending %s", "release");
880 /* Note: normally we unicast here since "server" is not zero. 880 /* Note: normally we unicast here since "server" is not zero.
881 * However, there _are_ people who run "address-less" DHCP servers, 881 * However, there _are_ people who run "address-less" DHCP servers,
@@ -886,7 +886,7 @@ int send_release(uint32_t server, uint32_t ciaddr)
886 886
887/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ 887/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
888/* NOINLINE: limit stack usage in caller */ 888/* NOINLINE: limit stack usage in caller */
889static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) 889static NOINLINE int d4_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
890{ 890{
891 int bytes; 891 int bytes;
892 struct ip_udp_dhcp_packet packet; 892 struct ip_udp_dhcp_packet packet;
@@ -979,11 +979,12 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
979 skip_udp_sum_check: 979 skip_udp_sum_check:
980 980
981 if (packet.data.cookie != htonl(DHCP_MAGIC)) { 981 if (packet.data.cookie != htonl(DHCP_MAGIC)) {
982 bb_simple_info_msg("packet with bad magic, ignoring"); 982 log1s("packet with bad magic, ignoring");
983 return -2; 983 return -2;
984 } 984 }
985 985
986 log1("received %s", "a packet"); 986 log2("received %s", "a packet");
987 /* log2 because more informative msg for valid packets is printed later at log1 level */
987 udhcp_dump_packet(&packet.data); 988 udhcp_dump_packet(&packet.data);
988 989
989 bytes -= sizeof(packet.ip) + sizeof(packet.udp); 990 bytes -= sizeof(packet.ip) + sizeof(packet.udp);
@@ -1096,8 +1097,6 @@ static int udhcp_raw_socket(int ifindex)
1096 log1s("can't set PACKET_AUXDATA on raw socket"); 1097 log1s("can't set PACKET_AUXDATA on raw socket");
1097 } 1098 }
1098 1099
1099 log1s("created raw socket");
1100
1101 return fd; 1100 return fd;
1102} 1101}
1103 1102
@@ -1126,6 +1125,8 @@ static void perform_release(uint32_t server_addr, uint32_t requested_ip)
1126 char buffer[sizeof("255.255.255.255")]; 1125 char buffer[sizeof("255.255.255.255")];
1127 struct in_addr temp_addr; 1126 struct in_addr temp_addr;
1128 1127
1128 change_listen_mode(LISTEN_NONE);
1129
1129 /* send release packet */ 1130 /* send release packet */
1130 if (client_data.state == BOUND 1131 if (client_data.state == BOUND
1131 || client_data.state == RENEWING 1132 || client_data.state == RENEWING
@@ -1146,23 +1147,10 @@ static void perform_release(uint32_t server_addr, uint32_t requested_ip)
1146 * Users requested to be notified in all cases, even if not in one 1147 * Users requested to be notified in all cases, even if not in one
1147 * of the states above. 1148 * of the states above.
1148 */ 1149 */
1149 udhcp_run_script(NULL, "deconfig"); 1150 d4_run_script_deconfig();
1150
1151 change_listen_mode(LISTEN_NONE);
1152 client_data.state = RELEASED; 1151 client_data.state = RELEASED;
1153} 1152}
1154 1153
1155static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
1156{
1157 uint8_t *storage;
1158 int len = strnlen(str, 255);
1159 storage = xzalloc(len + extra + OPT_DATA);
1160 storage[OPT_CODE] = code;
1161 storage[OPT_LEN] = len + extra;
1162 memcpy(storage + extra + OPT_DATA, str, len);
1163 return storage;
1164}
1165
1166#if BB_MMU 1154#if BB_MMU
1167static void client_background(void) 1155static void client_background(void)
1168{ 1156{
@@ -1227,10 +1215,10 @@ int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1227int udhcpc_main(int argc UNUSED_PARAM, char **argv) 1215int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1228{ 1216{
1229 uint8_t *message; 1217 uint8_t *message;
1230 const char *str_V, *str_h, *str_F, *str_r; 1218 const char *str_V, *str_F, *str_r;
1231 IF_FEATURE_UDHCPC_ARPING(const char *str_a = "2000";) 1219 IF_FEATURE_UDHCPC_ARPING(const char *str_a = "2000";)
1232 IF_FEATURE_UDHCP_PORT(char *str_P;) 1220 IF_FEATURE_UDHCP_PORT(char *str_P;)
1233 void *clientid_mac_ptr; 1221 uint8_t *clientid_mac_ptr;
1234 llist_t *list_O = NULL; 1222 llist_t *list_O = NULL;
1235 llist_t *list_x = NULL; 1223 llist_t *list_x = NULL;
1236 int tryagain_timeout = 20; 1224 int tryagain_timeout = 20;
@@ -1263,14 +1251,14 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1263 /* Parse command line */ 1251 /* Parse command line */
1264 opt = getopt32long(argv, "^" 1252 opt = getopt32long(argv, "^"
1265 /* O,x: list; -T,-t,-A take numeric param */ 1253 /* O,x: list; -T,-t,-A take numeric param */
1266 "CV:H:h:F:i:np:qRr:s:T:+t:+SA:+O:*ox:*fB" 1254 "CV:F:i:np:qRr:s:T:+t:+SA:+O:*ox:*fB"
1267 USE_FOR_MMU("b") 1255 USE_FOR_MMU("b")
1268 IF_FEATURE_UDHCPC_ARPING("a::") 1256 IF_FEATURE_UDHCPC_ARPING("a::")
1269 IF_FEATURE_UDHCP_PORT("P:") 1257 IF_FEATURE_UDHCP_PORT("P:")
1270 "v" 1258 "v"
1271 "\0" IF_UDHCP_VERBOSE("vv") /* -v is a counter */ 1259 "\0" IF_UDHCP_VERBOSE("vv") /* -v is a counter */
1272 , udhcpc_longopts 1260 , udhcpc_longopts
1273 , &str_V, &str_h, &str_h, &str_F 1261 , &str_V, &str_F
1274 , &client_data.interface, &client_data.pidfile /* i,p */ 1262 , &client_data.interface, &client_data.pidfile /* i,p */
1275 , &str_r /* r */ 1263 , &str_r /* r */
1276 , &client_data.script /* s */ 1264 , &client_data.script /* s */
@@ -1281,14 +1269,14 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1281 IF_FEATURE_UDHCP_PORT(, &str_P) 1269 IF_FEATURE_UDHCP_PORT(, &str_P)
1282 IF_UDHCP_VERBOSE(, &dhcp_verbose) 1270 IF_UDHCP_VERBOSE(, &dhcp_verbose)
1283 ); 1271 );
1284 if (opt & (OPT_h|OPT_H)) {
1285 //msg added 2011-11
1286 bb_simple_error_msg("option -h NAME is deprecated, use -x hostname:NAME");
1287 client_data.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
1288 }
1289 if (opt & OPT_F) { 1272 if (opt & OPT_F) {
1273 char *p;
1274 unsigned len;
1290 /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */ 1275 /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */
1291 client_data.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3); 1276 len = strlen(str_F);
1277 p = udhcp_insert_new_option(
1278 &client_data.options, DHCP_FQDN,
1279 len + 3, /*dhcp6:*/ 0);
1292 /* Flag bits: 0000NEOS 1280 /* Flag bits: 0000NEOS
1293 * S: 1 = Client requests server to update A RR in DNS as well as PTR 1281 * S: 1 = Client requests server to update A RR in DNS as well as PTR
1294 * O: 1 = Server indicates to client that DNS has been updated regardless 1282 * O: 1 = Server indicates to client that DNS has been updated regardless
@@ -1297,9 +1285,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1297 * N: 1 = Client requests server to not update DNS (S must be 0 then) 1285 * N: 1 = Client requests server to not update DNS (S must be 0 then)
1298 * Two [0] bytes which follow are deprecated and must be 0. 1286 * Two [0] bytes which follow are deprecated and must be 0.
1299 */ 1287 */
1300 client_data.fqdn[OPT_DATA + 0] = 0x1; 1288 p[OPT_DATA + 0] = 0x1;
1301 /*client_data.fqdn[OPT_DATA + 1] = 0; - xzalloc did it */ 1289 /*p[OPT_DATA + 1] = 0; - xzalloc did it */
1302 /*client_data.fqdn[OPT_DATA + 2] = 0; */ 1290 /*p[OPT_DATA + 2] = 0; */
1291 memcpy(p + OPT_DATA + 3, str_F, len); /* do not store NUL byte */
1303 } 1292 }
1304 if (opt & OPT_r) 1293 if (opt & OPT_r)
1305 requested_ip = inet_addr(str_r); 1294 requested_ip = inet_addr(str_r);
@@ -1335,7 +1324,29 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1335 ); 1324 );
1336 free(optstr); 1325 free(optstr);
1337 } 1326 }
1327 if (str_V[0] != '\0') {
1328 char *p;
1329 unsigned len = strnlen(str_V, 254);
1330 p = udhcp_insert_new_option(
1331 &client_data.options, DHCP_VENDOR,
1332 len, /*dhcp6:*/ 0);
1333 memcpy(p + OPT_DATA, str_V, len); /* do not store NUL byte */
1334 }
1335
1336 clientid_mac_ptr = NULL;
1337 if (!(opt & OPT_C) && !udhcp_find_option(client_data.options, DHCP_CLIENT_ID)) {
1338 /* not suppressed and not set, create default client ID */
1339 clientid_mac_ptr = udhcp_insert_new_option(
1340 &client_data.options, DHCP_CLIENT_ID,
1341 1 + 6, /*dhcp6:*/ 0);
1342 clientid_mac_ptr[OPT_DATA] = 1; /* type: ethernet */
1343 clientid_mac_ptr += OPT_DATA + 1; /* skip option code, len, ethernet */
1344 }
1338 1345
1346 /* Not really necessary (we redo it on every iteration)
1347 * but allows early (before daemonization) detection
1348 * of bad interface name.
1349 */
1339 if (udhcp_read_interface(client_data.interface, 1350 if (udhcp_read_interface(client_data.interface,
1340 &client_data.ifindex, 1351 &client_data.ifindex,
1341 NULL, 1352 NULL,
@@ -1344,24 +1355,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1344 return 1; 1355 return 1;
1345 } 1356 }
1346 1357
1347 clientid_mac_ptr = NULL;
1348 if (!(opt & OPT_C) && !udhcp_find_option(client_data.options, DHCP_CLIENT_ID)) {
1349 /* not suppressed and not set, set the default client ID */
1350 client_data.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
1351 client_data.clientid[OPT_DATA] = 1; /* type: ethernet */
1352 clientid_mac_ptr = client_data.clientid + OPT_DATA+1;
1353 memcpy(clientid_mac_ptr, client_data.client_mac, 6);
1354 }
1355 if (str_V[0] != '\0') {
1356 // can drop -V, str_V, client_data.vendorclass,
1357 // but need to add "vendor" to the list of recognized
1358 // string opts for this to work;
1359 // and need to tweak add_client_options() too...
1360 // ...so the question is, should we?
1361 //bb_error_msg("option -V VENDOR is deprecated, use -x vendor:VENDOR");
1362 client_data.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
1363 }
1364
1365#if !BB_MMU 1358#if !BB_MMU
1366 /* on NOMMU reexec (i.e., background) early */ 1359 /* on NOMMU reexec (i.e., background) early */
1367 if (!(opt & OPT_f)) { 1360 if (!(opt & OPT_f)) {
@@ -1382,8 +1375,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1382 srand(monotonic_us()); 1375 srand(monotonic_us());
1383 1376
1384 client_data.state = INIT_SELECTING; 1377 client_data.state = INIT_SELECTING;
1385 udhcp_run_script(NULL, "deconfig"); 1378 d4_run_script_deconfig();
1386 change_listen_mode(LISTEN_RAW);
1387 packet_num = 0; 1379 packet_num = 0;
1388 timeout = 0; 1380 timeout = 0;
1389 lease_remaining = 0; 1381 lease_remaining = 0;
@@ -1417,14 +1409,17 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1417 log1("waiting %u seconds", timeout); 1409 log1("waiting %u seconds", timeout);
1418 diff = (unsigned)monotonic_sec(); 1410 diff = (unsigned)monotonic_sec();
1419 retval = poll(pfds, 2, timeout * 1000); 1411 retval = poll(pfds, 2, timeout * 1000);
1412 diff = (unsigned)monotonic_sec() - diff;
1413 lease_remaining -= diff;
1414 if (lease_remaining < 0)
1415 lease_remaining = 0;
1416 timeout -= diff;
1417 if (timeout < 0)
1418 timeout = 0;
1419
1420 if (retval < 0) { 1420 if (retval < 0) {
1421 /* EINTR? A signal was caught, don't panic */ 1421 /* EINTR? A signal was caught, don't panic */
1422 if (errno == EINTR) { 1422 if (errno == EINTR) {
1423 diff = (unsigned)monotonic_sec() - diff;
1424 lease_remaining -= diff;
1425 if (lease_remaining < 0)
1426 lease_remaining = 0;
1427 timeout -= diff;
1428 continue; 1423 continue;
1429 } 1424 }
1430 /* Else: an error occurred, panic! */ 1425 /* Else: an error occurred, panic! */
@@ -1454,8 +1449,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1454 switch (client_data.state) { 1449 switch (client_data.state) {
1455 case INIT_SELECTING: 1450 case INIT_SELECTING:
1456 if (!discover_retries || packet_num < discover_retries) { 1451 if (!discover_retries || packet_num < discover_retries) {
1457 if (packet_num == 0) 1452 if (packet_num == 0) {
1453 change_listen_mode(LISTEN_RAW);
1458 xid = random_xid(); 1454 xid = random_xid();
1455 }
1459 /* broadcast */ 1456 /* broadcast */
1460 send_discover(xid, requested_ip); 1457 send_discover(xid, requested_ip);
1461 timeout = discover_timeout; 1458 timeout = discover_timeout;
@@ -1463,7 +1460,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1463 continue; 1460 continue;
1464 } 1461 }
1465 leasefail: 1462 leasefail:
1466 udhcp_run_script(NULL, "leasefail"); 1463 change_listen_mode(LISTEN_NONE);
1464 d4_run_script(NULL, "leasefail");
1467#if BB_MMU /* -b is not supported on NOMMU */ 1465#if BB_MMU /* -b is not supported on NOMMU */
1468 if (opt & OPT_b) { /* background if no lease */ 1466 if (opt & OPT_b) { /* background if no lease */
1469 bb_simple_info_msg("no lease, forking to background"); 1467 bb_simple_info_msg("no lease, forking to background");
@@ -1483,7 +1481,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1483 retval = 1; 1481 retval = 1;
1484 goto ret; 1482 goto ret;
1485 } 1483 }
1486 /* wait before trying again */ 1484 /* Wait before trying again */
1487 timeout = tryagain_timeout; 1485 timeout = tryagain_timeout;
1488 packet_num = 0; 1486 packet_num = 0;
1489 continue; 1487 continue;
@@ -1499,22 +1497,20 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1499 * "discover...select...discover..." loops 1497 * "discover...select...discover..." loops
1500 * were seen in the wild. Treat them similarly 1498 * were seen in the wild. Treat them similarly
1501 * to "no response to discover" case */ 1499 * to "no response to discover" case */
1502 change_listen_mode(LISTEN_RAW);
1503 client_data.state = INIT_SELECTING; 1500 client_data.state = INIT_SELECTING;
1504 goto leasefail; 1501 goto leasefail;
1505 case BOUND: 1502 case BOUND:
1506 /* 1/2 lease passed, enter renewing state */ 1503 /* 1/2 lease passed, enter renewing state */
1507 client_data.state = RENEWING; 1504 client_data.state = RENEWING;
1508 client_data.first_secs = 0; /* make secs field count from 0 */ 1505 client_data.first_secs = 0; /* make secs field count from 0 */
1509 change_listen_mode(LISTEN_KERNEL); 1506 got_SIGUSR1:
1510 log1s("entering renew state"); 1507 log1s("entering renew state");
1508 change_listen_mode(LISTEN_KERNEL);
1511 /* fall right through */ 1509 /* fall right through */
1512 case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ 1510 case RENEW_REQUESTED: /* in manual (SIGUSR1) renew */
1513 case_RENEW_REQUESTED:
1514 case RENEWING: 1511 case RENEWING:
1515 if (packet_num < 3) { 1512 if (packet_num == 0) {
1516 packet_num++; 1513 /* Send an unicast renew request */
1517 /* send an unicast renew request */
1518 /* Sometimes observed to fail (EADDRNOTAVAIL) to bind 1514 /* Sometimes observed to fail (EADDRNOTAVAIL) to bind
1519 * a new UDP socket for sending inside send_renew. 1515 * a new UDP socket for sending inside send_renew.
1520 * I hazard to guess existing listening socket 1516 * I hazard to guess existing listening socket
@@ -1525,7 +1521,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1525 */ 1521 */
1526 if (send_renew(xid, server_addr, requested_ip) >= 0) { 1522 if (send_renew(xid, server_addr, requested_ip) >= 0) {
1527 timeout = discover_timeout; 1523 timeout = discover_timeout;
1528 /* ^^^ used to be = lease_remaining / 2 - WAY too long */ 1524 packet_num++;
1529 continue; 1525 continue;
1530 } 1526 }
1531 /* else: error sending. 1527 /* else: error sending.
@@ -1533,27 +1529,34 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1533 * which gave us bogus server ID 1.1.1.1 1529 * which gave us bogus server ID 1.1.1.1
1534 * which wasn't reachable (and probably did not exist). 1530 * which wasn't reachable (and probably did not exist).
1535 */ 1531 */
1532 } /* else: we had sent one packet, but got no reply */
1533 log1s("no response to renew");
1534 if (lease_remaining > 30) {
1535 /* Some lease time remains, try to renew later */
1536 change_listen_mode(LISTEN_NONE);
1537 goto BOUND_for_half_lease;
1536 } 1538 }
1537//TODO: if 3 renew's failed (no reply) but remaining lease is large, 1539 /* Enter rebinding state */
1538//it might make sense to make a large pause (~1 hour?) and try later?
1539 /* Timed out or error, enter rebinding state */
1540 log1s("entering rebinding state");
1541 client_data.state = REBINDING; 1540 client_data.state = REBINDING;
1542 /* fall right through */ 1541 log1s("entering rebinding state");
1543 case REBINDING:
1544 /* Switch to bcast receive */ 1542 /* Switch to bcast receive */
1545 change_listen_mode(LISTEN_RAW); 1543 change_listen_mode(LISTEN_RAW);
1544 packet_num = 0;
1545 /* fall right through */
1546 case REBINDING:
1546 /* Lease is *really* about to run out, 1547 /* Lease is *really* about to run out,
1547 * try to find DHCP server using broadcast */ 1548 * try to find DHCP server using broadcast */
1548 if (lease_remaining > 0) { 1549 if (lease_remaining > 0 && packet_num < 3) {
1549 /* send a broadcast renew request */ 1550 /* send a broadcast renew request */
1550 send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); 1551 send_renew(xid, 0 /*INADDR_ANY*/, requested_ip);
1551 timeout = discover_timeout; 1552 timeout = discover_timeout;
1553 packet_num++;
1552 continue; 1554 continue;
1553 } 1555 }
1554 /* Timed out, enter init state */ 1556 /* Timed out, enter init state */
1557 change_listen_mode(LISTEN_NONE);
1555 bb_simple_info_msg("lease lost, entering init state"); 1558 bb_simple_info_msg("lease lost, entering init state");
1556 udhcp_run_script(NULL, "deconfig"); 1559 d4_run_script_deconfig();
1557 client_data.state = INIT_SELECTING; 1560 client_data.state = INIT_SELECTING;
1558 client_data.first_secs = 0; /* make secs field count from 0 */ 1561 client_data.first_secs = 0; /* make secs field count from 0 */
1559 timeout = 0; 1562 timeout = 0;
@@ -1561,7 +1564,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1561 continue; 1564 continue;
1562 /* case RELEASED: */ 1565 /* case RELEASED: */
1563 } 1566 }
1564 /* yah, I know, *you* say it would never happen */ 1567 /* RELEASED state (when we got SIGUSR2) ends up here.
1568 * (wait for SIGUSR1 to re-init, or for TERM, etc)
1569 */
1565 timeout = INT_MAX; 1570 timeout = INT_MAX;
1566 continue; /* back to main loop */ 1571 continue; /* back to main loop */
1567 } /* if poll timed out */ 1572 } /* if poll timed out */
@@ -1571,33 +1576,42 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1571 /* Is it a signal? */ 1576 /* Is it a signal? */
1572 switch (udhcp_sp_read()) { 1577 switch (udhcp_sp_read()) {
1573 case SIGUSR1: 1578 case SIGUSR1:
1579 if (client_data.state <= REQUESTING)
1580 /* Initial negotiations in progress, do not disturb */
1581 break;
1582 if (client_data.state == REBINDING)
1583 /* Do not go back from rebind to renew state */
1584 break;
1585
1586 if (lease_remaining > 30) /* if renew fails, do not go back to BOUND */
1587 lease_remaining = 30;
1574 client_data.first_secs = 0; /* make secs field count from 0 */ 1588 client_data.first_secs = 0; /* make secs field count from 0 */
1575 bb_simple_info_msg("performing DHCP renew"); 1589 packet_num = 0;
1576 1590
1577 switch (client_data.state) { 1591 switch (client_data.state) {
1578 /* Try to renew/rebind */
1579 case BOUND: 1592 case BOUND:
1580 case RENEWING: 1593 case RENEWING:
1581 case REBINDING: 1594 /* Try to renew/rebind */
1582 change_listen_mode(LISTEN_KERNEL);
1583 client_data.state = RENEW_REQUESTED; 1595 client_data.state = RENEW_REQUESTED;
1584 goto case_RENEW_REQUESTED; 1596 goto got_SIGUSR1;
1585 1597
1586 /* Start things over */ 1598 case RENEW_REQUESTED:
1587 case RENEW_REQUESTED: /* two or more SIGUSR1 received */ 1599 /* Two SIGUSR1 received, start things over */
1588 udhcp_run_script(NULL, "deconfig"); 1600 change_listen_mode(LISTEN_NONE);
1589 /* case REQUESTING: break; */ 1601 d4_run_script_deconfig();
1590 /* case RELEASED: break; */ 1602
1591 /* case INIT_SELECTING: break; */ 1603 default:
1604 /* case RELEASED: */
1605 /* Wake from SIGUSR2-induced deconfigured state */
1606 change_listen_mode(LISTEN_NONE);
1592 } 1607 }
1593 change_listen_mode(LISTEN_RAW);
1594 client_data.state = INIT_SELECTING; 1608 client_data.state = INIT_SELECTING;
1595 packet_num = 0;
1596 /* Kill any timeouts, user wants this to hurry along */ 1609 /* Kill any timeouts, user wants this to hurry along */
1597 timeout = 0; 1610 timeout = 0;
1598 continue; 1611 continue;
1599 case SIGUSR2: 1612 case SIGUSR2:
1600 perform_release(server_addr, requested_ip); 1613 perform_release(server_addr, requested_ip);
1614 /* ^^^ switches to LISTEN_NONE */
1601 timeout = INT_MAX; 1615 timeout = INT_MAX;
1602 continue; 1616 continue;
1603 case SIGTERM: 1617 case SIGTERM:
@@ -1616,7 +1630,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1616 if (client_data.listen_mode == LISTEN_KERNEL) 1630 if (client_data.listen_mode == LISTEN_KERNEL)
1617 len = udhcp_recv_kernel_packet(&packet, client_data.sockfd); 1631 len = udhcp_recv_kernel_packet(&packet, client_data.sockfd);
1618 else 1632 else
1619 len = udhcp_recv_raw_packet(&packet, client_data.sockfd); 1633 len = d4_recv_raw_packet(&packet, client_data.sockfd);
1620 if (len == -1) { 1634 if (len == -1) {
1621 /* Error is severe, reopen socket */ 1635 /* Error is severe, reopen socket */
1622 bb_error_msg("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO); 1636 bb_error_msg("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO);
@@ -1640,13 +1654,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1640 || memcmp(packet.chaddr, client_data.client_mac, 6) != 0 1654 || memcmp(packet.chaddr, client_data.client_mac, 6) != 0
1641 ) { 1655 ) {
1642//FIXME: need to also check that last 10 bytes are zero 1656//FIXME: need to also check that last 10 bytes are zero
1643 log1("chaddr does not match%s", ", ignoring packet"); // log2? 1657 log1("chaddr does not match%s", ", ignoring packet");
1644 continue; 1658 continue;
1645 } 1659 }
1646 1660
1647 message = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); 1661 message = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
1648 if (message == NULL) { 1662 if (message == NULL) {
1649 bb_info_msg("no message type option%s", ", ignoring packet"); 1663 log1("no message type option%s", ", ignoring packet");
1650 continue; 1664 continue;
1651 } 1665 }
1652 1666
@@ -1654,6 +1668,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1654 case INIT_SELECTING: 1668 case INIT_SELECTING:
1655 /* Must be a DHCPOFFER */ 1669 /* Must be a DHCPOFFER */
1656 if (*message == DHCPOFFER) { 1670 if (*message == DHCPOFFER) {
1671 struct in_addr temp_addr;
1657 uint8_t *temp; 1672 uint8_t *temp;
1658 1673
1659/* What exactly is server's IP? There are several values. 1674/* What exactly is server's IP? There are several values.
@@ -1689,7 +1704,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1689 move_from_unaligned32(server_addr, temp); 1704 move_from_unaligned32(server_addr, temp);
1690 } 1705 }
1691 /*xid = packet.xid; - already is */ 1706 /*xid = packet.xid; - already is */
1692 requested_ip = packet.yiaddr; 1707 temp_addr.s_addr = requested_ip = packet.yiaddr;
1708 log1("received offer of %s", inet_ntoa(temp_addr));
1693 1709
1694 /* enter requesting state */ 1710 /* enter requesting state */
1695 client_data.state = REQUESTING; 1711 client_data.state = REQUESTING;
@@ -1707,14 +1723,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1707 char server_str[sizeof("255.255.255.255")]; 1723 char server_str[sizeof("255.255.255.255")];
1708 uint8_t *temp; 1724 uint8_t *temp;
1709 1725
1726 change_listen_mode(LISTEN_NONE);
1727
1710 temp_addr.s_addr = server_addr; 1728 temp_addr.s_addr = server_addr;
1711 strcpy(server_str, inet_ntoa(temp_addr)); 1729 strcpy(server_str, inet_ntoa(temp_addr));
1712 temp_addr.s_addr = packet.yiaddr; 1730 temp_addr.s_addr = packet.yiaddr;
1713 1731
1732 lease_remaining = 60 * 60;
1714 temp = udhcp_get_option32(&packet, DHCP_LEASE_TIME); 1733 temp = udhcp_get_option32(&packet, DHCP_LEASE_TIME);
1715 if (!temp) { 1734 if (temp) {
1716 lease_remaining = 60 * 60;
1717 } else {
1718 uint32_t lease; 1735 uint32_t lease;
1719 /* it IS unaligned sometimes, don't "optimize" */ 1736 /* it IS unaligned sometimes, don't "optimize" */
1720 move_from_unaligned32(lease, temp); 1737 move_from_unaligned32(lease, temp);
@@ -1758,8 +1775,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1758 send_decline(/*xid,*/ server_addr, packet.yiaddr); 1775 send_decline(/*xid,*/ server_addr, packet.yiaddr);
1759 1776
1760 if (client_data.state != REQUESTING) 1777 if (client_data.state != REQUESTING)
1761 udhcp_run_script(NULL, "deconfig"); 1778 d4_run_script_deconfig();
1762 change_listen_mode(LISTEN_RAW);
1763 client_data.state = INIT_SELECTING; 1779 client_data.state = INIT_SELECTING;
1764 client_data.first_secs = 0; /* make secs field count from 0 */ 1780 client_data.first_secs = 0; /* make secs field count from 0 */
1765 requested_ip = 0; 1781 requested_ip = 0;
@@ -1769,17 +1785,12 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1769 } 1785 }
1770 } 1786 }
1771#endif 1787#endif
1772
1773 /* enter bound state */ 1788 /* enter bound state */
1774 start = monotonic_sec(); 1789 start = monotonic_sec();
1775 udhcp_run_script(&packet, client_data.state == REQUESTING ? "bound" : "renew"); 1790 d4_run_script(&packet, client_data.state == REQUESTING ? "bound" : "renew");
1776 timeout = (unsigned)lease_remaining / 2; 1791 lease_remaining -= (unsigned)monotonic_sec() - start;
1777//TODO: why / 2? 1792 if (lease_remaining < 0)
1778 timeout -= (unsigned)monotonic_sec() - start; 1793 lease_remaining = 0;
1779 packet_num = 0;
1780
1781 client_data.state = BOUND;
1782 change_listen_mode(LISTEN_NONE);
1783 if (opt & OPT_q) { /* quit after lease */ 1794 if (opt & OPT_q) { /* quit after lease */
1784 goto ret0; 1795 goto ret0;
1785 } 1796 }
@@ -1792,9 +1803,12 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1792 opt = ((opt & ~OPT_b) | OPT_f); 1803 opt = ((opt & ~OPT_b) | OPT_f);
1793 } 1804 }
1794#endif 1805#endif
1806 BOUND_for_half_lease:
1807 timeout = (unsigned)lease_remaining / 2;
1808 client_data.state = BOUND;
1795 /* make future renew packets use different xid */ 1809 /* make future renew packets use different xid */
1796 /* xid = random_xid(); ...but why bother? */ 1810 /* xid = random_xid(); ...but why bother? */
1797 1811 packet_num = 0;
1798 continue; /* back to main loop */ 1812 continue; /* back to main loop */
1799 } 1813 }
1800 if (*message == DHCPNAK) { 1814 if (*message == DHCPNAK) {
@@ -1818,11 +1832,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1818 goto non_matching_svid; 1832 goto non_matching_svid;
1819 } 1833 }
1820 /* return to init state */ 1834 /* return to init state */
1835 change_listen_mode(LISTEN_NONE);
1821 bb_info_msg("received %s", "DHCP NAK"); 1836 bb_info_msg("received %s", "DHCP NAK");
1822 udhcp_run_script(&packet, "nak"); 1837 d4_run_script(&packet, "nak");
1823 if (client_data.state != REQUESTING) 1838 if (client_data.state != REQUESTING)
1824 udhcp_run_script(NULL, "deconfig"); 1839 d4_run_script_deconfig();
1825 change_listen_mode(LISTEN_RAW);
1826 sleep(3); /* avoid excessive network traffic */ 1840 sleep(3); /* avoid excessive network traffic */
1827 client_data.state = INIT_SELECTING; 1841 client_data.state = INIT_SELECTING;
1828 client_data.first_secs = 0; /* make secs field count from 0 */ 1842 client_data.first_secs = 0; /* make secs field count from 0 */