diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-06-28 19:18:17 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-06-28 19:18:17 +0200 |
commit | ba4fbca8a81d765f81aefc74db7f73ec9ded3550 (patch) | |
tree | 3790acaa5ef3c682831aa15428beb313eea5dcb7 | |
parent | ae2b9f286c985394410aec19b12c1ebecfbe20f6 (diff) | |
download | busybox-w32-ba4fbca8a81d765f81aefc74db7f73ec9ded3550.tar.gz busybox-w32-ba4fbca8a81d765f81aefc74db7f73ec9ded3550.tar.bz2 busybox-w32-ba4fbca8a81d765f81aefc74db7f73ec9ded3550.zip |
udhcpc6: make -O OPT work
Patch is based on work by tiggerswelt.net.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/udhcp/common.c | 27 | ||||
-rw-r--r-- | networking/udhcp/common.h | 17 | ||||
-rw-r--r-- | networking/udhcp/d6_dhcpc.c | 150 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.c | 4 | ||||
-rw-r--r-- | networking/udhcp/dhcpc.h | 1 | ||||
-rw-r--r-- | networking/udhcp/dhcpd.c | 8 |
6 files changed, 149 insertions, 58 deletions
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 420695a20..d3eea5def 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c | |||
@@ -14,6 +14,7 @@ const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = { | |||
14 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | 14 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff |
15 | }; | 15 | }; |
16 | 16 | ||
17 | #if ENABLE_UDHCPC || ENABLE_UDHCPD | ||
17 | /* Supported options are easily added here. | 18 | /* Supported options are easily added here. |
18 | * See RFC2132 for more options. | 19 | * See RFC2132 for more options. |
19 | * OPTION_REQ: these options are requested by udhcpc (unless -o). | 20 | * OPTION_REQ: these options are requested by udhcpc (unless -o). |
@@ -136,6 +137,7 @@ const char dhcp_option_strings[] ALIGN1 = | |||
136 | "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */ | 137 | "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */ |
137 | "wpad" "\0" /* DHCP_WPAD */ | 138 | "wpad" "\0" /* DHCP_WPAD */ |
138 | ; | 139 | ; |
140 | #endif | ||
139 | 141 | ||
140 | /* Lengths of the option types in binary form. | 142 | /* Lengths of the option types in binary form. |
141 | * Used by: | 143 | * Used by: |
@@ -190,21 +192,26 @@ static void log_option(const char *pfx, const uint8_t *opt) | |||
190 | # define log_option(pfx, opt) ((void)0) | 192 | # define log_option(pfx, opt) ((void)0) |
191 | #endif | 193 | #endif |
192 | 194 | ||
193 | unsigned FAST_FUNC udhcp_option_idx(const char *name) | 195 | unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings) |
194 | { | 196 | { |
195 | int n = index_in_strings(dhcp_option_strings, name); | 197 | int n = index_in_strings(option_strings, name); |
196 | if (n >= 0) | 198 | if (n >= 0) |
197 | return n; | 199 | return n; |
198 | 200 | ||
199 | { | 201 | { |
200 | char buf[sizeof(dhcp_option_strings)]; | 202 | char *buf, *d; |
201 | char *d = buf; | 203 | const char *s; |
202 | const char *s = dhcp_option_strings; | 204 | |
203 | while (s < dhcp_option_strings + sizeof(dhcp_option_strings) - 2) { | 205 | s = option_strings; |
206 | while (*s) | ||
207 | s += strlen(s) + 1; | ||
208 | |||
209 | d = buf = xzalloc(s - option_strings); | ||
210 | s = option_strings; | ||
211 | while (!(*s == '\0' && s[1] == '\0')) { | ||
204 | *d++ = (*s == '\0' ? ' ' : *s); | 212 | *d++ = (*s == '\0' ? ' ' : *s); |
205 | s++; | 213 | s++; |
206 | } | 214 | } |
207 | *d = '\0'; | ||
208 | bb_error_msg_and_die("unknown option '%s', known options: %s", name, buf); | 215 | bb_error_msg_and_die("unknown option '%s', known options: %s", name, buf); |
209 | } | 216 | } |
210 | } | 217 | } |
@@ -315,6 +322,7 @@ void FAST_FUNC udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addo | |||
315 | optionptr[end + len] = DHCP_END; | 322 | optionptr[end + len] = DHCP_END; |
316 | } | 323 | } |
317 | 324 | ||
325 | #if ENABLE_UDHCPC || ENABLE_UDHCPD | ||
318 | /* Add an one to four byte option to a packet */ | 326 | /* Add an one to four byte option to a packet */ |
319 | void FAST_FUNC udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data) | 327 | void FAST_FUNC udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data) |
320 | { | 328 | { |
@@ -338,6 +346,7 @@ void FAST_FUNC udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, | |||
338 | 346 | ||
339 | bb_error_msg("can't add option 0x%02x", code); | 347 | bb_error_msg("can't add option 0x%02x", code); |
340 | } | 348 | } |
349 | #endif | ||
341 | 350 | ||
342 | /* Find option 'code' in opt_list */ | 351 | /* Find option 'code' in opt_list */ |
343 | struct option_set* FAST_FUNC udhcp_find_option(struct option_set *opt_list, uint8_t code) | 352 | struct option_set* FAST_FUNC udhcp_find_option(struct option_set *opt_list, uint8_t code) |
@@ -451,7 +460,7 @@ static NOINLINE void attach_option( | |||
451 | free(allocated); | 460 | free(allocated); |
452 | } | 461 | } |
453 | 462 | ||
454 | int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) | 463 | int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg, const struct dhcp_optflag *optflags, const char *option_strings) |
455 | { | 464 | { |
456 | struct option_set **opt_list = arg; | 465 | struct option_set **opt_list = arg; |
457 | char *opt, *val; | 466 | char *opt, *val; |
@@ -478,7 +487,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) | |||
478 | bin_optflag.code = optcode; | 487 | bin_optflag.code = optcode; |
479 | optflag = &bin_optflag; | 488 | optflag = &bin_optflag; |
480 | } else { | 489 | } else { |
481 | optflag = &dhcp_optflags[udhcp_option_idx(opt)]; | 490 | optflag = &optflags[udhcp_option_idx(opt, option_strings)]; |
482 | } | 491 | } |
483 | 492 | ||
484 | retval = 0; | 493 | retval = 0; |
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index ee12cf91b..6907e7f60 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h | |||
@@ -93,8 +93,10 @@ enum { | |||
93 | OPTION_BIN, | 93 | OPTION_BIN, |
94 | OPTION_STATIC_ROUTES, | 94 | OPTION_STATIC_ROUTES, |
95 | OPTION_6RD, | 95 | OPTION_6RD, |
96 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 96 | #if ENABLE_FEATURE_UDHCP_RFC3397 || ENABLE_FEATURE_UDHCPC6_RFC3646 || ENABLE_FEATURE_UDHCPC6_RFC4704 |
97 | OPTION_DNS_STRING, /* RFC1035 compressed domain name list */ | 97 | OPTION_DNS_STRING, /* RFC1035 compressed domain name list */ |
98 | #endif | ||
99 | #if ENABLE_FEATURE_UDHCP_RFC3397 | ||
98 | OPTION_SIP_SERVERS, | 100 | OPTION_SIP_SERVERS, |
99 | #endif | 101 | #endif |
100 | 102 | ||
@@ -189,17 +191,21 @@ struct option_set { | |||
189 | struct option_set *next; | 191 | struct option_set *next; |
190 | }; | 192 | }; |
191 | 193 | ||
194 | #if ENABLE_UDHCPC || ENABLE_UDHCPD | ||
192 | extern const struct dhcp_optflag dhcp_optflags[]; | 195 | extern const struct dhcp_optflag dhcp_optflags[]; |
193 | extern const char dhcp_option_strings[] ALIGN1; | 196 | extern const char dhcp_option_strings[] ALIGN1; |
197 | #endif | ||
194 | extern const uint8_t dhcp_option_lengths[] ALIGN1; | 198 | extern const uint8_t dhcp_option_lengths[] ALIGN1; |
195 | 199 | ||
196 | unsigned FAST_FUNC udhcp_option_idx(const char *name); | 200 | unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings); |
197 | 201 | ||
198 | uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC; | 202 | uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC; |
199 | int udhcp_end_option(uint8_t *optionptr) FAST_FUNC; | 203 | int udhcp_end_option(uint8_t *optionptr) FAST_FUNC; |
200 | void udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt) FAST_FUNC; | 204 | void udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt) FAST_FUNC; |
205 | #if ENABLE_UDHCPC || ENABLE_UDHCPD | ||
201 | void udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data) FAST_FUNC; | 206 | void udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data) FAST_FUNC; |
202 | #if ENABLE_FEATURE_UDHCP_RFC3397 | 207 | #endif |
208 | #if ENABLE_FEATURE_UDHCP_RFC3397 || ENABLE_FEATURE_UDHCPC6_RFC3646 || ENABLE_FEATURE_UDHCPC6_RFC4704 | ||
203 | char *dname_dec(const uint8_t *cstr, int clen, const char *pre) FAST_FUNC; | 209 | char *dname_dec(const uint8_t *cstr, int clen, const char *pre) FAST_FUNC; |
204 | uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) FAST_FUNC; | 210 | uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) FAST_FUNC; |
205 | #endif | 211 | #endif |
@@ -284,7 +290,10 @@ void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC; | |||
284 | /* 2nd param is "uint32_t*" */ | 290 | /* 2nd param is "uint32_t*" */ |
285 | int FAST_FUNC udhcp_str2nip(const char *str, void *arg); | 291 | int FAST_FUNC udhcp_str2nip(const char *str, void *arg); |
286 | /* 2nd param is "struct option_set**" */ | 292 | /* 2nd param is "struct option_set**" */ |
287 | int FAST_FUNC udhcp_str2optset(const char *str, void *arg); | 293 | int FAST_FUNC udhcp_str2optset(const char *str, |
294 | void *arg, | ||
295 | const struct dhcp_optflag *optflags, | ||
296 | const char *option_strings); | ||
288 | 297 | ||
289 | void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; | 298 | void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; |
290 | 299 | ||
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index ef9b9a5f2..f6d3fb98b 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c | |||
@@ -2,26 +2,49 @@ | |||
2 | /* | 2 | /* |
3 | * DHCPv6 client. | 3 | * DHCPv6 client. |
4 | * | 4 | * |
5 | * 2011-11. | 5 | * WARNING: THIS CODE IS INCOMPLETE. |
6 | * WARNING: THIS CODE IS INCOMPLETE. IT IS NOWHERE NEAR | ||
7 | * TO BE READY FOR PRODUCTION USE. | ||
8 | * | 6 | * |
9 | * Copyright (C) 2011 Denys Vlasenko. | 7 | * Copyright (C) 2011-2017 Denys Vlasenko. |
10 | * | 8 | * |
11 | * Licensed under GPLv2, see file LICENSE in this source tree. | 9 | * Licensed under GPLv2, see file LICENSE in this source tree. |
12 | */ | 10 | */ |
13 | 11 | ||
14 | //config:config UDHCPC6 | 12 | //config:config UDHCPC6 |
15 | //config: bool "udhcpc6 (DHCPv6 client, NOT READY)" | 13 | //config: bool "udhcpc6 (DHCPv6 client, EXPERIMENTAL)" |
16 | //config: default n # not yet ready | 14 | //config: default n # not yet ready |
17 | //config: depends on FEATURE_IPV6 | 15 | //config: depends on FEATURE_IPV6 |
18 | //config: help | 16 | //config: help |
19 | //config: udhcpc6 is a DHCPv6 client | 17 | //config: udhcpc6 is a DHCPv6 client |
18 | //config: | ||
19 | //config:config FEATURE_UDHCPC6_RFC3646 | ||
20 | //config: bool "Support RFC 3646 (DNS server and search list)" | ||
21 | //config: default y | ||
22 | //config: depends on UDHCPC6 | ||
23 | //config: help | ||
24 | //config: List of DNS servers and domain search list can be requested with | ||
25 | //config: "-O dns" and "-O search". If server gives these values, | ||
26 | //config: they will be set in environment variables "dns" and "search". | ||
27 | //config: | ||
28 | //config:config FEATURE_UDHCPC6_RFC4704 | ||
29 | //config: bool "Support RFC 4704 (Client FQDN)" | ||
30 | //config: default y | ||
31 | //config: depends on UDHCPC6 | ||
32 | //config: help | ||
33 | //config: You can request FQDN to be given by server using "-O fqdn". | ||
34 | //config: | ||
35 | //config:config FEATURE_UDHCPC6_RFC4833 | ||
36 | //config: bool "Support RFC 4833 (Timezones)" | ||
37 | //config: default y | ||
38 | //config: depends on UDHCPC6 | ||
39 | //config: help | ||
40 | //config: You can request POSIX timezone with "-O tz" and timezone name | ||
41 | //config: with "-O timezone". | ||
20 | 42 | ||
21 | //applet:IF_UDHCPC6(APPLET(udhcpc6, BB_DIR_USR_BIN, BB_SUID_DROP)) | 43 | //applet:IF_UDHCPC6(APPLET(udhcpc6, BB_DIR_USR_BIN, BB_SUID_DROP)) |
22 | 44 | ||
23 | //kbuild:lib-$(CONFIG_UDHCPC6) += d6_dhcpc.o d6_packet.o d6_socket.o common.o socket.o signalpipe.o | 45 | //kbuild:lib-$(CONFIG_UDHCPC6) += d6_dhcpc.o d6_packet.o d6_socket.o common.o socket.o signalpipe.o |
24 | 46 | //kbuild:lib-$(CONFIG_FEATURE_UDHCPC6_RFC3646) += domain_codec.o | |
47 | //kbuild:lib-$(CONFIG_FEATURE_UDHCPC6_RFC4704) += domain_codec.o | ||
25 | 48 | ||
26 | #include <syslog.h> | 49 | #include <syslog.h> |
27 | /* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */ | 50 | /* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */ |
@@ -37,6 +60,34 @@ | |||
37 | 60 | ||
38 | /* "struct client_config_t client_config" is in bb_common_bufsiz1 */ | 61 | /* "struct client_config_t client_config" is in bb_common_bufsiz1 */ |
39 | 62 | ||
63 | static const struct dhcp_optflag d6_optflags[] = { | ||
64 | #if ENABLE_FEATURE_UDHCPC6_RFC3646 | ||
65 | { OPTION_6RD | OPTION_LIST | OPTION_REQ, D6_OPT_DNS_SERVERS }, | ||
66 | { OPTION_DNS_STRING | OPTION_LIST | OPTION_REQ, D6_OPT_DOMAIN_LIST }, | ||
67 | #endif | ||
68 | #if ENABLE_FEATURE_UDHCPC6_RFC4704 | ||
69 | { OPTION_DNS_STRING, D6_OPT_CLIENT_FQDN }, | ||
70 | #endif | ||
71 | #if ENABLE_FEATURE_UDHCPC6_RFC4833 | ||
72 | { OPTION_STRING, D6_OPT_TZ_POSIX }, | ||
73 | { OPTION_STRING, D6_OPT_TZ_NAME }, | ||
74 | #endif | ||
75 | { 0, 0 } | ||
76 | }; | ||
77 | /* Must match d6_optflags[] order */ | ||
78 | static const char d6_option_strings[] ALIGN1 = | ||
79 | #if ENABLE_FEATURE_UDHCPC6_RFC3646 | ||
80 | "dns" "\0" /* D6_OPT_DNS_SERVERS */ | ||
81 | "search" "\0" /* D6_OPT_DOMAIN_LIST */ | ||
82 | #endif | ||
83 | #if ENABLE_FEATURE_UDHCPC6_RFC4704 | ||
84 | "fqdn" "\0" /* D6_OPT_CLIENT_FQDN */ | ||
85 | #endif | ||
86 | #if ENABLE_FEATURE_UDHCPC6_RFC4833 | ||
87 | "tz" "\0" /* D6_OPT_TZ_POSIX */ | ||
88 | "timezone" "\0" /* D6_OPT_TZ_NAME */ | ||
89 | #endif | ||
90 | "\0"; | ||
40 | 91 | ||
41 | #if ENABLE_LONG_OPTS | 92 | #if ENABLE_LONG_OPTS |
42 | static const char udhcpc6_longopts[] ALIGN1 = | 93 | static const char udhcpc6_longopts[] ALIGN1 = |
@@ -88,14 +139,7 @@ enum { | |||
88 | IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) | 139 | IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) |
89 | }; | 140 | }; |
90 | 141 | ||
91 | static const char opt_req[] = { | 142 | #if ENABLE_FEATURE_UDHCPC6_RFC4704 |
92 | (D6_OPT_ORO >> 8), (D6_OPT_ORO & 0xff), | ||
93 | 0, 6, | ||
94 | (D6_OPT_DNS_SERVERS >> 8), (D6_OPT_DNS_SERVERS & 0xff), | ||
95 | (D6_OPT_DOMAIN_LIST >> 8), (D6_OPT_DOMAIN_LIST & 0xff), | ||
96 | (D6_OPT_CLIENT_FQDN >> 8), (D6_OPT_CLIENT_FQDN & 0xff), | ||
97 | }; | ||
98 | |||
99 | static const char opt_fqdn_req[] = { | 143 | static const char opt_fqdn_req[] = { |
100 | (D6_OPT_CLIENT_FQDN >> 8), (D6_OPT_CLIENT_FQDN & 0xff), | 144 | (D6_OPT_CLIENT_FQDN >> 8), (D6_OPT_CLIENT_FQDN & 0xff), |
101 | 0, 2, /* optlen */ | 145 | 0, 2, /* optlen */ |
@@ -105,6 +149,7 @@ static const char opt_fqdn_req[] = { | |||
105 | /* N=0: server SHOULD perform updates (PTR RR only in our case, since S=0) */ | 149 | /* N=0: server SHOULD perform updates (PTR RR only in our case, since S=0) */ |
106 | 0 /* empty DNS-encoded name */ | 150 | 0 /* empty DNS-encoded name */ |
107 | }; | 151 | }; |
152 | #endif | ||
108 | 153 | ||
109 | /*** Utility functions ***/ | 154 | /*** Utility functions ***/ |
110 | 155 | ||
@@ -152,10 +197,12 @@ static char** new_env(void) | |||
152 | /* put all the parameters into the environment */ | 197 | /* put all the parameters into the environment */ |
153 | static void option_to_env(uint8_t *option, uint8_t *option_end) | 198 | static void option_to_env(uint8_t *option, uint8_t *option_end) |
154 | { | 199 | { |
155 | char *dlist; | 200 | #if ENABLE_FEATURE_UDHCPC6_RFC3646 |
201 | int addrs, option_offset; | ||
202 | #endif | ||
156 | /* "length minus 4" */ | 203 | /* "length minus 4" */ |
157 | int len_m4 = option_end - option - 4; | 204 | int len_m4 = option_end - option - 4; |
158 | int addrs, option_offset; | 205 | |
159 | while (len_m4 >= 0) { | 206 | while (len_m4 >= 0) { |
160 | uint32_t v32; | 207 | uint32_t v32; |
161 | char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]; | 208 | char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]; |
@@ -237,7 +284,10 @@ static void option_to_env(uint8_t *option, uint8_t *option_end) | |||
237 | sprint_nip6(ipv6str, option + 4 + 4 + 1); | 284 | sprint_nip6(ipv6str, option + 4 + 4 + 1); |
238 | *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4])); | 285 | *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4])); |
239 | break; | 286 | break; |
240 | case D6_OPT_DNS_SERVERS: | 287 | #if ENABLE_FEATURE_UDHCPC6_RFC3646 |
288 | case D6_OPT_DNS_SERVERS: { | ||
289 | char *dlist; | ||
290 | |||
241 | /* Make sure payload-size is a multiple of 16 */ | 291 | /* Make sure payload-size is a multiple of 16 */ |
242 | if ((option[3] & 0x0f) != 0) | 292 | if ((option[3] & 0x0f) != 0) |
243 | break; | 293 | break; |
@@ -259,13 +309,21 @@ static void option_to_env(uint8_t *option, uint8_t *option_end) | |||
259 | } | 309 | } |
260 | 310 | ||
261 | break; | 311 | break; |
262 | case D6_OPT_DOMAIN_LIST: | 312 | } |
313 | case D6_OPT_DOMAIN_LIST: { | ||
314 | char *dlist; | ||
315 | |||
263 | dlist = dname_dec(option + 4, (option[2] << 8) | option[3], "search="); | 316 | dlist = dname_dec(option + 4, (option[2] << 8) | option[3], "search="); |
264 | if (!dlist) | 317 | if (!dlist) |
265 | break; | 318 | break; |
266 | *new_env() = dlist; | 319 | *new_env() = dlist; |
267 | break; | 320 | break; |
268 | case D6_OPT_CLIENT_FQDN: | 321 | } |
322 | #endif | ||
323 | #if ENABLE_FEATURE_UDHCPC6_RFC4704 | ||
324 | case D6_OPT_CLIENT_FQDN: { | ||
325 | char *dlist; | ||
326 | |||
269 | if (option[3] == 0) | 327 | if (option[3] == 0) |
270 | break; | 328 | break; |
271 | /* Work around broken ISC DHCPD6. | 329 | /* Work around broken ISC DHCPD6. |
@@ -284,6 +342,9 @@ static void option_to_env(uint8_t *option, uint8_t *option_end) | |||
284 | break; | 342 | break; |
285 | *new_env() = dlist; | 343 | *new_env() = dlist; |
286 | break; | 344 | break; |
345 | } | ||
346 | #endif | ||
347 | #if ENABLE_FEATURE_UDHCPC6_RFC4833 | ||
287 | /* RFC 4833 Timezones */ | 348 | /* RFC 4833 Timezones */ |
288 | case D6_OPT_TZ_POSIX: | 349 | case D6_OPT_TZ_POSIX: |
289 | *new_env() = xasprintf("tz=%.*s", (int)option[3], (char*)option + 4); | 350 | *new_env() = xasprintf("tz=%.*s", (int)option[3], (char*)option + 4); |
@@ -291,6 +352,7 @@ static void option_to_env(uint8_t *option, uint8_t *option_end) | |||
291 | case D6_OPT_TZ_NAME: | 352 | case D6_OPT_TZ_NAME: |
292 | *new_env() = xasprintf("tz_name=%.*s", (int)option[3], (char*)option + 4); | 353 | *new_env() = xasprintf("tz_name=%.*s", (int)option[3], (char*)option + 4); |
293 | break; | 354 | break; |
355 | #endif | ||
294 | } | 356 | } |
295 | len_m4 -= 4 + option[3]; | 357 | len_m4 -= 4 + option[3]; |
296 | option += 4 + option[3]; | 358 | option += 4 + option[3]; |
@@ -363,17 +425,33 @@ static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid | |||
363 | 425 | ||
364 | static uint8_t *add_d6_client_options(uint8_t *ptr) | 426 | static uint8_t *add_d6_client_options(uint8_t *ptr) |
365 | { | 427 | { |
366 | return ptr; | 428 | uint8_t *start = ptr; |
367 | //uint8_t c; | 429 | unsigned option; |
368 | //int i, end, len; | 430 | |
431 | ptr += 4; | ||
432 | for (option = 1; option < 256; option++) { | ||
433 | if (client_config.opt_mask[option >> 3] & (1 << (option & 7))) { | ||
434 | ptr[0] = (option >> 8); | ||
435 | ptr[1] = option; | ||
436 | ptr += 2; | ||
437 | } | ||
438 | } | ||
369 | 439 | ||
370 | /* Add a "param req" option with the list of options we'd like to have | 440 | if ((ptr - start - 4) != 0) { |
371 | * from stubborn DHCP servers. Pull the data from the struct in common.c. | 441 | start[0] = (D6_OPT_ORO >> 8); |
372 | * No bounds checking because it goes towards the head of the packet. */ | 442 | start[1] = D6_OPT_ORO; |
373 | //... | 443 | start[2] = ((ptr - start - 4) >> 8); |
444 | start[3] = (ptr - start - 4); | ||
445 | } else | ||
446 | ptr = start; | ||
374 | 447 | ||
448 | #if ENABLE_FEATURE_UDHCPC6_RFC4704 | ||
449 | ptr = mempcpy(ptr, &opt_fqdn_req, sizeof(opt_fqdn_req)); | ||
450 | #endif | ||
375 | /* Add -x options if any */ | 451 | /* Add -x options if any */ |
376 | //... | 452 | //... |
453 | |||
454 | return ptr; | ||
377 | } | 455 | } |
378 | 456 | ||
379 | static int d6_mcast_from_client_config_ifindex(struct d6_packet *packet, uint8_t *end) | 457 | static int d6_mcast_from_client_config_ifindex(struct d6_packet *packet, uint8_t *end) |
@@ -497,10 +575,6 @@ static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ip | |||
497 | } | 575 | } |
498 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len); | 576 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, len); |
499 | 577 | ||
500 | /* Request additional options */ | ||
501 | opt_ptr = mempcpy(opt_ptr, &opt_req, sizeof(opt_req)); | ||
502 | opt_ptr = mempcpy(opt_ptr, &opt_fqdn_req, sizeof(opt_fqdn_req)); | ||
503 | |||
504 | /* Add options: | 578 | /* Add options: |
505 | * "param req" option according to -O, options specified with -x | 579 | * "param req" option according to -O, options specified with -x |
506 | */ | 580 | */ |
@@ -554,10 +628,6 @@ static NOINLINE int send_d6_select(uint32_t xid) | |||
554 | /* IA NA (contains requested IP) */ | 628 | /* IA NA (contains requested IP) */ |
555 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); | 629 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); |
556 | 630 | ||
557 | /* Request additional options */ | ||
558 | opt_ptr = mempcpy(opt_ptr, &opt_req, sizeof(opt_req)); | ||
559 | opt_ptr = mempcpy(opt_ptr, &opt_fqdn_req, sizeof(opt_fqdn_req)); | ||
560 | |||
561 | /* Add options: | 631 | /* Add options: |
562 | * "param req" option according to -O, options specified with -x | 632 | * "param req" option according to -O, options specified with -x |
563 | */ | 633 | */ |
@@ -1063,20 +1133,18 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1063 | char *optstr = llist_pop(&list_O); | 1133 | char *optstr = llist_pop(&list_O); |
1064 | unsigned n = bb_strtou(optstr, NULL, 0); | 1134 | unsigned n = bb_strtou(optstr, NULL, 0); |
1065 | if (errno || n > 254) { | 1135 | if (errno || n > 254) { |
1066 | n = udhcp_option_idx(optstr); | 1136 | n = udhcp_option_idx(optstr, d6_option_strings); |
1067 | n = dhcp_optflags[n].code; | 1137 | n = d6_optflags[n].code; |
1068 | } | 1138 | } |
1069 | client_config.opt_mask[n >> 3] |= 1 << (n & 7); | 1139 | client_config.opt_mask[n >> 3] |= 1 << (n & 7); |
1070 | } | 1140 | } |
1071 | if (!(opt & OPT_o)) { | 1141 | if (!(opt & OPT_o)) { |
1072 | /* | ||
1073 | unsigned i, n; | 1142 | unsigned i, n; |
1074 | for (i = 0; (n = dhcp_optflags[i].code) != 0; i++) { | 1143 | for (i = 0; (n = d6_optflags[i].code) != 0; i++) { |
1075 | if (dhcp_optflags[i].flags & OPTION_REQ) { | 1144 | if (d6_optflags[i].flags & OPTION_REQ) { |
1076 | client_config.opt_mask[n >> 3] |= 1 << (n & 7); | 1145 | client_config.opt_mask[n >> 3] |= 1 << (n & 7); |
1077 | } | 1146 | } |
1078 | } | 1147 | } |
1079 | */ | ||
1080 | } | 1148 | } |
1081 | while (list_x) { | 1149 | while (list_x) { |
1082 | char *optstr = llist_pop(&list_x); | 1150 | char *optstr = llist_pop(&list_x); |
@@ -1085,7 +1153,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1085 | *colon = ' '; | 1153 | *colon = ' '; |
1086 | /* now it looks similar to udhcpd's config file line: | 1154 | /* now it looks similar to udhcpd's config file line: |
1087 | * "optname optval", using the common routine: */ | 1155 | * "optname optval", using the common routine: */ |
1088 | udhcp_str2optset(optstr, &client_config.options); | 1156 | udhcp_str2optset(optstr, &client_config.options, d6_optflags, d6_option_strings); |
1089 | if (colon) | 1157 | if (colon) |
1090 | *colon = ':'; /* restore it for NOMMU reexec */ | 1158 | *colon = ':'; /* restore it for NOMMU reexec */ |
1091 | } | 1159 | } |
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 6aa6731fb..1a66c610e 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -1346,7 +1346,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1346 | char *optstr = llist_pop(&list_O); | 1346 | char *optstr = llist_pop(&list_O); |
1347 | unsigned n = bb_strtou(optstr, NULL, 0); | 1347 | unsigned n = bb_strtou(optstr, NULL, 0); |
1348 | if (errno || n > 254) { | 1348 | if (errno || n > 254) { |
1349 | n = udhcp_option_idx(optstr); | 1349 | n = udhcp_option_idx(optstr, dhcp_option_strings); |
1350 | n = dhcp_optflags[n].code; | 1350 | n = dhcp_optflags[n].code; |
1351 | } | 1351 | } |
1352 | client_config.opt_mask[n >> 3] |= 1 << (n & 7); | 1352 | client_config.opt_mask[n >> 3] |= 1 << (n & 7); |
@@ -1366,7 +1366,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1366 | *colon = ' '; | 1366 | *colon = ' '; |
1367 | /* now it looks similar to udhcpd's config file line: | 1367 | /* now it looks similar to udhcpd's config file line: |
1368 | * "optname optval", using the common routine: */ | 1368 | * "optname optval", using the common routine: */ |
1369 | udhcp_str2optset(optstr, &client_config.options); | 1369 | udhcp_str2optset(optstr, &client_config.options, dhcp_optflags, dhcp_option_strings); |
1370 | if (colon) | 1370 | if (colon) |
1371 | *colon = ':'; /* restore it for NOMMU reexec */ | 1371 | *colon = ':'; /* restore it for NOMMU reexec */ |
1372 | } | 1372 | } |
diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h index 9f423a5b2..7fdbc9a6c 100644 --- a/networking/udhcp/dhcpc.h +++ b/networking/udhcp/dhcpc.h | |||
@@ -12,6 +12,7 @@ struct client_config_t { | |||
12 | IF_FEATURE_UDHCP_PORT(uint16_t port;) | 12 | IF_FEATURE_UDHCP_PORT(uint16_t port;) |
13 | int ifindex; /* Index number of the interface to use */ | 13 | int ifindex; /* Index number of the interface to use */ |
14 | uint8_t opt_mask[256 / 8]; /* Bitmask of options to send (-O option) */ | 14 | uint8_t opt_mask[256 / 8]; /* Bitmask of options to send (-O option) */ |
15 | // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TODO: DHCPv6 has 16-bit option numbers | ||
15 | const char *interface; /* The name of the interface to use */ | 16 | const char *interface; /* The name of the interface to use */ |
16 | char *pidfile; /* Optionally store the process ID */ | 17 | char *pidfile; /* Optionally store the process ID */ |
17 | const char *script; /* User script to run at dhcp events */ | 18 | const char *script; /* User script to run at dhcp events */ |
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 5eff026bc..3a5fc2db7 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
@@ -361,6 +361,10 @@ static int FAST_FUNC read_staticlease(const char *const_line, void *arg) | |||
361 | return 1; | 361 | return 1; |
362 | } | 362 | } |
363 | 363 | ||
364 | static int FAST_FUNC read_optset(const char *line, void *arg) { | ||
365 | return udhcp_str2optset(line, arg, dhcp_optflags, dhcp_option_strings); | ||
366 | } | ||
367 | |||
364 | struct config_keyword { | 368 | struct config_keyword { |
365 | const char *keyword; | 369 | const char *keyword; |
366 | int (*handler)(const char *line, void *var) FAST_FUNC; | 370 | int (*handler)(const char *line, void *var) FAST_FUNC; |
@@ -387,8 +391,8 @@ static const struct config_keyword keywords[] = { | |||
387 | {"pidfile" , read_str , OFS(pidfile ), "/var/run/udhcpd.pid"}, | 391 | {"pidfile" , read_str , OFS(pidfile ), "/var/run/udhcpd.pid"}, |
388 | {"siaddr" , udhcp_str2nip , OFS(siaddr_nip ), "0.0.0.0"}, | 392 | {"siaddr" , udhcp_str2nip , OFS(siaddr_nip ), "0.0.0.0"}, |
389 | /* keywords with no defaults must be last! */ | 393 | /* keywords with no defaults must be last! */ |
390 | {"option" , udhcp_str2optset, OFS(options ), ""}, | 394 | {"option" , read_optset , OFS(options ), ""}, |
391 | {"opt" , udhcp_str2optset, OFS(options ), ""}, | 395 | {"opt" , read_optset , OFS(options ), ""}, |
392 | {"notify_file" , read_str , OFS(notify_file ), NULL}, | 396 | {"notify_file" , read_str , OFS(notify_file ), NULL}, |
393 | {"sname" , read_str , OFS(sname ), NULL}, | 397 | {"sname" , read_str , OFS(sname ), NULL}, |
394 | {"boot_file" , read_str , OFS(boot_file ), NULL}, | 398 | {"boot_file" , read_str , OFS(boot_file ), NULL}, |