]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Fix Prefix Exclude encoding/decoding.
authorRoy Marples <roy@marples.name>
Mon, 7 Jul 2014 09:21:35 +0000 (09:21 +0000)
committerRoy Marples <roy@marples.name>
Mon, 7 Jul 2014 09:21:35 +0000 (09:21 +0000)
dhcp6.c

diff --git a/dhcp6.c b/dhcp6.c
index 40c4d49eb06e5b0fdb0bab3757575ad184c5b62a..290ec09975b0b0582c5ca7e5029b5f59cf4a3e73 100644 (file)
--- a/dhcp6.c
+++ b/dhcp6.c
@@ -411,7 +411,7 @@ dhcp6_makemessage(struct interface *ifp)
        uint16_t *u16, n_options;
        struct if_options *ifo;
        const struct dhcp_opt *opt, *opt2;
-       uint8_t IA, *p;
+       uint8_t IA, *p, *pp;
        uint32_t u32;
        const struct ipv6_addr *ap;
        char hbuf[HOSTNAME_MAX_LEN + 1];
@@ -704,31 +704,28 @@ dhcp6_makemessage(struct interface *ifp)
                                memcpy(p, &ap->prefix.s6_addr,
                                    sizeof(ap->prefix.s6_addr));
 
-                               /* RFC6603 Sectio 4.2 */
+                               /* RFC6603 Section 4.2 */
                                sla = dhcp6_findselfsla(ifp, ap->iaid);
                                if (sla &&
                                    dhcp6_delegateaddr(&addr, ifp, ap, sla) ==0)
                                {
-                                       uint16_t el;
-                                       uint8_t *pp;
-
-                                       el = ((sla->prefix_len -
+                                       n = ((sla->prefix_len -
                                            ap->prefix_len - 1) / NBBY) + 1;
                                        eo = D6_NEXT_OPTION(so);
                                        eo->code = htons(D6_OPTION_PD_EXCLUDE);
-                                       eo->len = el + 1;
+                                       eo->len = (uint16_t)n + 1;
                                        p = D6_OPTION_DATA(eo);
                                        *p++ = (uint8_t)sla->prefix_len;
                                        pp = addr.s6_addr;
-                                       pp += (ap->prefix_len - 1) / NBBY;
+                                       pp += ((ap->prefix_len - 1) / NBBY)
+                                           + (n - 1);
                                        u8 = ap->prefix_len % NBBY;
-                                       if (u8 % NBBY == 0)
-                                               pp++;
-                                       else {
-                                               *p = (uint8_t)(*pp++ << u8);
-                                               el--;
-                                       }
-                                       memcpy(p, pp, el);
+                                       if (u8)
+                                               n--;
+                                       while (n-- > 0)
+                                               *p++ = *pp--;
+                                       if (u8)
+                                               *p = (uint8_t)(*pp << u8);
                                        u32 = ntohs(so->len) +
                                            sizeof(*eo) + eo->len;
                                        so->len = htons(u32);
@@ -1672,7 +1669,7 @@ dhcp6_findpd(struct interface *ifp, const uint8_t *iaid,
        char iabuf[INET6_ADDRSTRLEN];
        const char *ia;
        int i;
-       uint8_t u8, len;
+       uint8_t u8, len, *pw;
        uint32_t u32, pltime, vltime;
        struct in6_addr prefix;
        size_t off;
@@ -1748,7 +1745,19 @@ dhcp6_findpd(struct interface *ifp, const uint8_t *iaid,
 
                off = (size_t)(pe - p);
                ex = dhcp6_findoption(D6_OPTION_PD_EXCLUDE, p, off);
-
+#if 0
+               if (ex == NULL) {
+                       struct dhcp6_option *w;
+                       uint8_t *wp;
+
+                       w = calloc(1, 128);
+                       w->len = htons(2);
+                       wp = D6_OPTION_DATA(w);
+                       *wp++ = 64;
+                       *wp++ = 0x78;
+                       ex = w;
+               }
+#endif
                if (ex) {
                        off = ntohs(ex->len);
                        if (off < 2) {
@@ -1758,19 +1767,21 @@ dhcp6_findpd(struct interface *ifp, const uint8_t *iaid,
                        }
                }
                if (ex) {
-                       int bytelen, bitlen;
-
                        op = D6_COPTION_DATA(ex);
                        a->prefix_exclude_len = *op++;
                        memcpy(&a->prefix_exclude, &a->prefix,
                            sizeof(a->prefix_exclude));
-                       bytelen = a->prefix_len / NBBY;
-                       bitlen = a->prefix_len % NBBY;
-                       if (bitlen != 0)
-                               a->prefix_exclude.s6_addr[bytelen] |=
-                                   *op++ >> bitlen;
-                       memcpy(a->prefix_exclude.s6_addr + bytelen + 1,
-                           op, off - 2);
+                       len = a->prefix_len / NBBY;
+                       u8 = a->prefix_len % NBBY;
+                       off--;
+                       if (u8)
+                               off--;
+                       pw = a->prefix_exclude.s6_addr +
+                           (a->prefix_exclude_len / NBBY) - 1;
+                       while (off-- > 0)
+                               *pw-- = *op++;
+                       if (u8)
+                               *pw |= *op >> u8;
                } else {
                        a->prefix_exclude_len = 0;
                        memset(&a->prefix_exclude, 0,