aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--networking/udhcp/dhcpc.c108
1 files changed, 90 insertions, 18 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 9713e817e..f685a1d22 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -346,31 +346,34 @@ static ALWAYS_INLINE uint32_t random_xid(void)
346/* Initialize the packet with the proper defaults */ 346/* Initialize the packet with the proper defaults */
347static void init_packet(struct dhcp_packet *packet, char type) 347static void init_packet(struct dhcp_packet *packet, char type)
348{ 348{
349 /* Fill in: op, htype, hlen, cookie fields; message type option: */
349 udhcp_init_header(packet, type); 350 udhcp_init_header(packet, type);
351
352 packet->xid = random_xid();
353
350 memcpy(packet->chaddr, client_config.client_mac, 6); 354 memcpy(packet->chaddr, client_config.client_mac, 6);
351 if (client_config.clientid) 355 if (client_config.clientid)
352 udhcp_add_binary_option(packet, client_config.clientid); 356 udhcp_add_binary_option(packet, client_config.clientid);
357}
358
359static void add_client_options(struct dhcp_packet *packet)
360{
361 uint8_t c;
362 int i, end, len;
363
364 udhcp_add_simple_option(packet, DHCP_MAX_SIZE, htons(IP_UDP_DHCP_SIZE));
353 if (client_config.hostname) 365 if (client_config.hostname)
354 udhcp_add_binary_option(packet, client_config.hostname); 366 udhcp_add_binary_option(packet, client_config.hostname);
355 if (client_config.fqdn) 367 if (client_config.fqdn)
356 udhcp_add_binary_option(packet, client_config.fqdn); 368 udhcp_add_binary_option(packet, client_config.fqdn);
357 if (type != DHCPDECLINE 369 if (client_config.vendorclass)
358 && type != DHCPRELEASE
359 && client_config.vendorclass
360 ) {
361 udhcp_add_binary_option(packet, client_config.vendorclass); 370 udhcp_add_binary_option(packet, client_config.vendorclass);
362 }
363}
364 371
365static void add_client_options(struct dhcp_packet *packet)
366{
367 /* Add a "param req" option with the list of options we'd like to have 372 /* Add a "param req" option with the list of options we'd like to have
368 * from stubborn DHCP servers. Pull the data from the struct in common.c. 373 * from stubborn DHCP servers. Pull the data from the struct in common.c.
369 * No bounds checking because it goes towards the head of the packet. */ 374 * No bounds checking because it goes towards the head of the packet. */
370 uint8_t c; 375 end = udhcp_end_option(packet->options);
371 int end = udhcp_end_option(packet->options); 376 len = 0;
372 int i, len = 0;
373
374 for (i = 0; (c = dhcp_optflags[i].code) != 0; i++) { 377 for (i = 0; (c = dhcp_optflags[i].code) != 0; i++) {
375 if (( (dhcp_optflags[i].flags & OPTION_REQ) 378 if (( (dhcp_optflags[i].flags & OPTION_REQ)
376 && !client_config.no_default_options 379 && !client_config.no_default_options
@@ -432,13 +435,20 @@ static int send_discover(uint32_t xid, uint32_t requested)
432{ 435{
433 struct dhcp_packet packet; 436 struct dhcp_packet packet;
434 437
438 /* Fill in: op, htype, hlen, cookie, chaddr fields,
439 * random xid field (we override it below),
440 * client-id option (unless -C), message type option:
441 */
435 init_packet(&packet, DHCPDISCOVER); 442 init_packet(&packet, DHCPDISCOVER);
443
436 packet.xid = xid; 444 packet.xid = xid;
437 if (requested) 445 if (requested)
438 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); 446 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
439 /* Explicitly saying that we want RFC-compliant packets helps 447
440 * some buggy DHCP servers to NOT send bigger packets */ 448 /* Add options: maxsize,
441 udhcp_add_simple_option(&packet, DHCP_MAX_SIZE, htons(576)); 449 * optionally: hostname, fqdn, vendorclass,
450 * "param req" option according to -O, options specified with -x
451 */
442 add_client_options(&packet); 452 add_client_options(&packet);
443 453
444 bb_info_msg("Sending discover..."); 454 bb_info_msg("Sending discover...");
@@ -454,10 +464,33 @@ static int send_select(uint32_t xid, uint32_t server, uint32_t requested)
454 struct dhcp_packet packet; 464 struct dhcp_packet packet;
455 struct in_addr addr; 465 struct in_addr addr;
456 466
467/*
468 * RFC 2131 4.3.2 DHCPREQUEST message
469 * ...
470 * If the DHCPREQUEST message contains a 'server identifier'
471 * option, the message is in response to a DHCPOFFER message.
472 * Otherwise, the message is a request to verify or extend an
473 * existing lease. If the client uses a 'client identifier'
474 * in a DHCPREQUEST message, it MUST use that same 'client identifier'
475 * in all subsequent messages. If the client included a list
476 * of requested parameters in a DHCPDISCOVER message, it MUST
477 * include that list in all subsequent messages.
478 */
479 /* Fill in: op, htype, hlen, cookie, chaddr fields,
480 * random xid field (we override it below),
481 * client-id option (unless -C), message type option:
482 */
457 init_packet(&packet, DHCPREQUEST); 483 init_packet(&packet, DHCPREQUEST);
484
458 packet.xid = xid; 485 packet.xid = xid;
459 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); 486 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
487
460 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 488 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
489
490 /* Add options: maxsize,
491 * optionally: hostname, fqdn, vendorclass,
492 * "param req" option according to -O, and options specified with -x
493 */
461 add_client_options(&packet); 494 add_client_options(&packet);
462 495
463 addr.s_addr = requested; 496 addr.s_addr = requested;
@@ -470,9 +503,33 @@ static int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
470{ 503{
471 struct dhcp_packet packet; 504 struct dhcp_packet packet;
472 505
506/*
507 * RFC 2131 4.3.2 DHCPREQUEST message
508 * ...
509 * DHCPREQUEST generated during RENEWING state:
510 *
511 * 'server identifier' MUST NOT be filled in, 'requested IP address'
512 * option MUST NOT be filled in, 'ciaddr' MUST be filled in with
513 * client's IP address. In this situation, the client is completely
514 * configured, and is trying to extend its lease. This message will
515 * be unicast, so no relay agents will be involved in its
516 * transmission. Because 'giaddr' is therefore not filled in, the
517 * DHCP server will trust the value in 'ciaddr', and use it when
518 * replying to the client.
519 */
520 /* Fill in: op, htype, hlen, cookie, chaddr fields,
521 * random xid field (we override it below),
522 * client-id option (unless -C), message type option:
523 */
473 init_packet(&packet, DHCPREQUEST); 524 init_packet(&packet, DHCPREQUEST);
525
474 packet.xid = xid; 526 packet.xid = xid;
475 packet.ciaddr = ciaddr; 527 packet.ciaddr = ciaddr;
528
529 /* Add options: maxsize,
530 * optionally: hostname, fqdn, vendorclass,
531 * "param req" option according to -O, and options specified with -x
532 */
476 add_client_options(&packet); 533 add_client_options(&packet);
477 534
478 bb_info_msg("Sending renew..."); 535 bb_info_msg("Sending renew...");
@@ -489,9 +546,20 @@ static int send_decline(uint32_t xid, uint32_t server, uint32_t requested)
489{ 546{
490 struct dhcp_packet packet; 547 struct dhcp_packet packet;
491 548
549 /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields,
550 * client-id option (unless -C), message type option:
551 */
492 init_packet(&packet, DHCPDECLINE); 552 init_packet(&packet, DHCPDECLINE);
553
554 /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client,
555 * but in case the server is buggy and wants DHCPDECLINE's xid
556 * to match the xid which started entire handshake,
557 * we use the same xid we used in initial DHCPDISCOVER:
558 */
493 packet.xid = xid; 559 packet.xid = xid;
560 /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */
494 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); 561 udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
562
495 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 563 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
496 564
497 bb_info_msg("Sending decline..."); 565 bb_info_msg("Sending decline...");
@@ -504,8 +572,12 @@ static int send_release(uint32_t server, uint32_t ciaddr)
504{ 572{
505 struct dhcp_packet packet; 573 struct dhcp_packet packet;
506 574
575 /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields,
576 * client-id option (unless -C), message type option:
577 */
507 init_packet(&packet, DHCPRELEASE); 578 init_packet(&packet, DHCPRELEASE);
508 packet.xid = random_xid(); 579
580 /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */
509 packet.ciaddr = ciaddr; 581 packet.ciaddr = ciaddr;
510 582
511 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 583 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
@@ -1254,7 +1326,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1254 1326
1255 /* Ignore packets that aren't for us */ 1327 /* Ignore packets that aren't for us */
1256 if (packet.hlen != 6 1328 if (packet.hlen != 6
1257 || memcmp(packet.chaddr, client_config.client_mac, 6) 1329 || memcmp(packet.chaddr, client_config.client_mac, 6) != 0
1258 ) { 1330 ) {
1259//FIXME: need to also check that last 10 bytes are zero 1331//FIXME: need to also check that last 10 bytes are zero
1260 log1("chaddr does not match, ignoring packet"); // log2? 1332 log1("chaddr does not match, ignoring packet"); // log2?
@@ -1280,7 +1352,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1280 } 1352 }
1281 /* it IS unaligned sometimes, don't "optimize" */ 1353 /* it IS unaligned sometimes, don't "optimize" */
1282 move_from_unaligned32(server_addr, temp); 1354 move_from_unaligned32(server_addr, temp);
1283 xid = packet.xid; 1355 /*xid = packet.xid; - already is */
1284 requested_ip = packet.yiaddr; 1356 requested_ip = packet.yiaddr;
1285 1357
1286 /* enter requesting state */ 1358 /* enter requesting state */