diff options
Diffstat (limited to 'networking/udhcp/dhcpc.c')
-rw-r--r-- | networking/udhcp/dhcpc.c | 220 |
1 files changed, 170 insertions, 50 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 4d755e6b8..3d4c397ff 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -100,6 +100,7 @@ static const uint8_t len_of_option_as_string[] = { | |||
100 | [OPTION_IP ] = sizeof("255.255.255.255 "), | 100 | [OPTION_IP ] = sizeof("255.255.255.255 "), |
101 | [OPTION_IP_PAIR ] = sizeof("255.255.255.255 ") * 2, | 101 | [OPTION_IP_PAIR ] = sizeof("255.255.255.255 ") * 2, |
102 | [OPTION_STATIC_ROUTES ] = sizeof("255.255.255.255/32 255.255.255.255 "), | 102 | [OPTION_STATIC_ROUTES ] = sizeof("255.255.255.255/32 255.255.255.255 "), |
103 | [OPTION_6RD ] = sizeof("32 128 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 255.255.255.255 "), | ||
103 | [OPTION_STRING ] = 1, | 104 | [OPTION_STRING ] = 1, |
104 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 105 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
105 | [OPTION_DNS_STRING ] = 1, /* unused */ | 106 | [OPTION_DNS_STRING ] = 1, /* unused */ |
@@ -123,6 +124,24 @@ static int sprint_nip(char *dest, const char *pre, const uint8_t *ip) | |||
123 | return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); | 124 | return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); |
124 | } | 125 | } |
125 | 126 | ||
127 | static int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) | ||
128 | { | ||
129 | char hexstrbuf[16 * 2]; | ||
130 | bin2hex(hexstrbuf, (void*)ip, 16); | ||
131 | return sprintf(dest, /* "%s" */ | ||
132 | "%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s", | ||
133 | /* pre, */ | ||
134 | hexstrbuf + 0 * 4, | ||
135 | hexstrbuf + 1 * 4, | ||
136 | hexstrbuf + 2 * 4, | ||
137 | hexstrbuf + 3 * 4, | ||
138 | hexstrbuf + 4 * 4, | ||
139 | hexstrbuf + 5 * 4, | ||
140 | hexstrbuf + 6 * 4, | ||
141 | hexstrbuf + 7 * 4 | ||
142 | ); | ||
143 | } | ||
144 | |||
126 | /* really simple implementation, just count the bits */ | 145 | /* really simple implementation, just count the bits */ |
127 | static int mton(uint32_t mask) | 146 | static int mton(uint32_t mask) |
128 | { | 147 | { |
@@ -142,27 +161,25 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ | |||
142 | int len, type, optlen; | 161 | int len, type, optlen; |
143 | char *dest, *ret; | 162 | char *dest, *ret; |
144 | 163 | ||
145 | /* option points to OPT_DATA, need to go back and get OPT_LEN */ | 164 | /* option points to OPT_DATA, need to go back to get OPT_LEN */ |
146 | len = option[OPT_LEN - OPT_DATA]; | 165 | len = option[-OPT_DATA + OPT_LEN]; |
147 | 166 | ||
148 | type = optflag->flags & OPTION_TYPE_MASK; | 167 | type = optflag->flags & OPTION_TYPE_MASK; |
149 | optlen = dhcp_option_lengths[type]; | 168 | optlen = dhcp_option_lengths[type]; |
150 | upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen); | 169 | upper_length = len_of_option_as_string[type] |
170 | * ((unsigned)(len + optlen - 1) / (unsigned)optlen); | ||
151 | 171 | ||
152 | dest = ret = xmalloc(upper_length + strlen(opt_name) + 2); | 172 | dest = ret = xmalloc(upper_length + strlen(opt_name) + 2); |
153 | dest += sprintf(ret, "%s=", opt_name); | 173 | dest += sprintf(ret, "%s=", opt_name); |
154 | 174 | ||
155 | while (len >= optlen) { | 175 | while (len >= optlen) { |
156 | unsigned ip_ofs = 0; | ||
157 | |||
158 | switch (type) { | 176 | switch (type) { |
177 | case OPTION_IP: | ||
159 | case OPTION_IP_PAIR: | 178 | case OPTION_IP_PAIR: |
160 | dest += sprint_nip(dest, "", option); | 179 | dest += sprint_nip(dest, "", option); |
161 | *dest++ = '/'; | 180 | if (type == OPTION_IP) |
162 | ip_ofs = 4; | 181 | break; |
163 | /* fall through */ | 182 | dest += sprint_nip(dest, "/", option + 4); |
164 | case OPTION_IP: | ||
165 | dest += sprint_nip(dest, "", option + ip_ofs); | ||
166 | break; | 183 | break; |
167 | // case OPTION_BOOLEAN: | 184 | // case OPTION_BOOLEAN: |
168 | // dest += sprintf(dest, *option ? "yes" : "no"); | 185 | // dest += sprintf(dest, *option ? "yes" : "no"); |
@@ -184,10 +201,14 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ | |||
184 | dest += sprintf(dest, type == OPTION_U32 ? "%lu" : "%ld", (unsigned long) ntohl(val_u32)); | 201 | dest += sprintf(dest, type == OPTION_U32 ? "%lu" : "%ld", (unsigned long) ntohl(val_u32)); |
185 | break; | 202 | break; |
186 | } | 203 | } |
204 | /* Note: options which use 'return' instead of 'break' | ||
205 | * (for example, OPTION_STRING) skip the code which handles | ||
206 | * the case of list of options. | ||
207 | */ | ||
187 | case OPTION_STRING: | 208 | case OPTION_STRING: |
188 | memcpy(dest, option, len); | 209 | memcpy(dest, option, len); |
189 | dest[len] = '\0'; | 210 | dest[len] = '\0'; |
190 | return ret; /* Short circuit this case */ | 211 | return ret; |
191 | case OPTION_STATIC_ROUTES: { | 212 | case OPTION_STATIC_ROUTES: { |
192 | /* Option binary format: | 213 | /* Option binary format: |
193 | * mask [one byte, 0..32] | 214 | * mask [one byte, 0..32] |
@@ -232,6 +253,53 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ | |||
232 | 253 | ||
233 | return ret; | 254 | return ret; |
234 | } | 255 | } |
256 | case OPTION_6RD: | ||
257 | /* Option binary format (see RFC 5969): | ||
258 | * 0 1 2 3 | ||
259 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | ||
260 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
261 | * | OPTION_6RD | option-length | IPv4MaskLen | 6rdPrefixLen | | ||
262 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
263 | * | 6rdPrefix | | ||
264 | * ... (16 octets) ... | ||
265 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
266 | * ... 6rdBRIPv4Address(es) ... | ||
267 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ||
268 | * We convert it to a string | ||
269 | * "IPv4MaskLen 6rdPrefixLen 6rdPrefix 6rdBRIPv4Address..." | ||
270 | * | ||
271 | * Sanity check: ensure that our length is at least 22 bytes, that | ||
272 | * IPv4MaskLen <= 32, | ||
273 | * 6rdPrefixLen <= 128, | ||
274 | * 6rdPrefixLen + (32 - IPv4MaskLen) <= 128 | ||
275 | * (2nd condition need no check - it follows from 1st and 3rd). | ||
276 | * Else, return envvar with empty value ("optname=") | ||
277 | */ | ||
278 | if (len >= (1 + 1 + 16 + 4) | ||
279 | && option[0] <= 32 | ||
280 | && (option[1] + 32 - option[0]) <= 128 | ||
281 | ) { | ||
282 | /* IPv4MaskLen */ | ||
283 | dest += sprintf(dest, "%u ", *option++); | ||
284 | /* 6rdPrefixLen */ | ||
285 | dest += sprintf(dest, "%u ", *option++); | ||
286 | /* 6rdPrefix */ | ||
287 | dest += sprint_nip6(dest, /* "", */ option); | ||
288 | option += 16; | ||
289 | len -= 1 + 1 + 16 + 4; | ||
290 | /* "+ 4" above corresponds to the length of IPv4 addr | ||
291 | * we consume in the loop below */ | ||
292 | while (1) { | ||
293 | /* 6rdBRIPv4Address(es) */ | ||
294 | dest += sprint_nip(dest, " ", option); | ||
295 | option += 4; | ||
296 | len -= 4; /* do we have yet another 4+ bytes? */ | ||
297 | if (len < 0) | ||
298 | break; /* no */ | ||
299 | } | ||
300 | } | ||
301 | |||
302 | return ret; | ||
235 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 303 | #if ENABLE_FEATURE_UDHCP_RFC3397 |
236 | case OPTION_DNS_STRING: | 304 | case OPTION_DNS_STRING: |
237 | /* unpack option into dest; use ret for prefix (i.e., "optname=") */ | 305 | /* unpack option into dest; use ret for prefix (i.e., "optname=") */ |
@@ -271,16 +339,21 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ | |||
271 | return ret; | 339 | return ret; |
272 | #endif | 340 | #endif |
273 | } /* switch */ | 341 | } /* switch */ |
342 | |||
343 | /* If we are here, try to format any remaining data | ||
344 | * in the option as another, similarly-formatted option | ||
345 | */ | ||
274 | option += optlen; | 346 | option += optlen; |
275 | len -= optlen; | 347 | len -= optlen; |
276 | // TODO: it can be a list only if (optflag->flags & OPTION_LIST). | 348 | // TODO: it can be a list only if (optflag->flags & OPTION_LIST). |
277 | // Should we bail out/warn if we see multi-ip option which is | 349 | // Should we bail out/warn if we see multi-ip option which is |
278 | // not allowed to be such (for example, DHCP_BROADCAST)? - | 350 | // not allowed to be such (for example, DHCP_BROADCAST)? - |
279 | if (len <= 0 /* || !(optflag->flags & OPTION_LIST) */) | 351 | if (len < optlen /* || !(optflag->flags & OPTION_LIST) */) |
280 | break; | 352 | break; |
281 | *dest++ = ' '; | 353 | *dest++ = ' '; |
282 | *dest = '\0'; | 354 | *dest = '\0'; |
283 | } | 355 | } /* while */ |
356 | |||
284 | return ret; | 357 | return ret; |
285 | } | 358 | } |
286 | 359 | ||
@@ -320,7 +393,7 @@ static char **fill_envp(struct dhcp_packet *packet) | |||
320 | if (i == DHCP_OPTION_OVERLOAD) | 393 | if (i == DHCP_OPTION_OVERLOAD) |
321 | overload = *temp; | 394 | overload = *temp; |
322 | else if (i == DHCP_SUBNET) | 395 | else if (i == DHCP_SUBNET) |
323 | envc++; /* for mton */ | 396 | envc++; /* for $mask */ |
324 | envc++; | 397 | envc++; |
325 | /*if (i != DHCP_MESSAGE_TYPE)*/ | 398 | /*if (i != DHCP_MESSAGE_TYPE)*/ |
326 | FOUND_OPTS(i) |= BMASK(i); | 399 | FOUND_OPTS(i) |= BMASK(i); |
@@ -335,10 +408,42 @@ static char **fill_envp(struct dhcp_packet *packet) | |||
335 | if (!packet) | 408 | if (!packet) |
336 | return envp; | 409 | return envp; |
337 | 410 | ||
411 | /* Export BOOTP fields. Fields we don't (yet?) export: | ||
412 | * uint8_t op; // always BOOTREPLY | ||
413 | * uint8_t htype; // hardware address type. 1 = 10mb ethernet | ||
414 | * uint8_t hlen; // hardware address length | ||
415 | * uint8_t hops; // used by relay agents only | ||
416 | * uint32_t xid; | ||
417 | * uint16_t secs; // elapsed since client began acquisition/renewal | ||
418 | * uint16_t flags; // only one flag so far: bcast. Never set by server | ||
419 | * uint32_t ciaddr; // client IP (usually == yiaddr. can it be different | ||
420 | * // if during renew server wants to give us differn IP?) | ||
421 | * uint32_t gateway_nip; // relay agent IP address | ||
422 | * uint8_t chaddr[16]; // link-layer client hardware address (MAC) | ||
423 | * TODO: export gateway_nip as $giaddr? | ||
424 | */ | ||
425 | /* Most important one: yiaddr as $ip */ | ||
338 | *curr = xmalloc(sizeof("ip=255.255.255.255")); | 426 | *curr = xmalloc(sizeof("ip=255.255.255.255")); |
339 | sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr); | 427 | sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr); |
340 | putenv(*curr++); | 428 | putenv(*curr++); |
429 | if (packet->siaddr_nip) { | ||
430 | /* IP address of next server to use in bootstrap */ | ||
431 | *curr = xmalloc(sizeof("siaddr=255.255.255.255")); | ||
432 | sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); | ||
433 | putenv(*curr++); | ||
434 | } | ||
435 | if (!(overload & FILE_FIELD) && packet->file[0]) { | ||
436 | /* watch out for invalid packets */ | ||
437 | *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); | ||
438 | putenv(*curr++); | ||
439 | } | ||
440 | if (!(overload & SNAME_FIELD) && packet->sname[0]) { | ||
441 | /* watch out for invalid packets */ | ||
442 | *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); | ||
443 | putenv(*curr++); | ||
444 | } | ||
341 | 445 | ||
446 | /* Export known DHCP options */ | ||
342 | opt_name = dhcp_option_strings; | 447 | opt_name = dhcp_option_strings; |
343 | i = 0; | 448 | i = 0; |
344 | while (*opt_name) { | 449 | while (*opt_name) { |
@@ -355,29 +460,14 @@ static char **fill_envp(struct dhcp_packet *packet) | |||
355 | /* Subnet option: make things like "$ip/$mask" possible */ | 460 | /* Subnet option: make things like "$ip/$mask" possible */ |
356 | uint32_t subnet; | 461 | uint32_t subnet; |
357 | move_from_unaligned32(subnet, temp); | 462 | move_from_unaligned32(subnet, temp); |
358 | *curr = xasprintf("mask=%d", mton(subnet)); | 463 | *curr = xasprintf("mask=%u", mton(subnet)); |
359 | putenv(*curr++); | 464 | putenv(*curr++); |
360 | } | 465 | } |
361 | next: | 466 | next: |
362 | opt_name += strlen(opt_name) + 1; | 467 | opt_name += strlen(opt_name) + 1; |
363 | i++; | 468 | i++; |
364 | } | 469 | } |
365 | if (packet->siaddr_nip) { | 470 | /* Export unknown options */ |
366 | *curr = xmalloc(sizeof("siaddr=255.255.255.255")); | ||
367 | sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); | ||
368 | putenv(*curr++); | ||
369 | } | ||
370 | if (!(overload & FILE_FIELD) && packet->file[0]) { | ||
371 | /* watch out for invalid packets */ | ||
372 | *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); | ||
373 | putenv(*curr++); | ||
374 | } | ||
375 | if (!(overload & SNAME_FIELD) && packet->sname[0]) { | ||
376 | /* watch out for invalid packets */ | ||
377 | *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); | ||
378 | putenv(*curr++); | ||
379 | } | ||
380 | /* Handle unknown options */ | ||
381 | for (i = 0; i < 256;) { | 471 | for (i = 0; i < 256;) { |
382 | BITMAP bitmap = FOUND_OPTS(i); | 472 | BITMAP bitmap = FOUND_OPTS(i); |
383 | if (!bitmap) { | 473 | if (!bitmap) { |
@@ -394,11 +484,12 @@ static char **fill_envp(struct dhcp_packet *packet) | |||
394 | len = temp[-OPT_DATA + OPT_LEN]; | 484 | len = temp[-OPT_DATA + OPT_LEN]; |
395 | *curr = xmalloc(sizeof("optNNN=") + 1 + len*2); | 485 | *curr = xmalloc(sizeof("optNNN=") + 1 + len*2); |
396 | ofs = sprintf(*curr, "opt%u=", i); | 486 | ofs = sprintf(*curr, "opt%u=", i); |
397 | bin2hex(*curr + ofs, (void*) temp, len)[0] = '\0'; | 487 | *bin2hex(*curr + ofs, (void*) temp, len) = '\0'; |
398 | putenv(*curr++); | 488 | putenv(*curr++); |
399 | } | 489 | } |
400 | i++; | 490 | i++; |
401 | } | 491 | } |
492 | |||
402 | return envp; | 493 | return envp; |
403 | } | 494 | } |
404 | 495 | ||
@@ -726,7 +817,8 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | |||
726 | bytes = ntohs(packet.ip.tot_len); | 817 | bytes = ntohs(packet.ip.tot_len); |
727 | 818 | ||
728 | /* make sure its the right packet for us, and that it passes sanity checks */ | 819 | /* make sure its the right packet for us, and that it passes sanity checks */ |
729 | if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION | 820 | if (packet.ip.protocol != IPPROTO_UDP |
821 | || packet.ip.version != IPVERSION | ||
730 | || packet.ip.ihl != (sizeof(packet.ip) >> 2) | 822 | || packet.ip.ihl != (sizeof(packet.ip) >> 2) |
731 | || packet.udp.dest != htons(CLIENT_PORT) | 823 | || packet.udp.dest != htons(CLIENT_PORT) |
732 | /* || bytes > (int) sizeof(packet) - can't happen */ | 824 | /* || bytes > (int) sizeof(packet) - can't happen */ |
@@ -739,7 +831,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | |||
739 | /* verify IP checksum */ | 831 | /* verify IP checksum */ |
740 | check = packet.ip.check; | 832 | check = packet.ip.check; |
741 | packet.ip.check = 0; | 833 | packet.ip.check = 0; |
742 | if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) { | 834 | if (check != inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip))) { |
743 | log1("Bad IP header checksum, ignoring"); | 835 | log1("Bad IP header checksum, ignoring"); |
744 | return -2; | 836 | return -2; |
745 | } | 837 | } |
@@ -750,20 +842,22 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | |||
750 | packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ | 842 | packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ |
751 | check = packet.udp.check; | 843 | check = packet.udp.check; |
752 | packet.udp.check = 0; | 844 | packet.udp.check = 0; |
753 | if (check && check != udhcp_checksum(&packet, bytes)) { | 845 | if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { |
754 | log1("Packet with bad UDP checksum received, ignoring"); | 846 | log1("Packet with bad UDP checksum received, ignoring"); |
755 | return -2; | 847 | return -2; |
756 | } | 848 | } |
757 | 849 | ||
758 | memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp))); | 850 | if (packet.data.cookie != htonl(DHCP_MAGIC)) { |
759 | |||
760 | if (dhcp_pkt->cookie != htonl(DHCP_MAGIC)) { | ||
761 | bb_info_msg("Packet with bad magic, ignoring"); | 851 | bb_info_msg("Packet with bad magic, ignoring"); |
762 | return -2; | 852 | return -2; |
763 | } | 853 | } |
854 | |||
764 | log1("Got valid DHCP packet"); | 855 | log1("Got valid DHCP packet"); |
765 | udhcp_dump_packet(dhcp_pkt); | 856 | udhcp_dump_packet(&packet.data); |
766 | return bytes - (sizeof(packet.ip) + sizeof(packet.udp)); | 857 | |
858 | bytes -= sizeof(packet.ip) + sizeof(packet.udp); | ||
859 | memcpy(dhcp_pkt, &packet.data, bytes); | ||
860 | return bytes; | ||
767 | } | 861 | } |
768 | 862 | ||
769 | 863 | ||
@@ -1077,11 +1171,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1077 | 1171 | ||
1078 | /* Parse command line */ | 1172 | /* Parse command line */ |
1079 | /* O,x: list; -T,-t,-A take numeric param */ | 1173 | /* O,x: list; -T,-t,-A take numeric param */ |
1080 | opt_complementary = "O::x::T+:t+:A+" | 1174 | opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ; |
1081 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 | ||
1082 | ":vv" | ||
1083 | #endif | ||
1084 | ; | ||
1085 | IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) | 1175 | IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) |
1086 | opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB" | 1176 | opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB" |
1087 | USE_FOR_MMU("b") | 1177 | USE_FOR_MMU("b") |
@@ -1095,9 +1185,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1095 | , &list_O | 1185 | , &list_O |
1096 | , &list_x | 1186 | , &list_x |
1097 | IF_FEATURE_UDHCP_PORT(, &str_P) | 1187 | IF_FEATURE_UDHCP_PORT(, &str_P) |
1098 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 | 1188 | IF_UDHCP_VERBOSE(, &dhcp_verbose) |
1099 | , &dhcp_verbose | ||
1100 | #endif | ||
1101 | ); | 1189 | ); |
1102 | if (opt & (OPT_h|OPT_H)) | 1190 | if (opt & (OPT_h|OPT_H)) |
1103 | client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); | 1191 | client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); |
@@ -1361,9 +1449,23 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1361 | switch (udhcp_sp_read(&rfds)) { | 1449 | switch (udhcp_sp_read(&rfds)) { |
1362 | case SIGUSR1: | 1450 | case SIGUSR1: |
1363 | client_config.first_secs = 0; /* make secs field count from 0 */ | 1451 | client_config.first_secs = 0; /* make secs field count from 0 */ |
1452 | already_waited_sec = 0; | ||
1364 | perform_renew(); | 1453 | perform_renew(); |
1365 | if (state == RENEW_REQUESTED) | 1454 | if (state == RENEW_REQUESTED) { |
1455 | /* We might be either on the same network | ||
1456 | * (in which case renew might work), | ||
1457 | * or we might be on a completely different one | ||
1458 | * (in which case renew won't ever succeed). | ||
1459 | * For the second case, must make sure timeout | ||
1460 | * is not too big, or else we can send | ||
1461 | * futile renew requests for hours. | ||
1462 | * (Ab)use -A TIMEOUT value (usually 20 sec) | ||
1463 | * as a cap on the timeout. | ||
1464 | */ | ||
1465 | if (timeout > tryagain_timeout) | ||
1466 | timeout = tryagain_timeout; | ||
1366 | goto case_RENEW_REQUESTED; | 1467 | goto case_RENEW_REQUESTED; |
1468 | } | ||
1367 | /* Start things over */ | 1469 | /* Start things over */ |
1368 | packet_num = 0; | 1470 | packet_num = 0; |
1369 | /* Kill any timeouts, user wants this to hurry along */ | 1471 | /* Kill any timeouts, user wants this to hurry along */ |
@@ -1431,7 +1533,25 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1431 | case INIT_SELECTING: | 1533 | case INIT_SELECTING: |
1432 | /* Must be a DHCPOFFER to one of our xid's */ | 1534 | /* Must be a DHCPOFFER to one of our xid's */ |
1433 | if (*message == DHCPOFFER) { | 1535 | if (*message == DHCPOFFER) { |
1434 | /* TODO: why we don't just fetch server's IP from IP header? */ | 1536 | /* What exactly is server's IP? There are several values. |
1537 | * Example DHCP offer captured with tchdump: | ||
1538 | * | ||
1539 | * 10.34.25.254:67 > 10.34.25.202:68 // IP header's src | ||
1540 | * BOOTP fields: | ||
1541 | * Your-IP 10.34.25.202 | ||
1542 | * Server-IP 10.34.32.125 // "next server" IP | ||
1543 | * Gateway-IP 10.34.25.254 // relay's address (if DHCP relays are in use) | ||
1544 | * DHCP options: | ||
1545 | * DHCP-Message Option 53, length 1: Offer | ||
1546 | * Server-ID Option 54, length 4: 10.34.255.7 // "server ID" | ||
1547 | * Default-Gateway Option 3, length 4: 10.34.25.254 // router | ||
1548 | * | ||
1549 | * We think that real server IP (one to use in renew/release) | ||
1550 | * is one in Server-ID option. But I am not 100% sure. | ||
1551 | * IP header's src and Gateway-IP (same in this example) | ||
1552 | * might work too. | ||
1553 | * "Next server" and router are definitely wrong ones to use, though... | ||
1554 | */ | ||
1435 | temp = udhcp_get_option(&packet, DHCP_SERVER_ID); | 1555 | temp = udhcp_get_option(&packet, DHCP_SERVER_ID); |
1436 | if (!temp) { | 1556 | if (!temp) { |
1437 | bb_error_msg("no server ID, ignoring packet"); | 1557 | bb_error_msg("no server ID, ignoring packet"); |