DHCPv6 address allocation - same DUID, two IAIDs
diff --git a/src/dhcp6.c b/src/dhcp6.c
index dd88058..9922c85 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -328,6 +328,7 @@
return 0;
}
+/* can dynamically allocate addr */
struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids)
@@ -352,6 +353,22 @@
return NULL;
}
+/* address OK if configured */
+struct dhcp_context *address6_valid(struct dhcp_context *context,
+ struct in6_addr *taddr,
+ struct dhcp_netid *netids)
+{
+ struct dhcp_context *tmp;
+
+ for (tmp = context; tmp; tmp = tmp->current)
+ if ((tmp->flags & CONTEXT_STATIC) &&
+ is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
+ match_netid(tmp->filter, netids, 1))
+ return tmp;
+
+ return NULL;
+}
+
struct dhcp_context *narrow_context6(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids)
@@ -366,21 +383,12 @@
struct dhcp_context *tmp;
- if (!(tmp = address6_available(context, taddr, netids)))
- {
- for (tmp = context; tmp; tmp = tmp->current)
- if (match_netid(tmp->filter, netids, 1) &&
- is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
- (tmp->flags & CONTEXT_STATIC))
- break;
-
- if (!tmp)
- for (tmp = context; tmp; tmp = tmp->current)
- if (match_netid(tmp->filter, netids, 1) &&
- is_same_net6(taddr, &tmp->start6, tmp->prefix) &&
- !(tmp->flags & CONTEXT_PROXY))
- break;
- }
+ if (!(tmp = address6_available(context, taddr, netids)) &&
+ !(tmp = address6_valid(context, taddr, netids)))
+ for (tmp = context; tmp; tmp = tmp->current)
+ if (match_netid(tmp->filter, netids, 1) &&
+ is_same_net6(taddr, &tmp->start6, tmp->prefix))
+ break;
/* Only one context allowed now */
if (tmp)
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 5eadaa1..d3a34ea 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1149,6 +1149,9 @@
struct dhcp_context *address6_available(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids);
+struct dhcp_context *address6_valid(struct dhcp_context *context,
+ struct in6_addr *taddr,
+ struct dhcp_netid *netids);
struct dhcp_context *narrow_context6(struct dhcp_context *context,
struct in6_addr *taddr,
struct dhcp_netid *netids);
diff --git a/src/rfc3315.c b/src/rfc3315.c
index 560fdc1..f24a3c6 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -525,32 +525,38 @@
{
struct in6_addr *req_addr = opt6_ptr(ia_option, 0);
requested_time = opt6_uint(ia_option, 16, 4);
-
- if (!address6_available(context, req_addr, tags) &&
- (!have_config(config, CONFIG_ADDR6) || memcmp(&config->addr6, req_addr, IN6ADDRSZ) != 0))
+ struct dhcp_context *dynamic;
+
+ if ((dynamic = address6_available(context, req_addr, tags)) || address6_valid(context, req_addr, tags))
{
- if (msg_type == DHCP6REQUEST)
+ if (!dynamic && !(have_config(config, CONFIG_ADDR6) && memcmp(&config->addr6, req_addr, IN6ADDRSZ) == 0))
{
- /* host has a lease, but it's not on the correct link */
+ /* Static range, not configured. */
o1 = new_opt6(OPTION6_STATUS_CODE);
- put_opt6_short(DHCP6NOTONLINK);
- put_opt6_string("Not on link");
+ put_opt6_short(DHCP6UNSPEC);
+ put_opt6_string("Address unavailable");
end_opt6(o1);
}
+ else if (lease6_find_by_addr(req_addr, 128, 0) &&
+ !(lease = lease6_find(clid, clid_len, ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA, iaid, req_addr)))
+ {
+ /* Address leased to another DUID/IAID */
+ o1 = new_opt6(OPTION6_STATUS_CODE);
+ put_opt6_short(DHCP6UNSPEC);
+ put_opt6_string("Address in use");
+ end_opt6(o1);
+ }
+ else
+ addrp = req_addr;
}
- else if ((lease = lease6_find(NULL, 0, ia_type == OPTION6_IA_NA ? LEASE_NA : LEASE_TA,
- iaid, req_addr)) &&
- (clid_len != lease->clid_len ||
- memcmp(clid, lease->clid, clid_len) != 0))
+ else if (msg_type == DHCP6REQUEST)
{
- /* Address leased to another DUID */
+ /* requested address not on the correct link */
o1 = new_opt6(OPTION6_STATUS_CODE);
- put_opt6_short(DHCP6UNSPEC);
- put_opt6_string("Address in use");
+ put_opt6_short(DHCP6NOTONLINK);
+ put_opt6_string("Not on link");
end_opt6(o1);
- }
- else
- addrp = req_addr;
+ }
}
else
{