From 22a633962786a7bc97870ced913fc237143cfd68 Mon Sep 17 00:00:00 2001 From: Eivind Versvik Date: Sat, 24 Aug 2019 17:23:48 +0200 Subject: [PATCH] udhcpc6: support stateless DHCPv6 -l will send Information-Request to request configuration parameters function old new delta packed_usage 33114 33180 +66 send_d6_info_request - 62 +62 udhcpc6_main 2534 2593 +59 udhcpc6_longopts 199 211 +12 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/0 up/down: 199/0) Total: 199 bytes Signed-off-by: Eivind Versvik Signed-off-by: Denys Vlasenko --- networking/udhcp/d6_dhcpc.c | 81 ++++++++++++++++++++++++++++++++----- 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 9d8e17c51..a426b9933 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c @@ -123,6 +123,7 @@ static const char udhcpc6_longopts[] ALIGN1 = "request-option\0" Required_argument "O" "no-default-options\0" No_argument "o" "foreground\0" No_argument "f" + "stateless\0" No_argument "l" USE_FOR_MMU( "background\0" No_argument "b" ) @@ -147,9 +148,10 @@ enum { OPT_o = 1 << 12, OPT_x = 1 << 13, OPT_f = 1 << 14, - OPT_d = 1 << 15, + OPT_l = 1 << 15, + OPT_d = 1 << 16, /* The rest has variable bit positions, need to be clever */ - OPTBIT_d = 15, + OPTBIT_d = 16, USE_FOR_MMU( OPTBIT_b,) ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) IF_FEATURE_UDHCP_PORT( OPTBIT_P,) @@ -544,6 +546,46 @@ static int d6_mcast_from_client_data_ifindex(struct d6_packet *packet, uint8_t * ); } +/* RFC 3315 18.1.5. Creation and Transmission of Information-request Messages + * + * The client uses an Information-request message to obtain + * configuration information without having addresses assigned to it. + * + * The client sets the "msg-type" field to INFORMATION-REQUEST. The + * client generates a transaction ID and inserts this value in the + * "transaction-id" field. + * + * The client SHOULD include a Client Identifier option to identify + * itself to the server. If the client does not include a Client + * Identifier option, the server will not be able to return any client- + * specific options to the client, or the server may choose not to + * respond to the message at all. The client MUST include a Client + * Identifier option if the Information-Request message will be + * authenticated. + * + * The client MUST include an Option Request option (see section 22.7) + * to indicate the options the client is interested in receiving. The + * client MAY include options with data values as hints to the server + * about parameter values the client would like to have returned. + */ +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_d6_info_request(uint32_t xid) +{ + struct d6_packet packet; + uint8_t *opt_ptr; + + /* Fill in: msg type, client id */ + opt_ptr = init_d6_packet(&packet, D6_MSG_INFORMATION_REQUEST, xid); + + /* Add options: + * "param req" option according to -O, options specified with -x + */ + opt_ptr = add_d6_client_options(opt_ptr); + + bb_error_msg("sending %s", "info request"); + return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); +} + /* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP. * * RFC 3315 17.1.1. Creation of Solicit Messages @@ -1129,6 +1171,8 @@ static void client_background(void) //usage: "\n -o Don't request any options (unless -O is given)" //usage: "\n -r IPv6 Request this address ('no' to not request any IP)" //usage: "\n -d Request prefix" +//usage: "\n -l Send 'information request' instead of 'solicit'" +//usage: "\n (used for servers which do not assign IPv6 addresses)" //usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" //usage: "\n Examples of string, numeric, and hex byte opts:" //usage: "\n -x hostname:bbox - option 12" @@ -1181,7 +1225,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) /* Parse command line */ opt = getopt32long(argv, "^" /* O,x: list; -T,-t,-A take numeric param */ - "i:np:qRr:s:T:+t:+SA:+O:*ox:*fd" + "i:np:qRr:s:T:+t:+SA:+O:*ox:*fld" USE_FOR_MMU("b") ///IF_FEATURE_UDHCPC_ARPING("a") IF_FEATURE_UDHCP_PORT("P:") @@ -1198,15 +1242,20 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) ); requested_ipv6 = NULL; option_mask32 |= OPT_r; - if (opt & OPT_r) { + if (opt & OPT_l) { + /* for -l, do not require IPv6 assignment from server */ + option_mask32 &= ~OPT_r; + } else if (opt & OPT_r) { + /* explicit "-r ARG" given */ if (strcmp(str_r, "no") == 0) { - option_mask32 -= OPT_r; + option_mask32 &= ~OPT_r; } else { if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0) bb_error_msg_and_die("bad IPv6 address '%s'", str_r); requested_ipv6 = &ipv6_buf; } } + #if ENABLE_FEATURE_UDHCP_PORT if (opt & OPT_P) { CLIENT_PORT6 = xatou16(str_P); @@ -1353,7 +1402,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) if (packet_num == 0) xid = random_xid(); /* multicast */ - send_d6_discover(xid, requested_ipv6); + if (opt & OPT_l) + send_d6_info_request(xid); + else + send_d6_discover(xid, requested_ipv6); timeout = discover_timeout; packet_num++; continue; @@ -1418,7 +1470,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) * Anyway, it does recover by eventually failing through * into INIT_SELECTING state. */ - send_d6_renew(xid, &srv6_buf, requested_ipv6); + if (opt & OPT_l) + send_d6_info_request(xid); + else + send_d6_renew(xid, &srv6_buf, requested_ipv6); timeout >>= 1; continue; } @@ -1432,8 +1487,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) /* Lease is *really* about to run out, * try to find DHCP server using broadcast */ if (timeout > 0) { - /* send a broadcast renew request */ - send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); + if (opt & OPT_l) + send_d6_info_request(xid); + else /* send a broadcast renew request */ + send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); timeout >>= 1; continue; } @@ -1740,6 +1797,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) prefix_timeout = address_timeout; /* note: "int timeout" will not overflow even with 0xffffffff inputs here: */ timeout = (prefix_timeout < address_timeout ? prefix_timeout : address_timeout) / 2; + if (opt & OPT_l) { + /* TODO: request OPTION_INFORMATION_REFRESH_TIME (32) + * and use its value instead of the default 1 day. + */ + timeout = 24 * 60 * 60; + } /* paranoia: must not be too small */ /* timeout > 60 - ensures at least one unicast renew attempt */ if (timeout < 61) -- 2.25.1