dhcpv6: assign a new field for prefix exclusion length
authorPaul Donald <newtwen+github@gmail.com>
Tue, 18 Nov 2025 15:46:01 +0000 (16:46 +0100)
committerÁlvaro Fernández Rojas <noltari@gmail.com>
Sun, 23 Nov 2025 19:09:22 +0000 (20:09 +0100)
re-using the priority field is very confusing, for the sake of saving a byte.

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
Link: https://github.com/openwrt/odhcp6c/pull/123
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
src/dhcpv6.c
src/odhcp6c.h
src/script.c
src/ubus.c

index a756971f7535a549c775bd00c44b3d2f86f931f3..5fbc437bc5a54aeeb9c80d589353458b2b87d054 100644 (file)
@@ -787,8 +787,8 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs)
                                        continue;
 
                                uint8_t ex_len = 0;
-                               if (pd_entries[j].priority > 0)
-                                       ex_len = ((pd_entries[j].priority - pd_entries[j].length - 1) / 8) + 6;
+                               if (pd_entries[j].exclusion_length > 0)
+                                       ex_len = ((pd_entries[j].exclusion_length - pd_entries[j].length - 1) / 8) + 6;
 
                                struct dhcpv6_ia_prefix p = {
                                        .type = htons(DHCPV6_OPT_IA_PREFIX),
@@ -810,11 +810,11 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs)
                                        ia_pd[ia_pd_len++] = DHCPV6_OPT_PD_EXCLUDE;
                                        ia_pd[ia_pd_len++] = 0;
                                        ia_pd[ia_pd_len++] = ex_len - DHCPV6_OPT_HDR_SIZE;
-                                       ia_pd[ia_pd_len++] = pd_entries[j].priority;
+                                       ia_pd[ia_pd_len++] = pd_entries[j].exclusion_length;
 
                                        uint32_t excl = ntohl(pd_entries[j].router.s6_addr32[1]);
-                                       excl >>= (64 - pd_entries[j].priority);
-                                       excl <<= 8 - ((pd_entries[j].priority - pd_entries[j].length) % 8);
+                                       excl >>= (64 - pd_entries[j].exclusion_length);
+                                       excl <<= 8 - ((pd_entries[j].exclusion_length - pd_entries[j].length) % 8);
 
                                        for (size_t k = ex_len - 5; k > 0; --k, excl >>= 8)
                                                ia_pd[ia_pd_len + k] = excl & 0xff;
@@ -1666,6 +1666,7 @@ static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret)
                        .auxlen = 0,
                        .length = 0,
                        .ra_flags = 0,
+                       .exclusion_length = 0,
                        .target = IN6ADDR_ANY_INIT,
                        .priority = 0,
                        .valid = 0,
@@ -1721,33 +1722,35 @@ static unsigned int dhcpv6_parse_ia(void *opt, void *end, int *ret)
                                        if (ret) *ret = 0; // renewal failed
                                } else if (stype == DHCPV6_OPT_PD_EXCLUDE && slen > 2) {
                                        /*      RFC 6603 §4.2 Prefix Exclude option */
-                                       uint8_t elen = sdata[0];
-                                       if (elen > 64)
-                                               elen = 64;
+                                       uint8_t exclude_length = sdata[0];
+                                       if (exclude_length > 64)
+                                               exclude_length = 64;
 
-                                       if (entry.length < 32 || elen <= entry.length) {
+                                       if (entry.length < 32 || exclude_length <= entry.length) {
                                                update_state = false;
                                                continue;
                                        }
 
-                                       uint8_t bytes = ((elen - entry.length - 1) / 8) + 1;
-                                       if (slen <= bytes) {
+                                       uint8_t bytes_needed = ((exclude_length - entry.length - 1) / 8) + 1;
+                                       if (slen <= bytes_needed) {
                                                update_state = false;
                                                continue;
                                        }
 
-                                       uint32_t exclude = 0;
+                                       // this decrements through the ipaddr bytes masking against 
+                                       // the address in the option until byte 0, the option length field.
+                                       uint32_t excluded_bits = 0;
                                        do {
-                                               exclude = exclude << 8 | sdata[bytes];
-                                       } while (--bytes);
+                                               excluded_bits = excluded_bits << 8 | sdata[bytes_needed];
+                                       } while (--bytes_needed);
 
-                                       exclude >>= 8 - ((elen - entry.length) % 8);
-                                       exclude <<= 64 - elen;
+                                       excluded_bits >>= 8 - ((exclude_length - entry.length) % 8);
+                                       excluded_bits <<= 64 - exclude_length;
 
-                                       // Abusing router & priority fields for exclusion
-                                       entry.router = entry.target;
-                                       entry.router.s6_addr32[1] |= htonl(exclude);
-                                       entry.priority = elen;
+                                       // Re-using router field to hold the prefix
+                                       entry.router = entry.target; // base prefix
+                                       entry.router.s6_addr32[1] |= htonl(excluded_bits);
+                                       entry.exclusion_length = exclude_length;
                                }
                        }
 
index 410da1e4c4ed97abe11fa6bf02b49c1d14ddbf69..b0094fe942d210c6edec68d9f1ad2639b3883df0 100644 (file)
@@ -482,6 +482,7 @@ struct odhcp6c_entry {
        uint8_t auxlen;
        uint8_t length;
        uint8_t ra_flags;
+       uint8_t exclusion_length;
        struct in6_addr target;
        int16_t priority;
        uint32_t valid;
index 131d70da5445ebeb010ba78dd553c93871858466..10c348221e7cd38f2851daf8aa73a0e6b306021b 100644 (file)
@@ -217,13 +217,13 @@ static void entry_to_env(const char *name, const void *data, size_t len, enum en
                                buf_len += strlen(&buf[buf_len]);
                        }
 
-                       if (type == ENTRY_PREFIX && e[i].priority) {
-                               // priority and router are abused for prefix exclusion
+                       if (type == ENTRY_PREFIX && e[i].exclusion_length) {
                                snprintf(&buf[buf_len], 11, ",excluded=");
                                buf_len += strlen(&buf[buf_len]);
+                               // '.router' is dual-used: for prefixes it contains the prefix
                                inet_ntop(AF_INET6, &e[i].router, &buf[buf_len], INET6_ADDRSTRLEN);
                                buf_len += strlen(&buf[buf_len]);
-                               snprintf(&buf[buf_len], 12, "/%u", e[i].priority);
+                               snprintf(&buf[buf_len], 12, "/%u", e[i].exclusion_length);
                                buf_len += strlen(&buf[buf_len]);
                        }
                }
index 0b37ddfb377054e373a689f95c2d1549d420987b..664feffbda1f7555d28725857cefc958e8b0d072 100644 (file)
@@ -343,13 +343,13 @@ static int entry_to_blob(const char *name, const void *data, size_t len, enum en
                                blobmsg_add_u32(&b, "iaid", ntohl(e[i].iaid));
                        }
 
-                       if (type == ENTRY_PREFIX && e[i].priority) {
-                               // priority and router are abused for prefix exclusion
+                       if (type == ENTRY_PREFIX && e[i].exclusion_length) {
                                buf = blobmsg_alloc_string_buffer(&b, "excluded", INET6_ADDRSTRLEN);
                                CHECK_ALLOC(buf);
+                               // '.router' is dual-used: for prefixes it contains the prefix
                                inet_ntop(AF_INET6, &e[i].router, buf, INET6_ADDRSTRLEN);
                                blobmsg_add_string_buffer(&b);
-                               blobmsg_add_u32(&b, "excluded_length", e[i].priority);
+                               blobmsg_add_u32(&b, "excluded_length", e[i].exclusion_length);
                        }
                }