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
 		  {