aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--networking/udhcp/d6_dhcpc.c81
1 files 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)