aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--networking/udhcp/dhcpc.c57
1 files changed, 47 insertions, 10 deletions
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index ca82d37e6..510c3a1d0 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -300,6 +300,14 @@ static char **fill_envp(struct dhcp_packet *packet)
uint8_t *temp;
uint8_t overload = 0;
+#define BITMAP unsigned
+#define BBITS (sizeof(BITMAP) * 8)
+#define BMASK(i) (1 << (i & (sizeof(BITMAP) * 8 - 1)))
+#define FOUND_OPTS(i) (found_opts[(unsigned)i / BBITS])
+ BITMAP found_opts[256 / BBITS];
+
+ memset(found_opts, 0, sizeof(found_opts));
+
/* We need 6 elements for:
* "interface=IFACE"
* "ip=N.N.N.N" from packet->yiaddr
@@ -311,18 +319,21 @@ static char **fill_envp(struct dhcp_packet *packet)
envc = 6;
/* +1 element for each option, +2 for subnet option: */
if (packet) {
- for (i = 0; dhcp_optflags[i].code; i++) {
- if (udhcp_get_option(packet, dhcp_optflags[i].code)) {
- if (dhcp_optflags[i].code == DHCP_SUBNET)
+ /* note: do not search for "pad" (0) and "end" (255) options */
+ for (i = 1; i < 255; i++) {
+ temp = udhcp_get_option(packet, i);
+ if (temp) {
+ if (i == DHCP_OPTION_OVERLOAD)
+ overload = *temp;
+ else if (i == DHCP_SUBNET)
envc++; /* for mton */
envc++;
+ /*if (i != DHCP_MESSAGE_TYPE)*/
+ FOUND_OPTS(i) |= BMASK(i);
}
}
- temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD);
- if (temp)
- overload = *temp;
}
- curr = envp = xzalloc(sizeof(char *) * envc);
+ curr = envp = xzalloc(sizeof(envp[0]) * envc);
*curr = xasprintf("interface=%s", client_config.interface);
putenv(*curr++);
@@ -337,12 +348,16 @@ static char **fill_envp(struct dhcp_packet *packet)
opt_name = dhcp_option_strings;
i = 0;
while (*opt_name) {
- temp = udhcp_get_option(packet, dhcp_optflags[i].code);
- if (!temp)
+ uint8_t code = dhcp_optflags[i].code;
+ BITMAP *found_ptr = &FOUND_OPTS(code);
+ BITMAP found_mask = BMASK(code);
+ if (!(*found_ptr & found_mask))
goto next;
+ *found_ptr &= ~found_mask; /* leave only unknown options */
+ temp = udhcp_get_option(packet, code);
*curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name);
putenv(*curr++);
- if (dhcp_optflags[i].code == DHCP_SUBNET) {
+ if (code == DHCP_SUBNET) {
/* Subnet option: make things like "$ip/$mask" possible */
uint32_t subnet;
move_from_unaligned32(subnet, temp);
@@ -368,6 +383,28 @@ static char **fill_envp(struct dhcp_packet *packet)
*curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname);
putenv(*curr++);
}
+ /* Handle unknown options */
+ for (i = 0; i < 256;) {
+ BITMAP bitmap = FOUND_OPTS(i);
+ if (!bitmap) {
+ i += BBITS;
+ continue;
+ }
+ if (bitmap & BMASK(i)) {
+ unsigned len, ofs;
+
+ temp = udhcp_get_option(packet, i);
+ /* udhcp_get_option returns ptr to data portion,
+ * need to go back to get len
+ */
+ len = temp[-OPT_DATA + OPT_LEN];
+ *curr = xmalloc(sizeof("optNNN=") + 1 + len*2);
+ ofs = sprintf(*curr, "opt%u=", i);
+ bin2hex(*curr + ofs, (void*) temp, len)[0] = '\0';
+ putenv(*curr++);
+ }
+ i++;
+ }
return envp;
}