1 /**
2  * @file
3  *
4  * ACD IPv4 Address Conflict Detection
5  *
6  * This is an IPv4 address conflict detection implementation for the lwIP TCP/IP
7  * stack. It aims to be conform to RFC5227.
8  *
9  * @defgroup acd ACD
10  * @ingroup ip4
11  * ACD related functions
12  * USAGE:
13  *
14  * define @ref LWIP_ACD 1 in your lwipopts.h
15  * Options:
16  * ACD_TMR_INTERVAL msecs,
17  *   I recommend a value of 100. The value must divide 1000 with a remainder almost 0.
18  *   Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....
19  *
20  * For fixed IP:
21  * - call acd_start after selecting an IP address. The caller will be informed
22  *   on conflict status via the callback function.
23  *
24  * With AUTOIP:
25  * - will be called from the autoip module. No extra's needed.
26  *
27  * With DHCP:
28  * - enable LWIP_DHCP_DOES_ACD_CHECK. Then it will be called from the dhcp module.
29  *   No extra's needed.
30  */
31 
32 /*
33  *
34  * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>
35  * Copyright (c) 2018 Jasper Verschueren <jasper.verschueren@apart-audio.com>
36  * All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without modification,
39  * are permitted provided that the following conditions are met:
40  *
41  * 1. Redistributions of source code must retain the above copyright notice,
42  *    this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright notice,
44  *    this list of conditions and the following disclaimer in the documentation
45  *    and/or other materials provided with the distribution.
46  * 3. The name of the author may not be used to endorse or promote products
47  *    derived from this software without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
50  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
51  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
52  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
53  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
54  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
56  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
57  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
58  * OF SUCH DAMAGE.
59  *
60  * Author: Jasper Verschueren <jasper.verschueren@apart-audio.com>
61  * Author: Dominik Spies <kontakt@dspies.de>
62  */
63 
64 #include "lwip/opt.h"
65 
66 /* don't build if not configured for use in lwipopts.h */
67 #if LWIP_IPV4 && LWIP_ACD
68 
69 #include <string.h>
70 
71 #include "lwip/acd.h"
72 #include "lwip/prot/acd.h"
73 
74 #define ACD_FOREACH(acd, acd_list) for ((acd) = acd_list; (acd) != NULL; (acd) = (acd)->next)
75 
76 #define ACD_TICKS_PER_SECOND  (1000 / ACD_TMR_INTERVAL)
77 
78 /* Define good random function (LWIP_RAND) in lwipopts.h */
79 #ifdef LWIP_RAND
80 #define LWIP_ACD_RAND(netif, acd)    LWIP_RAND()
81 #else /* LWIP_RAND */
82 #ifdef LWIP_AUTOIP_RAND
83 #include "lwip/autoip.h"
84 #define LWIP_ACD_RAND(netif, acd)    LWIP_AUTOIP_RAND(netif) /* for backwards compatibility */
85 #else
86 #define LWIP_ACD_RAND(netif, acd) ((((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
87                                     ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \
88                                     ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \
89                                     ((u32_t)((netif->hwaddr[4]) & 0xff))) + \
90                                     (acd->sent_num))
91 #endif /* LWIP_AUTOIP_RAND */
92 #endif /* LWIP_RAND */
93 
94 
95 #define ACD_RANDOM_PROBE_WAIT(netif, acd) (LWIP_ACD_RAND(netif, acd) % \
96                                     (PROBE_WAIT * ACD_TICKS_PER_SECOND))
97 
98 #define ACD_RANDOM_PROBE_INTERVAL(netif, acd) ((LWIP_ACD_RAND(netif, acd) % \
99                                     ((PROBE_MAX - PROBE_MIN) * ACD_TICKS_PER_SECOND)) + \
100                                     (PROBE_MIN * ACD_TICKS_PER_SECOND ))
101 
102 /* Function definitions */
103 static void acd_restart(struct netif *netif, struct acd *acd);
104 static void acd_handle_arp_conflict(struct netif *netif, struct acd *acd);
105 static void acd_put_in_passive_mode(struct netif *netif, struct acd *acd);
106 
107 /**
108  * @ingroup acd
109  * Add ACD client to the client list and initialize callback function
110  *
111  * @param netif                 network interface on which to start the acd
112  *                              client
113  * @param acd                   acd module to be added to the list
114  * @param acd_conflict_callback callback to be called when conflict information
115  *                              is available
116  */
117 err_t
acd_add(struct netif * netif,struct acd * acd,acd_conflict_callback_t acd_conflict_callback)118 acd_add(struct netif *netif, struct acd *acd,
119          acd_conflict_callback_t acd_conflict_callback)
120 {
121   struct acd *acd2;
122 
123   /* Set callback */
124   LWIP_ASSERT_CORE_LOCKED();
125   LWIP_ASSERT("acd_conflict_callback != NULL", acd_conflict_callback != NULL);
126   acd->acd_conflict_callback = acd_conflict_callback;
127 
128   /* Check if the acd struct is already added */
129   for (acd2 = netif->acd_list; acd2 != NULL; acd2 = acd2->next) {
130     if (acd2 == acd) {
131       LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
132                   ("acd_add(): acd already added to list\n"));
133       return ERR_OK;
134     }
135   }
136 
137   /* add acd struct to the list */
138   acd->next = netif->acd_list;
139   netif->acd_list = acd;
140 
141   return ERR_OK;
142 }
143 
144 /**
145  * @ingroup acd
146  * Remvoe ACD client from the client list
147  *
148  * @param netif network interface from which to remove the acd client
149  * @param acd   acd module to be removed from the list
150  */
151 void
acd_remove(struct netif * netif,struct acd * acd)152 acd_remove(struct netif *netif, struct acd *acd)
153 {
154   struct acd *acd2, *prev = NULL;
155 
156   LWIP_ASSERT_CORE_LOCKED();
157 
158   for (acd2 = netif->acd_list; acd2 != NULL; acd2 = acd2->next) {
159     if (acd2 == acd) {
160       if (prev) {
161         prev->next = acd->next;
162       } else {
163         netif->acd_list = acd->next;
164       }
165       return;
166     }
167     prev = acd2;
168   }
169   LWIP_ASSERT(("acd_remove(): acd not on list\n"), 0);
170 }
171 
172 
173 /**
174  * @ingroup acd
175  * Start ACD client
176  *
177  * @param netif   network interface on which to start the acd client
178  * @param acd     acd module to start
179  * @param ipaddr  ip address to perform acd on
180  */
181 err_t
acd_start(struct netif * netif,struct acd * acd,ip4_addr_t ipaddr)182 acd_start(struct netif *netif, struct acd *acd, ip4_addr_t ipaddr)
183 {
184   err_t result = ERR_OK;
185 
186   LWIP_UNUSED_ARG(netif);
187   LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
188               ("acd_start(netif=%p) %c%c%"U16_F"\n",
189               (void *)netif, netif->name[0],
190                netif->name[1], (u16_t)netif->num));
191 
192   /* init probing state */
193   acd->sent_num = 0;
194   acd->lastconflict = 0;
195   ip4_addr_copy(acd->ipaddr, ipaddr);
196   acd->state = ACD_STATE_PROBE_WAIT;
197 
198   acd->ttw = (u16_t)(ACD_RANDOM_PROBE_WAIT(netif, acd));
199 
200   return result;
201 }
202 
203 /**
204  * @ingroup acd
205  * Stop ACD client
206  *
207  * @param acd   acd module to stop
208  */
209 err_t
acd_stop(struct acd * acd)210 acd_stop(struct acd *acd)
211 {
212   LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("acd_stop\n"));
213 
214   if (acd != NULL) {
215     acd->state = ACD_STATE_OFF;
216   }
217   return ERR_OK;
218 }
219 
220 /**
221  * @ingroup acd
222  * Inform the ACD modules when the link goes down
223  *
224  * @param netif network interface on which to inform the ACD clients
225  */
226 void
acd_network_changed_link_down(struct netif * netif)227 acd_network_changed_link_down(struct netif *netif)
228 {
229   struct acd *acd;
230   /* loop over the acd's*/
231   ACD_FOREACH(acd, netif->acd_list) {
232     acd_stop(acd);
233   }
234 }
235 
236 /**
237  * Has to be called in loop every ACD_TMR_INTERVAL milliseconds
238  */
239 void
acd_tmr(void)240 acd_tmr(void)
241 {
242   struct netif *netif;
243   struct acd *acd;
244   /* loop through netif's */
245   NETIF_FOREACH(netif) {
246     ACD_FOREACH(acd, netif->acd_list) {
247       if (acd->lastconflict > 0) {
248         acd->lastconflict--;
249       }
250 
251       LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE,
252                   ("acd_tmr() ACD-State: %"U16_F", ttw=%"U16_F"\n",
253                    (u16_t)(acd->state), acd->ttw));
254 
255       if (acd->ttw > 0) {
256         acd->ttw--;
257       }
258 
259       switch (acd->state) {
260         case ACD_STATE_PROBE_WAIT:
261         case ACD_STATE_PROBING:
262           if (acd->ttw == 0) {
263             acd->state = ACD_STATE_PROBING;
264             etharp_acd_probe(netif, &acd->ipaddr);
265             LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE,
266                         ("acd_tmr() PROBING Sent Probe\n"));
267             acd->sent_num++;
268             if (acd->sent_num >= PROBE_NUM) {
269               /* Switch to ANNOUNCE_WAIT: last probe is sent*/
270               acd->state = ACD_STATE_ANNOUNCE_WAIT;
271 
272               acd->sent_num = 0;
273 
274               /* calculate time to wait before announcing */
275               acd->ttw = (u16_t)(ANNOUNCE_WAIT * ACD_TICKS_PER_SECOND);
276             } else {
277               /* calculate time to wait to next probe */
278               acd->ttw = (u16_t)(ACD_RANDOM_PROBE_INTERVAL(netif, acd));
279             }
280           }
281           break;
282 
283         case ACD_STATE_ANNOUNCE_WAIT:
284         case ACD_STATE_ANNOUNCING:
285           if (acd->ttw == 0) {
286             if (acd->sent_num == 0) {
287               acd->state = ACD_STATE_ANNOUNCING;
288 
289               /* reset conflict count to ensure fast re-probing after announcing */
290               acd->num_conflicts = 0;
291 
292               LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
293                     ("acd_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
294                      ip4_addr1_16(&acd->ipaddr), ip4_addr2_16(&acd->ipaddr),
295                      ip4_addr3_16(&acd->ipaddr), ip4_addr4_16(&acd->ipaddr)));
296             }
297 
298             etharp_acd_announce(netif, &acd->ipaddr);
299             LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE,
300                         ("acd_tmr() ANNOUNCING Sent Announce\n"));
301             acd->ttw = ANNOUNCE_INTERVAL * ACD_TICKS_PER_SECOND;
302             acd->sent_num++;
303 
304             if (acd->sent_num >= ANNOUNCE_NUM) {
305               acd->state = ACD_STATE_ONGOING;
306               acd->sent_num = 0;
307               acd->ttw = 0;
308               LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
309                     ("acd_tmr(): changing state to ONGOING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
310                      ip4_addr1_16(&acd->ipaddr), ip4_addr2_16(&acd->ipaddr),
311                      ip4_addr3_16(&acd->ipaddr), ip4_addr4_16(&acd->ipaddr)));
312 
313               /* finally, let acd user know that the address is good and can be used */
314               acd->acd_conflict_callback(netif, ACD_IP_OK);
315             }
316           }
317           break;
318 
319         case ACD_STATE_RATE_LIMIT:
320           if (acd->ttw == 0) {
321             /* acd should be stopped because ipaddr isn't valid any more */
322             acd_stop(acd);
323             /* let the acd user (after rate limit interval) know that their is
324              * a conflict detected. So it can restart the address acquiring
325              * process.*/
326             acd->acd_conflict_callback(netif, ACD_RESTART_CLIENT);
327           }
328           break;
329 
330         default:
331           /* nothing to do in other states */
332           break;
333       }
334     }
335   }
336 }
337 
338 /**
339  * Restarts the acd module
340  *
341  * The number of conflicts is increased and the upper layer is informed.
342  */
343 static void
acd_restart(struct netif * netif,struct acd * acd)344 acd_restart(struct netif *netif, struct acd *acd)
345 {
346   /* increase conflict counter. */
347   acd->num_conflicts++;
348 
349   /* Decline the address */
350   acd->acd_conflict_callback(netif, ACD_DECLINE);
351 
352   /* if we tried more then MAX_CONFLICTS we must limit our rate for
353    * acquiring and probing addresses. compliant to RFC 5227 Section 2.1.1 */
354   if (acd->num_conflicts >= MAX_CONFLICTS) {
355     acd->state = ACD_STATE_RATE_LIMIT;
356     acd->ttw = (u16_t)(RATE_LIMIT_INTERVAL * ACD_TICKS_PER_SECOND);
357     LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
358                 ("acd_restart(): rate limiting initiated. too many conflicts\n"));
359   }
360   else {
361     /* acd should be stopped because ipaddr isn't valid any more */
362     acd_stop(acd);
363     /* let the acd user know right away that their is a conflict detected.
364      * So it can restart the address acquiring process. */
365     acd->acd_conflict_callback(netif, ACD_RESTART_CLIENT);
366   }
367 }
368 
369 /**
370  * Handles every incoming ARP Packet, called by etharp_input().
371  *
372  * @param netif network interface to use for acd processing
373  * @param hdr   Incoming ARP packet
374  */
375 void
acd_arp_reply(struct netif * netif,struct etharp_hdr * hdr)376 acd_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
377 {
378   struct acd *acd;
379   ip4_addr_t sipaddr, dipaddr;
380   struct eth_addr netifaddr;
381   SMEMCPY(netifaddr.addr, netif->hwaddr, ETH_HWADDR_LEN);
382 
383   /* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support
384    * compilers without structure packing (not using structure copy which
385    * breaks strict-aliasing rules).
386    */
387   IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr);
388   IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&dipaddr, &hdr->dipaddr);
389 
390   LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE, ("acd_arp_reply()\n"));
391 
392   /* loop over the acd's*/
393   ACD_FOREACH(acd, netif->acd_list) {
394     switch(acd->state) {
395       case ACD_STATE_OFF:
396       case ACD_STATE_RATE_LIMIT:
397       default:
398         /* do nothing */
399         break;
400 
401       case ACD_STATE_PROBE_WAIT:
402       case ACD_STATE_PROBING:
403       case ACD_STATE_ANNOUNCE_WAIT:
404         /* RFC 5227 Section 2.1.1:
405          * from beginning to after ANNOUNCE_WAIT seconds we have a conflict if
406          * ip.src == ipaddr (someone is already using the address)
407          * OR
408          * ip.dst == ipaddr && hw.src != own hwaddr (someone else is probing it)
409          */
410         if ((ip4_addr_eq(&sipaddr, &acd->ipaddr)) ||
411             (ip4_addr_isany_val(sipaddr) &&
412              ip4_addr_eq(&dipaddr, &acd->ipaddr) &&
413              !eth_addr_eq(&netifaddr, &hdr->shwaddr))) {
414           LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
415                       ("acd_arp_reply(): Probe Conflict detected\n"));
416           acd_restart(netif, acd);
417         }
418         break;
419 
420       case ACD_STATE_ANNOUNCING:
421       case ACD_STATE_ONGOING:
422       case ACD_STATE_PASSIVE_ONGOING:
423         /* RFC 5227 Section 2.4:
424          * in any state we have a conflict if
425          * ip.src == ipaddr && hw.src != own hwaddr (someone is using our address)
426          */
427         if (ip4_addr_eq(&sipaddr, &acd->ipaddr) &&
428             !eth_addr_eq(&netifaddr, &hdr->shwaddr)) {
429           LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
430                       ("acd_arp_reply(): Conflicting ARP-Packet detected\n"));
431           acd_handle_arp_conflict(netif, acd);
432         }
433         break;
434     }
435   }
436 }
437 
438 /**
439  * Handle a IP address conflict after an ARP conflict detection
440  */
441 static void
acd_handle_arp_conflict(struct netif * netif,struct acd * acd)442 acd_handle_arp_conflict(struct netif *netif, struct acd *acd)
443 {
444   /* RFC5227, 2.4 "Ongoing Address Conflict Detection and Address Defense"
445      allows three options where:
446      a) means retreat on the first conflict,
447      b) allows to keep an already configured address when having only one
448         conflict in DEFEND_INTERVAL seconds and
449      c) the host will not give up it's address and defend it indefinitely
450 
451      We use option b) when the acd module represents the netif address, since it
452      helps to improve the chance that one of the two conflicting hosts may be
453      able to retain its address. while we are flexible enough to help network
454      performance
455 
456      We use option a) when the acd module does not represent the netif address,
457      since we cannot have the acd module announcing or restarting. This
458      situation occurs for the LL acd module when a routable address is used on
459      the netif but the LL address is still open in the background. */
460 
461   if (acd->state == ACD_STATE_PASSIVE_ONGOING) {
462     /* Immediately back off on a conflict. */
463     LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
464       ("acd_handle_arp_conflict(): conflict when we are in passive mode -> back off\n"));
465     acd_stop(acd);
466     acd->acd_conflict_callback(netif, ACD_DECLINE);
467   }
468   else {
469     if (acd->lastconflict > 0) {
470       /* retreat, there was a conflicting ARP in the last DEFEND_INTERVAL seconds */
471       LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
472         ("acd_handle_arp_conflict(): conflict within DEFEND_INTERVAL -> retreating\n"));
473 
474       /* Active TCP sessions are aborted when removing the ip address but a bad
475        * connection was inevitable anyway with conflicting hosts */
476        acd_restart(netif, acd);
477     } else {
478       LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
479           ("acd_handle_arp_conflict(): we are defending, send ARP Announce\n"));
480       etharp_acd_announce(netif, &acd->ipaddr);
481       acd->lastconflict = DEFEND_INTERVAL * ACD_TICKS_PER_SECOND;
482     }
483   }
484 }
485 
486 /**
487  * Put the acd module in passive ongoing conflict detection.
488  */
489 static void
acd_put_in_passive_mode(struct netif * netif,struct acd * acd)490 acd_put_in_passive_mode(struct netif *netif, struct acd *acd)
491 {
492   switch(acd->state) {
493     case ACD_STATE_OFF:
494     case ACD_STATE_PASSIVE_ONGOING:
495     default:
496       /* do nothing */
497       break;
498 
499     case ACD_STATE_PROBE_WAIT:
500     case ACD_STATE_PROBING:
501     case ACD_STATE_ANNOUNCE_WAIT:
502     case ACD_STATE_RATE_LIMIT:
503       acd_stop(acd);
504       acd->acd_conflict_callback(netif, ACD_DECLINE);
505       break;
506 
507     case ACD_STATE_ANNOUNCING:
508     case ACD_STATE_ONGOING:
509       acd->state = ACD_STATE_PASSIVE_ONGOING;
510       LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
511         ("acd_put_in_passive_mode()\n"));
512       break;
513   }
514 }
515 
516 /**
517  * @ingroup acd
518  * Inform the ACD modules of address changes
519  *
520  * @param netif     network interface on which the address is changing
521  * @param old_addr  old ip address
522  * @param new_addr  new ip address
523  */
524 void
acd_netif_ip_addr_changed(struct netif * netif,const ip_addr_t * old_addr,const ip_addr_t * new_addr)525 acd_netif_ip_addr_changed(struct netif *netif, const ip_addr_t *old_addr,
526                           const ip_addr_t *new_addr)
527 {
528   struct acd *acd;
529 
530   LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
531     ("acd_netif_ip_addr_changed(): Address changed\n"));
532 
533   LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
534     ("acd_netif_ip_addr_changed(): old address = %s\n", ipaddr_ntoa(old_addr)));
535   LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
536     ("acd_netif_ip_addr_changed(): new address = %s\n", ipaddr_ntoa(new_addr)));
537 
538   /* If we change from ANY to an IP or from an IP to ANY we do nothing */
539   if (ip_addr_isany(old_addr) || ip_addr_isany(new_addr)) {
540     return;
541   }
542 
543   ACD_FOREACH(acd, netif->acd_list) {
544     /* Find ACD module of old address */
545     if(ip4_addr_eq(&acd->ipaddr, ip_2_ip4(old_addr))) {
546       /* Did we change from a LL address to a routable address? */
547       if (ip_addr_islinklocal(old_addr) && !ip_addr_islinklocal(new_addr)) {
548         LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
549           ("acd_netif_ip_addr_changed(): changed from LL to routable address\n"));
550         /* Put the module in passive conflict detection mode */
551         acd_put_in_passive_mode(netif, acd);
552       }
553     }
554   }
555 }
556 
557 #endif /* LWIP_IPV4 && LWIP_ACD */
558