router: remove duplicated PIOs
authorÁlvaro Fernández Rojas <[email protected]>
Mon, 1 Dec 2025 10:07:43 +0000 (11:07 +0100)
committerÁlvaro Fernández Rojas <[email protected]>
Thu, 4 Dec 2025 14:40:49 +0000 (15:40 +0100)
There can be duplicated PIOs if the user changed the assigned prefix length
in the configuration.

Link: https://github.com/openwrt/odhcpd/pull/336
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
src/router.c

index 63bb3db646733c6e4207cea8f09bd1a3a3ffc444..ef47d0ffac0b78763dbd2cb3bd4ca8ae0dd7361a 100644 (file)
@@ -526,6 +526,43 @@ static void router_add_ra_pio(struct interface *iface,
             pio->length);
 }
 
+static void router_clear_duplicated_ra_pio(struct interface *iface)
+{
+       size_t pio_cnt = iface->pio_cnt;
+       char ipv6_str[INET6_ADDRSTRLEN];
+
+       for (size_t i = 0; i < iface->pio_cnt; i++) {
+               struct ra_pio *pio_a = &iface->pios[i];
+               size_t j = i + 1;
+
+               while (j < iface->pio_cnt) {
+                       struct ra_pio *pio_b = &iface->pios[j];
+
+                       if (pio_a->length == pio_b->length &&
+                           !memcmp(&pio_a->prefix, &pio_b->prefix, sizeof(struct in6_addr))) {
+                               warn("rfc9096: %s: clear duplicated %s/%u",
+                                    iface->ifname,
+                                    inet_ntop(AF_INET6, &pio_a->prefix, ipv6_str, sizeof(ipv6_str)),
+                                    pio_a->length);
+
+                               if (j + 1 < iface->pio_cnt)
+                                       iface->pios[j] = iface->pios[iface->pio_cnt - 1];
+
+                               iface->pio_cnt--;
+                       } else {
+                               j++;
+                       }
+               }
+       }
+
+       if (iface->pio_cnt != pio_cnt) {
+               struct ra_pio *new_pios = realloc(iface->pios, sizeof(struct ra_pio) * iface->pio_cnt);
+
+               if (new_pios)
+                       iface->pios = new_pios;
+       }
+}
+
 static void router_clear_expired_ra_pio(time_t now,
        struct interface *iface)
 {
@@ -824,6 +861,8 @@ static int send_router_advert(struct interface *iface, const struct in6_addr *fr
                }
        }
 
+       router_clear_duplicated_ra_pio(iface);
+
        iov[IOV_RA_PFXS].iov_base = (char *)pfxs;
        iov[IOV_RA_PFXS].iov_len = pfxs_cnt * sizeof(*pfxs);