dhcpc: export unrecognized options in "optNN=XXXXXXXXX" form
authorNigel Hathaway <Nigel.Hathaway@ubiquisys.com>
Tue, 26 Apr 2011 00:38:29 +0000 (02:38 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 26 Apr 2011 00:38:29 +0000 (02:38 +0200)
function                                             old     new   delta
udhcp_run_script                                     609     818    +209

Signed-off-by: Nigel Hathaway <Nigel.Hathaway@ubiquisys.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/udhcp/dhcpc.c

index ca82d37..510c3a1 100644 (file)
@@ -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;
 }