odhcpd: allow assignments to be reassigned
authorDavid Härdeman <[email protected]>
Sat, 20 Sep 2025 21:19:29 +0000 (23:19 +0200)
committerÁlvaro Fernández Rojas <[email protected]>
Thu, 9 Oct 2025 06:58:51 +0000 (08:58 +0200)
In a nutshell, this allows static leases which have only been configured
with a DUID (so no IAID specified) to be reassigned to any client with
the same DUID (but potentially different IAID). This matches how
multiple MAC addresses are handled in the DHCPv4 case, and supports the
use case for e.g. moving from WiFi to ethernet.

On the other hand, it is probably not what one would want for e.g. a
server that has several NICs connected to the same network. For those
cases, defining static leases with DUID and IAID anyway seems
preferrable (and it will also ensure a static interface<->IPv6 addr
mapping).

Signed-off-by: David Härdeman <[email protected]>
Link: https://github.com/openwrt/odhcpd/pull/255
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
src/dhcpv6-ia.c

index f24f14c37352452a12bf2f8ed707b9d3b112be87..1bdcfd39b409a58f8b3308782735c6176103644e 100644 (file)
@@ -1519,8 +1519,42 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
                               continue;
 
                        /* Does the IAID match? */
-                       if (c->iaid != ia->iaid)
-                              continue;
+                       if (c->iaid != ia->iaid) {
+                               if (is_pd)
+                                       continue;
+
+                               /* Does the existing assignment stem from the same static lease cfg? */
+                               if (c->lease != l)
+                                       continue;
+
+                               /*
+                                * If there's a DUID configured for this static lease, but without
+                                * an IAID, we will proceed under the assumption that a request
+                                * with the right DUID but with *any* IAID should be able to take
+                                * over the assignment. E.g. when switching from WiFi to ethernet
+                                * on the same client. This is similar to how multiple MAC adresses
+                                * are handled for DHCPv4.
+                                */
+                               for (size_t i = 0; i < l->duid_count; i++) {
+                                       if (l->duids[i].iaid_set && l->duids[i].iaid != htonl(ia->iaid))
+                                               continue;
+
+                                       if (l->duids[i].len != clid_len)
+                                               continue;
+
+                                       if (memcmp(l->duids[i].id, clid_data, clid_len))
+                                               continue;
+
+                                       /*
+                                        * Reconf doesn't specify the IAID, so we have to assume the client
+                                        * already knows or doesn't care about the old assignment.
+                                        */
+                                       stop_reconf(c);
+                                       free_assignment(c);
+                                       goto proceed;
+                               }
+                               continue;
+                       }
 
                        /* We have a match */
                        a = c;
@@ -1538,6 +1572,7 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
                        a = NULL;
                }
 
+proceed:
                /* Generic message handling */
                uint16_t status = DHCPV6_STATUS_OK;
                if (a && a->managed_size < 0)