Hi Simon,

I would like to re-post previous patches updating dhcpv6 address
conflict. It helps network booting many machines at similar time on ipv6
network. Just first patch has functional change, other are simple
improvements.

On 9/17/21 21:16, Petr Menšík wrote:
>
> Hi Harald, Simon,
>
> I made an alternative change, which I think has similar output. I
> think the use of DHCP6UNSPEC is suspicious itself and does not have
> any good error code assigned by RFC 8415, because it should not result
> in an error. I have tried to add also MUST require from the RFC,
> refusing off-link requests with NotOnLink error. Not yet tested it
> myself, I have no IPv6 booting environment available (yet). That is in
> patch1.
>
> Patch2 is just bunch of const changes, reduction of repeated status
> code filling into dedicated function. Should not change behaviour,
> just reduces few lines and some cosmetic changes.
>
> On 9/17/21 13:33, Harald Jensas wrote:
>> On 9/16/21 21:32, Petr Menšík wrote:
>>> Hi!
>>>
>>> There is also bug on Red Hat bugzilla [1] for this issue, which
>>> contains
>>> a bit more comments about it.
>>>
>>> I would make short summary here. The problem is client on the same
>>> machine with the same DUID and mac address requests IPv6. Before it
>>> processes Advertisement, it requests IPv6 again, this time with
>>> different IAID.
>>>
>>> So there are two different request, the only difference are IAID and
>>> requested options set. Now if the second request gets processed first,
>>> it assigns lease first. Consider --dhcp-sequential-ip is in use.
>>> Then first request processes advertisement and attempts to request the
>>> same IP.
>>> Now it would fail.
>>>
>>> How should it react according to RFC 8415 [2]? In current situation,
>>> dnsmasq responds with No address available error. Could it instead
>>> respond with different address? How should the server and the client
>>> behave, when advertised address is no longer available? Is it broken on
>>> both sides?
>>
>> I think Petr may be on to something with "Could it instead respond
>> with a different address?". It seems this is ok based on rfc8415
>> 18.3.2 [1] which states the following:
>> """
>>    The server MAY assign different addresses and/or delegated prefixes
>>    to an IA than those included within the IA of the client's Request
>>    message.
>> """
>>
>> With the below patch I got dnsmasq to reply with a new address to the
>> request with the already leased address. This makes dnsmasq behave
>> similar to kea-dhcp6, see Bugzilla comments #36 and #41 [2][3] which
>> also contain a pcap files.
>>
>> I tested this with both static and dynamic configuration,
>> "sequential-ip" enabled, and it seems to work.
>>
>> If I change the 'dhcp-host' entry in the static config to contain
>> just *one* address, it fails as expected with:
>>   option: 13 status  2 address unavailable
>>   option: 13 status  2 no addresses available
>>
>>
>> I tested with the following configurations ...
>>
>> Static config:
>> --------------
>> log-dhcp
>> port=0
>> dhcp-range=set:range0,2001::,static,64,10m
>> dhcp-host=00:84:ed:01:00:10,tag:dhcpv6,client.localdomain,[2001::20],[2001::21],[2001::22],[2001::23]
>>
>> dhcp-sequential-ip
>> # dhcpv6s for Client System Architecture Type (61)
>> dhcp-match=set:efi6,option6:61,0007
>> dhcp-match=set:efi6,option6:61,0009
>> dhcp-match=set:efi6,option6:61,0011
>> dhcp-option=tag:efi6,option6:bootfile-url,tftp://[2001::2]/shimx64.efi
>>
>> Dynamic config with sequential-ip:
>> ---------------------------------
>> log-dhcp
>> port=0
>>
>> dhcp-range=set:range0,2001::10,2001::100,64,10m
>> dhcp-sequential-ip
>> # dhcpv6s for Client System Architecture Type (61)
>> dhcp-match=set:efi6,option6:61,0007
>> dhcp-match=set:efi6,option6:61,0009
>> dhcp-match=set:efi6,option6:61,0011
>> dhcp-option=tag:efi6,option6:bootfile-url,tftp://[2001::2]/shimx64.efi
>>
>>
>>
>> Regards,
>> Harald
>>
>> [1] https://datatracker.ietf.org/doc/html/rfc8415#section-18.3.2
>> [2] https://bugzilla.redhat.com/show_bug.cgi?id=1998448#c36
>> [3] https://bugzilla.redhat.com/show_bug.cgi?id=1998448#c41
>>
>> _______________________________________________
>> Dnsmasq-discuss mailing list
>> Dnsmasq-discuss@lists.thekelleys.org.uk
>> https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss
> -- 
> Petr Menšík
> Software Engineer
> Red Hat, http://www.redhat.com/
> email: pemen...@redhat.com
> PGP: DFCF908DB7C87E8E529925BC4931CA5B6C9FC5CB

-- 
Petr Menšík
Software Engineer
Red Hat, http://www.redhat.com/
email: pemen...@redhat.com
PGP: DFCF908DB7C87E8E529925BC4931CA5B6C9FC5CB
From 6b54ca1b574e649394f856fd029278c58aa7a9bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemen...@redhat.com>
Date: Wed, 22 Sep 2021 14:54:01 +0200
Subject: [PATCH 3/3] Add support for option6 names of RFC 5970

Client Network Interface Identifier and Client System Architecture Type
options were not understood by dnsmasq. Add it to supported option
types.
---
 src/dhcp-common.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/dhcp-common.c b/src/dhcp-common.c
index 291e82b..ebb9302 100644
--- a/src/dhcp-common.c
+++ b/src/dhcp-common.c
@@ -694,6 +694,8 @@ static const struct opttab_t opttab6[] = {
   { "ntp-server", 56, 0 /* OT_ADDR_LIST | OT_RFC1035_NAME */ },
   { "bootfile-url", 59, OT_NAME },
   { "bootfile-param", 60, OT_CSTRING },
+  { "client-arch", 61, 2 | OT_DEC }, /* RFC 5970 */
+  { "client-interface-id", 62, 1 | OT_DEC }, /* RFC 5970 */
   { NULL, 0, 0 }
 };
 #endif
-- 
2.34.1

From b3f9e80caa3982838707df96179e18b5397bb380 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemen...@redhat.com>
Date: Fri, 17 Sep 2021 20:55:56 +0200
Subject: [PATCH 2/3] Move dhcp6 status code to subroutine, add consts

Setting DHCP6 status code is frequent in the code, it deserves
subroutine reducing four lines to single. Make putting string const, use
just single gettext call on few places. Move add_address companion
get_context_tag into the function, since it needs to be called always
with it. Has all needed parameters already.
---
 src/dnsmasq.h   |   4 +-
 src/outpacket.c |   4 +-
 src/rfc3315.c   | 127 +++++++++++++++---------------------------------
 3 files changed, 44 insertions(+), 91 deletions(-)

diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index e77e1eb..4a90d9e 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -1727,11 +1727,11 @@ void reset_counter(void);
 int save_counter(int newval);
 void *expand(size_t headroom);
 int new_opt6(int opt);
-void *put_opt6(void *data, size_t len);
+void *put_opt6(const void *data, size_t len);
 void put_opt6_long(unsigned int val);
 void put_opt6_short(unsigned int val);
 void put_opt6_char(unsigned int val);
-void put_opt6_string(char *s);
+void put_opt6_string(const char *s);
 #endif
 
 /* radv.c */
diff --git a/src/outpacket.c b/src/outpacket.c
index da6f73c..e8d31d8 100644
--- a/src/outpacket.c
+++ b/src/outpacket.c
@@ -76,7 +76,7 @@ int new_opt6(int opt)
   return ret;
 }
 
-void *put_opt6(void *data, size_t len)
+void *put_opt6(const void *data, size_t len)
 {
   void *p;
 
@@ -110,7 +110,7 @@ void put_opt6_char(unsigned int val)
     *p = val;   
 }
 
-void put_opt6_string(char *s)
+void put_opt6_string(const char *s)
 {
   put_opt6(s, strlen(s));
 }
diff --git a/src/rfc3315.c b/src/rfc3315.c
index f15bac9..2c9d9fa 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -37,8 +37,8 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
 			     struct in6_addr *client_addr, int is_unicast, time_t now);
 static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now);
 static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_opts);
-static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string);
-static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string);
+static void log6_packet(struct state *state, char *type, struct in6_addr *addr, const char *string);
+static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, const char *string);
 static void *opt6_find (void *opts, void *end, unsigned int search, unsigned int minsize);
 static void *opt6_next(void *opts, void *end);
 static unsigned int opt6_uint(unsigned char *opt, int offset, int size);
@@ -259,6 +259,14 @@ static int dhcp6_maybe_relay(struct state *state, void *inbuff, size_t sz,
   return 1;
 }
 
+static void put_opt6_status(unsigned int code, const char *message)
+{
+  int o1 = new_opt6(OPTION6_STATUS_CODE);
+  put_opt6_short(code);
+  put_opt6_string(message);
+  end_opt6(o1);
+}
+
 static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_t sz, int is_unicast, time_t now)
 {
   void *opt;
@@ -348,10 +356,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
     
     {  
       *outmsgtypep = DHCP6REPLY;
-      o1 = new_opt6(OPTION6_STATUS_CODE);
-      put_opt6_short(DHCP6USEMULTI);
-      put_opt6_string("Use multicast");
-      end_opt6(o1);
+      put_opt6_status(DHCP6USEMULTI, "Use multicast");
       return 1;
     }
 
@@ -694,7 +699,6 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 		    /* add address to output packet */
 		    add_address(state, c, lease_time, ia_option, &min_time, &req_addr, now);
 		    mark_context_used(state, &req_addr);
-		    get_context_tag(state, c);
 		    address_assigned = 1;
 		  }
 		else
@@ -716,7 +720,6 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 		  /* add address to output packet */
 		  add_address(state, c, lease_time, NULL, &min_time, &addr, now);
 		  mark_context_used(state, &addr);
-		  get_context_tag(state, c);
 		  address_assigned = 1;
 		}
 	    
@@ -729,7 +732,6 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 		  {
 		    add_address(state, c, c->lease_time, NULL, &min_time, &req_addr, now);
 		    mark_context_used(state, &req_addr);
-		    get_context_tag(state, c);
 		    address_assigned = 1;
 		  }
 	      }
@@ -740,7 +742,6 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 	      {
 		add_address(state, c, c->lease_time, NULL, &min_time, &addr, now);
 		mark_context_used(state, &addr);
-		get_context_tag(state, c);
 		address_assigned = 1;
 	      }
 	    
@@ -759,10 +760,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 		   from the client, the server MUST include the IA in the Reply message
 		   with no addresses in the IA and a Status Code option in the IA
 		   containing status code NoAddrsAvail. */
-		o1 = new_opt6(OPTION6_STATUS_CODE);
-		put_opt6_short(DHCP6NOADDRS);
-		put_opt6_string(_("address unavailable"));
-		end_opt6(o1);
+		put_opt6_status(DHCP6NOADDRS, _("address unavailable"));
 	      }
 	    
 	    end_ia(t1cntr, min_time, 0);
@@ -771,10 +769,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 
 	if (address_assigned) 
 	  {
-	    o1 = new_opt6(OPTION6_STATUS_CODE);
-	    put_opt6_short(DHCP6SUCCESS);
-	    put_opt6_string(_("success"));
-	    end_opt6(o1);
+	    put_opt6_status(DHCP6SUCCESS, _("success"));
 	    
 	    /* If --dhcp-authoritative is set, we can tell client not to wait for
 	       other possible servers */
@@ -785,9 +780,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 	  }
 	else
 	  {
-	    char *errmsg;
+	    const char *errmsg;
 	    /* no address, return error */
-	    o1 = new_opt6(OPTION6_STATUS_CODE);
 	    if (state->lease_allocate && ia_invalid)
 	      {
 		/* RFC 8415, Section 18.3.2:
@@ -795,16 +789,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 		   appropriate for the link to which the client is connected,
 		   the server MUST return the IA to the client with a Status
 		   Code option with the value NotOnLink. */
-		put_opt6_short(DHCP6NOTONLINK);
 		errmsg = _("not on link");
+		put_opt6_status(DHCP6NOTONLINK, errmsg);
 	      }
 	    else
 	      {
-		put_opt6_short(DHCP6NOADDRS);
 		errmsg = _("no addresses available");
+		put_opt6_status(DHCP6NOADDRS, errmsg);
 	      }
-	    put_opt6_string(errmsg);
-	    end_opt6(o1);
 
 	    /* Some clients will ask repeatedly when we're not giving
 	       out addresses because we're in stateless mode. Avoid spamming
@@ -871,10 +863,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 		    if (!dynamic && !config_ok)
 		      {
 			/* Static range, not configured. */
-			o1 = new_opt6(OPTION6_STATUS_CODE);
-			put_opt6_short(DHCP6NOADDRS);
-			put_opt6_string(_("address unavailable"));
-			end_opt6(o1);
+			put_opt6_status(DHCP6NOADDRS, _("address unavailable"));
 		      }
 		    else if (!check_address(state, &req_addr))
 		      {
@@ -895,17 +884,13 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 			  lease_time = config->lease_time;
 
 			add_address(state, dynamic, lease_time, ia_option, &min_time, &req_addr, now);
-			get_context_tag(state, dynamic);
 			address_assigned = 1;
 		      }
 		  }
 		else 
 		  {
 		    /* requested address not on the correct link */
-		    o1 = new_opt6(OPTION6_STATUS_CODE);
-		    put_opt6_short(DHCP6NOTONLINK);
-		    put_opt6_string(_("not on link"));
-		    end_opt6(o1);
+		    put_opt6_status(DHCP6NOTONLINK, _("not on link"));
 		  }
 	      }
 	 
@@ -914,20 +899,13 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 	  }
 
 	if (address_assigned) 
-	  {
-	    o1 = new_opt6(OPTION6_STATUS_CODE);
-	    put_opt6_short(DHCP6SUCCESS);
-	    put_opt6_string(_("success"));
-	    end_opt6(o1);
-	  }
+	  put_opt6_status(DHCP6SUCCESS, _("success"));
 	else
-	  { 
+	  {
+	    const char *errmsg = _("no addresses available");
 	    /* no address, return error */
-	    o1 = new_opt6(OPTION6_STATUS_CODE);
-	    put_opt6_short(DHCP6NOADDRS);
-	    put_opt6_string(_("no addresses available"));
-	    end_opt6(o1);
-	    log6_packet(state, "DHCPREPLY", NULL, _("no addresses available"));
+	    put_opt6_status(DHCP6NOADDRS, errmsg);
+	    log6_packet(state, "DHCPREPLY", NULL, errmsg);
 	  }
 
 	tagif = add_options(state, 0);
@@ -990,12 +968,9 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 			t1cntr = 0;
 			
 			log6_packet(state, "DHCPREPLY", &req_addr, _("lease not found"));
-			
-			o1 = new_opt6(OPTION6_STATUS_CODE);
-			put_opt6_short(DHCP6NOBINDING);
-			put_opt6_string(_("no binding found"));
-			end_opt6(o1);
-			
+
+			put_opt6_status(DHCP6NOBINDING, _("no binding found"));
+
 			preferred_time = valid_time = 0;
 			break;
 		      }
@@ -1059,10 +1034,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 	if (!address_assigned && msg_type == DHCP6REBIND)
 	  { 
 	    /* can't create lease for any address, return error */
-	    o1 = new_opt6(OPTION6_STATUS_CODE);
-	    put_opt6_short(DHCP6NOADDRS);
-	    put_opt6_string(_("no addresses available"));
-	    end_opt6(o1);
+	    put_opt6_status(DHCP6NOADDRS, _("no addresses available"));
 	  }
 	
 	tagif = add_options(state, 0);
@@ -1093,11 +1065,9 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 		
 		if (!address6_valid(state->context, &req_addr, tagif, 1))
 		  {
-		    o1 = new_opt6(OPTION6_STATUS_CODE);
-		    put_opt6_short(DHCP6NOTONLINK);
-		    put_opt6_string(_("confirm failed"));
-		    end_opt6(o1);
-		    log6_quiet(state, "DHCPREPLY", &req_addr, _("confirm failed"));
+		    const char *errmsg = _("confirm failed");
+		    put_opt6_status(DHCP6NOTONLINK, errmsg);
+		    log6_quiet(state, "DHCPREPLY", &req_addr, errmsg);
 		    return 1;
 		  }
 
@@ -1110,10 +1080,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 	if (!good_addr)
 	  return 0;
 
-	o1 = new_opt6(OPTION6_STATUS_CODE);
-	put_opt6_short(DHCP6SUCCESS );
-	put_opt6_string(_("all addresses still on link"));
-	end_opt6(o1);
+	put_opt6_status(DHCP6SUCCESS, _("all addresses still on link"));
 	break;
     }
       
@@ -1192,20 +1159,13 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 	    
 	    if (made_ia)
 	      {
-		o1 = new_opt6(OPTION6_STATUS_CODE);
-		put_opt6_short(DHCP6NOBINDING);
-		put_opt6_string(_("no binding found"));
-		end_opt6(o1);
-		
+		put_opt6_status(DHCP6NOBINDING, _("no binding found"));
 		end_opt6(o);
 	      }
 	  }
-	
-	o1 = new_opt6(OPTION6_STATUS_CODE);
-	put_opt6_short(DHCP6SUCCESS);
-	put_opt6_string(_("release received"));
-	end_opt6(o1);
-	
+
+	put_opt6_status(DHCP6SUCCESS, _("release received"));
+
 	break;
       }
 
@@ -1273,21 +1233,14 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 	    
 	    if (made_ia)
 	      {
-		o1 = new_opt6(OPTION6_STATUS_CODE);
-		put_opt6_short(DHCP6NOBINDING);
-		put_opt6_string(_("no binding found"));
-		end_opt6(o1);
-		
+		put_opt6_status(DHCP6NOBINDING, _("no binding found"));
 		end_opt6(o);
 	      }
 	    
 	  }
 
 	/* We must answer with 'success' in global section anyway */
-	o1 = new_opt6(OPTION6_STATUS_CODE);
-	put_opt6_short(DHCP6SUCCESS);
-	put_opt6_string(_("success"));
-	end_opt6(o1);
+	put_opt6_status(DHCP6SUCCESS, _("success"));
 	break;
       }
 
@@ -1689,7 +1642,7 @@ static void add_address(struct state *state, struct dhcp_context *context, unsig
     }
 
   log6_quiet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", addr, state->hostname);
-
+  get_context_tag(state, context);
 }
 
 static void mark_context_used(struct state *state, struct in6_addr *addr)
@@ -2020,13 +1973,13 @@ static void log6_opts(int nest, unsigned int xid, void *start_opts, void *end_op
     }
 }		 
  
-static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, char *string)
+static void log6_quiet(struct state *state, char *type, struct in6_addr *addr, const char *string)
 {
   if (option_bool(OPT_LOG_OPTS) || !option_bool(OPT_QUIET_DHCP6))
     log6_packet(state, type, addr, string);
 }
 
-static void log6_packet(struct state *state, char *type, struct in6_addr *addr, char *string)
+static void log6_packet(struct state *state, char *type, struct in6_addr *addr, const char *string)
 {
   int clid_len = state->clid_len;
 
-- 
2.34.1

From ade172eab396d3d898ddb7e6b05ba5c4ac00f159 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemen...@redhat.com>
Date: Fri, 17 Sep 2021 20:12:21 +0200
Subject: [PATCH 1/3] Offer alternative DHCPv6 address if requested is taken

In some cases multiple requests might arrive from single DUID. It may
happen just one address is offered to different IAID requests. When
the first request confirms lease, another would be offered alternative
address instead of address in use error.

Includes check on such Rapid commit equivalents and returns NotOnLink
error, required by RFC 8145, if requested address were not on any
supported prefix.
---
 src/rfc3315.c | 39 ++++++++++++++++++++++++++++-----------
 1 file changed, 28 insertions(+), 11 deletions(-)

diff --git a/src/rfc3315.c b/src/rfc3315.c
index 236df47..f15bac9 100644
--- a/src/rfc3315.c
+++ b/src/rfc3315.c
@@ -614,7 +614,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
       
     case DHCP6SOLICIT:
       {
-      	int address_assigned = 0;
+	int address_assigned = 0, ia_invalid = 0;
 	/* tags without all prefix-class tags */
 	struct dhcp_netid *solicit_tags;
 	struct dhcp_context *c;
@@ -697,6 +697,8 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 		    get_context_tag(state, c);
 		    address_assigned = 1;
 		  }
+		else
+		  ia_invalid++;
 	      }
 	    
 	    /* Suggest configured address(es) */
@@ -782,11 +784,26 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 	    tagif = add_options(state, 0);
 	  }
 	else
-	  { 
+	  {
+	    char *errmsg;
 	    /* no address, return error */
 	    o1 = new_opt6(OPTION6_STATUS_CODE);
-	    put_opt6_short(DHCP6NOADDRS);
-	    put_opt6_string(_("no addresses available"));
+	    if (state->lease_allocate && ia_invalid)
+	      {
+		/* RFC 8415, Section 18.3.2:
+		   If any of the prefixes of the included addresses are not
+		   appropriate for the link to which the client is connected,
+		   the server MUST return the IA to the client with a Status
+		   Code option with the value NotOnLink. */
+		put_opt6_short(DHCP6NOTONLINK);
+		errmsg = _("not on link");
+	      }
+	    else
+	      {
+		put_opt6_short(DHCP6NOADDRS);
+		errmsg = _("no addresses available");
+	      }
+	    put_opt6_string(errmsg);
 	    end_opt6(o1);
 
 	    /* Some clients will ask repeatedly when we're not giving
@@ -795,7 +812,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 	    for (c = state->context; c; c = c->current)
 	      if (!(c->flags & CONTEXT_RA_STATELESS))
 		{
-		  log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, _("no addresses available"));
+		  log6_packet(state, state->lease_allocate ? "DHCPREPLY" : "DHCPADVERTISE", NULL, errmsg);
 		  break;
 		}
 	  }
@@ -831,7 +848,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 		 /* If we get a request with an IA_*A without addresses, treat it exactly like
 		    a SOLICT with rapid commit set. */
 		 save_counter(start);
-		 goto request_no_address; 
+		 goto request_no_address;
 	       }
 
 	    o = build_ia(state, &t1cntr);
@@ -861,11 +878,11 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
 		      }
 		    else if (!check_address(state, &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);
+			/* Address leased to another DUID/IAID.
+			   Find another address for the client, treat it exactly like
+			   a SOLICT with rapid commit set. */
+			save_counter(start);
+			goto request_no_address;
 		      } 
 		    else 
 		      {
-- 
2.34.1

_______________________________________________
Dnsmasq-discuss mailing list
Dnsmasq-discuss@lists.thekelleys.org.uk
https://lists.thekelleys.org.uk/cgi-bin/mailman/listinfo/dnsmasq-discuss

Reply via email to