udhcpc: add support for DHCP option 212 (RFC 5969)
authorDenys Vlasenko <vda.linux@googlemail.com>
Wed, 19 Oct 2011 20:40:35 +0000 (22:40 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 19 Oct 2011 20:40:35 +0000 (22:40 +0200)
The patch is from OpenWRT people.

function                                             old     new   delta
xmalloc_optname_optval                               637     874    +237
dhcp_option_strings                                  237     243      +6
dhcp_optflags                                         68      70      +2
len_of_option_as_string                               12      13      +1
dhcp_option_lengths                                   12      13      +1
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/0 up/down: 247/0)             Total: 247 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
include/libbb.h
networking/udhcp/common.c
networking/udhcp/common.h
networking/udhcp/dhcpc.c

index f79b693..f0f54ef 100644 (file)
@@ -814,9 +814,9 @@ void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_F
 const char *make_human_readable_str(unsigned long long size,
                unsigned long block_size, unsigned long display_unit) FAST_FUNC;
 /* Put a string of hex bytes ("1b2e66fe"...), return advanced pointer */
-char *bin2hex(char *buf, const char *cp, int count) FAST_FUNC;
+char *bin2hex(char *dst, const char *src, int count) FAST_FUNC;
 /* Reverse */
-char* hex2bin(char *dst, const char *str, int count) FAST_FUNC;
+char* hex2bin(char *dst, const char *src, int count) FAST_FUNC;
 
 /* Generate a UUID */
 void generate_uuid(uint8_t *buf) FAST_FUNC;
index 70e3461..ba41905 100644 (file)
@@ -59,6 +59,7 @@ const struct dhcp_optflag dhcp_optflags[] = {
        { OPTION_U16                              , 0x84 }, /* DHCP_VLAN_ID       */
        { OPTION_U8                               , 0x85 }, /* DHCP_VLAN_PRIORITY */
 #endif
+       { OPTION_6RD                              , 0xd4 }, /* DHCP_6RD           */
        { OPTION_STATIC_ROUTES                    , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
        { OPTION_STRING                           , 0xfc }, /* DHCP_WPAD          */
 
@@ -126,6 +127,7 @@ const char dhcp_option_strings[] ALIGN1 =
        "vlanid" "\0"      /* DHCP_VLAN_ID        */
        "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY  */
 #endif
+       "ip6rd" "\0"       /* DHCP_6RD            */
        "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */
        "wpad" "\0"        /* DHCP_WPAD           */
        ;
@@ -154,6 +156,7 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = {
        [OPTION_S32] =     4,
        /* Just like OPTION_STRING, we use minimum length here */
        [OPTION_STATIC_ROUTES] = 5,
+       [OPTION_6RD] =    22,  /* ignored by udhcp_str2optset */
 };
 
 
index 7862668..da0bd38 100644 (file)
@@ -88,6 +88,7 @@ enum {
        OPTION_S32,
        OPTION_BIN,
        OPTION_STATIC_ROUTES,
+       OPTION_6RD,
 #if ENABLE_FEATURE_UDHCP_RFC3397
        OPTION_DNS_STRING,  /* RFC1035 compressed domain name list */
        OPTION_SIP_SERVERS,
index ddfe3cc..311d486 100644 (file)
@@ -100,6 +100,7 @@ static const uint8_t len_of_option_as_string[] = {
        [OPTION_IP              ] = sizeof("255.255.255.255 "),
        [OPTION_IP_PAIR         ] = sizeof("255.255.255.255 ") * 2,
        [OPTION_STATIC_ROUTES   ] = sizeof("255.255.255.255/32 255.255.255.255 "),
+       [OPTION_6RD             ] = sizeof("32 128 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 255.255.255.255 "),
        [OPTION_STRING          ] = 1,
 #if ENABLE_FEATURE_UDHCP_RFC3397
        [OPTION_DNS_STRING      ] = 1, /* unused */
@@ -123,6 +124,24 @@ static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
        return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
 }
 
+static int sprint_nip6(char *dest, const char *pre, const uint8_t *ip)
+{
+       char hexstrbuf[16 * 2];
+       bin2hex(hexstrbuf, (void*)ip, 16);
+       return sprintf(dest, "%s"
+               "%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s",
+               pre,
+               hexstrbuf + 0 * 4,
+               hexstrbuf + 1 * 4,
+               hexstrbuf + 2 * 4,
+               hexstrbuf + 3 * 4,
+               hexstrbuf + 4 * 4,
+               hexstrbuf + 5 * 4,
+               hexstrbuf + 6 * 4,
+               hexstrbuf + 7 * 4
+       );
+}
+
 /* really simple implementation, just count the bits */
 static int mton(uint32_t mask)
 {
@@ -147,7 +166,8 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
 
        type = optflag->flags & OPTION_TYPE_MASK;
        optlen = dhcp_option_lengths[type];
-       upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen);
+       upper_length = len_of_option_as_string[type]
+               * ((unsigned)(len + optlen - 1) / (unsigned)optlen);
 
        dest = ret = xmalloc(upper_length + strlen(opt_name) + 2);
        dest += sprintf(ret, "%s=", opt_name);
@@ -232,6 +252,62 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_
 
                        return ret;
                }
+               case OPTION_6RD: {
+                       /* Option binary format (see RFC 5969):
+                        * 0                   1                   2                   3
+                        * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+                        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                        * |  OPTION_6RD   | option-length |  IPv4MaskLen  |  6rdPrefixLen |
+                        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                        * |                                                               |
+                        * |                           6rdPrefix                           |
+                        * |                          (16 octets)                          |
+                        * |                                                               |
+                        * |                                                               |
+                        * |                                                               |
+                        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                        * |                     6rdBRIPv4Address(es)                      |
+                        * .                                                               .
+                        * .                                                               .
+                        * .                                                               .
+                        * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                        *
+                        * We convert it to a string
+                        * "IPv4MaskLen 6rdPrefixLen 6rdPrefix 6rdBRIPv4Address..."
+                        */
+
+                       /* Sanity check: ensure that our length is at least 22 bytes, that
+                        * IPv4MaskLen <= 32,
+                        * 6rdPrefixLen <= 128,
+                        * 6rdPrefixLen + (32 - IPv4MaskLen) <= 128
+                        * (2nd condition need no check - it follows from 1st and 3rd).
+                        * If any of these requirements is not fulfilled, return with empty
+                        * value.
+                        */
+                       if (len >= 22
+                        && option[0] <= 32
+                        && (option[1] + 32 - option[0]) <= 128
+                       ) {
+                               /* IPv4MaskLen */
+                               dest += sprintf(dest, "%u ", *option++);
+                               /* 6rdPrefixLen */
+                               dest += sprintf(dest, "%u ", *option++);
+                               /* 6rdPrefix */
+                               dest += sprint_nip6(dest, "", option);
+                               option += 16;
+                               len -= 1 + 1 + 16;
+                               /* 6rdBRIPv4Address(es) */
+                               while (1) {
+                                       dest += sprint_nip(dest, " ", option);
+                                       option += 4;
+                                       len -= 4;
+                                       if (len < 0)
+                                               break;
+                               }
+                       }
+
+                       return ret;
+               }
 #if ENABLE_FEATURE_UDHCP_RFC3397
                case OPTION_DNS_STRING:
                        /* unpack option into dest; use ret for prefix (i.e., "optname=") */
@@ -394,7 +470,7 @@ static char **fill_envp(struct dhcp_packet *packet)
                        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';
+                       *bin2hex(*curr + ofs, (void*) temp, len) = '\0';
                        putenv(*curr++);
                }
                i++;