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 <versvikeivind@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Eivind Versvik 2019-08-24 17:23:48 +02:00 committed by Denys Vlasenko
parent ac78f2ac96
commit 22a6339627

View File

@ -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)