aboutsummaryrefslogtreecommitdiff
path: root/networking/udhcp/d6_dhcpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'networking/udhcp/d6_dhcpc.c')
-rw-r--r--networking/udhcp/d6_dhcpc.c128
1 files changed, 101 insertions, 27 deletions
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 64339c9b5..18a104c61 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -54,7 +54,9 @@ static const char udhcpc6_longopts[] ALIGN1 =
54 "request-option\0" Required_argument "O" 54 "request-option\0" Required_argument "O"
55 "no-default-options\0" No_argument "o" 55 "no-default-options\0" No_argument "o"
56 "foreground\0" No_argument "f" 56 "foreground\0" No_argument "f"
57 USE_FOR_MMU(
57 "background\0" No_argument "b" 58 "background\0" No_argument "b"
59 )
58/// IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a") 60/// IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a")
59 IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P") 61 IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P")
60 ; 62 ;
@@ -86,6 +88,19 @@ enum {
86 IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) 88 IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,)
87}; 89};
88 90
91static const char opt_req[] = {
92 (D6_OPT_ORO >> 8), (D6_OPT_ORO & 0xff),
93 0, 6,
94 (D6_OPT_DNS_SERVERS >> 8), (D6_OPT_DNS_SERVERS & 0xff),
95 (D6_OPT_DOMAIN_LIST >> 8), (D6_OPT_DOMAIN_LIST & 0xff),
96 (D6_OPT_CLIENT_FQDN >> 8), (D6_OPT_CLIENT_FQDN & 0xff)
97};
98
99static const char opt_fqdn_req[] = {
100 (D6_OPT_CLIENT_FQDN >> 8), (D6_OPT_CLIENT_FQDN & 0xff),
101 0, 2,
102 0, 0
103};
89 104
90/*** Utility functions ***/ 105/*** Utility functions ***/
91 106
@@ -107,8 +122,8 @@ static void *d6_find_option(uint8_t *option, uint8_t *option_end, unsigned code)
107 /* Does its code match? */ 122 /* Does its code match? */
108 if (option[1] == code) 123 if (option[1] == code)
109 return option; /* yes! */ 124 return option; /* yes! */
110 option += option[3] + 4;
111 len_m4 -= option[3] + 4; 125 len_m4 -= option[3] + 4;
126 option += option[3] + 4;
112 } 127 }
113 return NULL; 128 return NULL;
114} 129}
@@ -139,8 +154,10 @@ static char** new_env(void)
139/* put all the parameters into the environment */ 154/* put all the parameters into the environment */
140static void option_to_env(uint8_t *option, uint8_t *option_end) 155static void option_to_env(uint8_t *option, uint8_t *option_end)
141{ 156{
157 char *dlist, *ptr;
142 /* "length minus 4" */ 158 /* "length minus 4" */
143 int len_m4 = option_end - option - 4; 159 int len_m4 = option_end - option - 4;
160 int olen, ooff;
144 while (len_m4 >= 0) { 161 while (len_m4 >= 0) {
145 uint32_t v32; 162 uint32_t v32;
146 char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]; 163 char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")];
@@ -217,9 +234,54 @@ static void option_to_env(uint8_t *option, uint8_t *option_end)
217 234
218 sprint_nip6(ipv6str, option + 4 + 4 + 1); 235 sprint_nip6(ipv6str, option + 4 + 4 + 1);
219 *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4])); 236 *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4]));
237 break;
238 case D6_OPT_DNS_SERVERS:
239 olen = ((option[2] << 8) | option[3]) / 16;
240 dlist = ptr = malloc (4 + olen * 40 - 1);
241
242 memcpy (ptr, "dns=", 4);
243 ptr += 4;
244 ooff = 0;
245
246 while (olen--) {
247 sprint_nip6(ptr, option + 4 + ooff);
248 ptr += 39;
249 ooff += 16;
250 if (olen)
251 *ptr++ = ' ';
252 }
253
254 *new_env() = dlist;
255
256 break;
257 case D6_OPT_DOMAIN_LIST:
258 dlist = dname_dec(option + 4, (option[2] << 8) | option[3], "search=");
259 if (!dlist)
260 break;
261 *new_env() = dlist;
262 break;
263 case D6_OPT_CLIENT_FQDN:
264 // Work around broken ISC DHCPD6
265 if (option[4] & 0xf8) {
266 olen = ((option[2] << 8) | option[3]);
267 dlist = xmalloc(olen);
268//fixme:
269//- explain
270//- add len error check
271//- merge two allocs into one
272 memcpy(dlist, option + 4, olen);
273 *new_env() = xasprintf("fqdn=%s", dlist);
274 free(dlist);
275 break;
276 }
277 dlist = dname_dec(option + 5, ((option[2] << 8) | option[3]) - 1, "fqdn=");
278 if (!dlist)
279 break;
280 *new_env() = dlist;
281 break;
220 } 282 }
221 option += 4 + option[3];
222 len_m4 -= 4 + option[3]; 283 len_m4 -= 4 + option[3];
284 option += 4 + option[3];
223 } 285 }
224} 286}
225 287
@@ -311,7 +373,7 @@ static int d6_mcast_from_client_config_ifindex(struct d6_packet *packet, uint8_t
311 373
312 return d6_send_raw_packet( 374 return d6_send_raw_packet(
313 packet, (end - (uint8_t*) packet), 375 packet, (end - (uint8_t*) packet),
314 /*src*/ NULL, CLIENT_PORT6, 376 /*src*/ &client6_data.ll_ip6, CLIENT_PORT6,
315 /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_BCAST_ADDR, 377 /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_BCAST_ADDR,
316 client_config.ifindex 378 client_config.ifindex
317 ); 379 );
@@ -423,6 +485,10 @@ static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ip
423 } 485 }
424 opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, len); 486 opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, len);
425 487
488 /* Request additional options */
489 opt_ptr = d6_store_blob(opt_ptr, &opt_req, sizeof(opt_req));
490 opt_ptr = d6_store_blob(opt_ptr, &opt_fqdn_req, sizeof(opt_fqdn_req));
491
426 /* Add options: 492 /* Add options:
427 * "param req" option according to -O, options specified with -x 493 * "param req" option according to -O, options specified with -x
428 */ 494 */
@@ -476,6 +542,10 @@ static NOINLINE int send_d6_select(uint32_t xid)
476 /* IA NA (contains requested IP) */ 542 /* IA NA (contains requested IP) */
477 opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); 543 opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2);
478 544
545 /* Request additional options */
546 opt_ptr = d6_store_blob(opt_ptr, &opt_req, sizeof(opt_req));
547 opt_ptr = d6_store_blob(opt_ptr, &opt_fqdn_req, sizeof(opt_fqdn_req));
548
479 /* Add options: 549 /* Add options:
480 * "param req" option according to -O, options specified with -x 550 * "param req" option according to -O, options specified with -x
481 */ 551 */
@@ -555,7 +625,8 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st
555 return d6_send_kernel_packet( 625 return d6_send_kernel_packet(
556 &packet, (opt_ptr - (uint8_t*) &packet), 626 &packet, (opt_ptr - (uint8_t*) &packet),
557 our_cur_ipv6, CLIENT_PORT6, 627 our_cur_ipv6, CLIENT_PORT6,
558 server_ipv6, SERVER_PORT6 628 server_ipv6, SERVER_PORT6,
629 client_config.ifindex
559 ); 630 );
560 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); 631 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr);
561} 632}
@@ -577,15 +648,14 @@ static int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cu
577 return d6_send_kernel_packet( 648 return d6_send_kernel_packet(
578 &packet, (opt_ptr - (uint8_t*) &packet), 649 &packet, (opt_ptr - (uint8_t*) &packet),
579 our_cur_ipv6, CLIENT_PORT6, 650 our_cur_ipv6, CLIENT_PORT6,
580 server_ipv6, SERVER_PORT6 651 server_ipv6, SERVER_PORT6,
652 client_config.ifindex
581 ); 653 );
582} 654}
583 655
584/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ 656/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
585/* NOINLINE: limit stack usage in caller */ 657/* NOINLINE: limit stack usage in caller */
586static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6 658static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6, struct d6_packet *d6_pkt, int fd)
587 UNUSED_PARAM
588 , struct d6_packet *d6_pkt, int fd)
589{ 659{
590 int bytes; 660 int bytes;
591 struct ip6_udp_d6_packet packet; 661 struct ip6_udp_d6_packet packet;
@@ -634,6 +704,9 @@ static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6
634// return -2; 704// return -2;
635// } 705// }
636 706
707 if (peer_ipv6)
708 *peer_ipv6 = packet.ip6.ip6_src; /* struct copy */
709
637 log1("received %s", "a packet"); 710 log1("received %s", "a packet");
638 d6_dump_packet(&packet.data); 711 d6_dump_packet(&packet.data);
639 712
@@ -935,9 +1008,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
935 int timeout; /* must be signed */ 1008 int timeout; /* must be signed */
936 unsigned already_waited_sec; 1009 unsigned already_waited_sec;
937 unsigned opt; 1010 unsigned opt;
938 int max_fd;
939 int retval; 1011 int retval;
940 fd_set rfds;
941 1012
942 setup_common_bufsiz(); 1013 setup_common_bufsiz();
943 1014
@@ -1003,11 +1074,13 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1003 /* now it looks similar to udhcpd's config file line: 1074 /* now it looks similar to udhcpd's config file line:
1004 * "optname optval", using the common routine: */ 1075 * "optname optval", using the common routine: */
1005 udhcp_str2optset(optstr, &client_config.options); 1076 udhcp_str2optset(optstr, &client_config.options);
1077 if (colon)
1078 *colon = ':'; /* restore it for NOMMU reexec */
1006 } 1079 }
1007 1080
1008 if (udhcp_read_interface(client_config.interface, 1081 if (d6_read_interface(client_config.interface,
1009 &client_config.ifindex, 1082 &client_config.ifindex,
1010 NULL, 1083 &client6_data.ll_ip6,
1011 client_config.client_mac) 1084 client_config.client_mac)
1012 ) { 1085 ) {
1013 return 1; 1086 return 1;
@@ -1063,7 +1136,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1063 * "continue" statements in code below jump to the top of the loop. 1136 * "continue" statements in code below jump to the top of the loop.
1064 */ 1137 */
1065 for (;;) { 1138 for (;;) {
1066 struct timeval tv; 1139 int tv;
1140 struct pollfd pfds[2];
1067 struct d6_packet packet; 1141 struct d6_packet packet;
1068 uint8_t *packet_end; 1142 uint8_t *packet_end;
1069 /* silence "uninitialized!" warning */ 1143 /* silence "uninitialized!" warning */
@@ -1078,16 +1152,15 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1078 * to change_listen_mode(). Thus we open listen socket 1152 * to change_listen_mode(). Thus we open listen socket
1079 * BEFORE we send renew request (see "case BOUND:"). */ 1153 * BEFORE we send renew request (see "case BOUND:"). */
1080 1154
1081 max_fd = udhcp_sp_fd_set(&rfds, sockfd); 1155 udhcp_sp_fd_set(pfds, sockfd);
1082 1156
1083 tv.tv_sec = timeout - already_waited_sec; 1157 tv = timeout - already_waited_sec;
1084 tv.tv_usec = 0;
1085 retval = 0; 1158 retval = 0;
1086 /* If we already timed out, fall through with retval = 0, else... */ 1159 /* If we already timed out, fall through with retval = 0, else... */
1087 if ((int)tv.tv_sec > 0) { 1160 if (tv > 0) {
1088 log1("waiting on select %u seconds", (int)tv.tv_sec); 1161 log1("waiting on select %u seconds", tv);
1089 timestamp_before_wait = (unsigned)monotonic_sec(); 1162 timestamp_before_wait = (unsigned)monotonic_sec();
1090 retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); 1163 retval = poll(pfds, 2, tv < INT_MAX/1000 ? tv * 1000 : INT_MAX);
1091 if (retval < 0) { 1164 if (retval < 0) {
1092 /* EINTR? A signal was caught, don't panic */ 1165 /* EINTR? A signal was caught, don't panic */
1093 if (errno == EINTR) { 1166 if (errno == EINTR) {
@@ -1108,13 +1181,14 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1108 * or if the status of the bridge changed). 1181 * or if the status of the bridge changed).
1109 * Refresh ifindex and client_mac: 1182 * Refresh ifindex and client_mac:
1110 */ 1183 */
1111 if (udhcp_read_interface(client_config.interface, 1184 if (d6_read_interface(client_config.interface,
1112 &client_config.ifindex, 1185 &client_config.ifindex,
1113 NULL, 1186 &client6_data.ll_ip6,
1114 client_config.client_mac) 1187 client_config.client_mac)
1115 ) { 1188 ) {
1116 goto ret0; /* iface is gone? */ 1189 goto ret0; /* iface is gone? */
1117 } 1190 }
1191
1118 memcpy(clientid_mac_ptr, client_config.client_mac, 6); 1192 memcpy(clientid_mac_ptr, client_config.client_mac, 6);
1119 1193
1120 /* We will restart the wait in any case */ 1194 /* We will restart the wait in any case */
@@ -1222,8 +1296,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1222 /* select() didn't timeout, something happened */ 1296 /* select() didn't timeout, something happened */
1223 1297
1224 /* Is it a signal? */ 1298 /* Is it a signal? */
1225 /* note: udhcp_sp_read checks FD_ISSET before reading */ 1299 /* note: udhcp_sp_read checks poll result before reading */
1226 switch (udhcp_sp_read(&rfds)) { 1300 switch (udhcp_sp_read(pfds)) {
1227 case SIGUSR1: 1301 case SIGUSR1:
1228 client_config.first_secs = 0; /* make secs field count from 0 */ 1302 client_config.first_secs = 0; /* make secs field count from 0 */
1229 already_waited_sec = 0; 1303 already_waited_sec = 0;
@@ -1258,7 +1332,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1258 } 1332 }
1259 1333
1260 /* Is it a packet? */ 1334 /* Is it a packet? */
1261 if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds)) 1335 if (listen_mode == LISTEN_NONE || !pfds[1].revents)
1262 continue; /* no */ 1336 continue; /* no */
1263 1337
1264 { 1338 {
@@ -1307,7 +1381,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1307 struct d6_option *option, *iaaddr; 1381 struct d6_option *option, *iaaddr;
1308 type_is_ok: 1382 type_is_ok:
1309 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); 1383 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
1310 if (option && option->data[4] != 0) { 1384 if (option && (option->data[0] | option->data[1]) != 0) {
1311 /* return to init state */ 1385 /* return to init state */
1312 bb_error_msg("received DHCP NAK (%u)", option->data[4]); 1386 bb_error_msg("received DHCP NAK (%u)", option->data[4]);
1313 d6_run_script(&packet, "nak"); 1387 d6_run_script(&packet, "nak");
@@ -1460,8 +1534,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1460 if (lease_seconds < 0x10) 1534 if (lease_seconds < 0x10)
1461 lease_seconds = 0x10; 1535 lease_seconds = 0x10;
1462/// TODO: check for 0 lease time? 1536/// TODO: check for 0 lease time?
1463 if (lease_seconds >= 0x10000000) 1537 if (lease_seconds > 0x7fffffff / 1000)
1464 lease_seconds = 0x0fffffff; 1538 lease_seconds = 0x7fffffff / 1000;
1465 /* enter bound state */ 1539 /* enter bound state */
1466 timeout = lease_seconds / 2; 1540 timeout = lease_seconds / 2;
1467 bb_error_msg("lease obtained, lease time %u", 1541 bb_error_msg("lease obtained, lease time %u",