xref: /btstack/3rd-party/lwip/core/src/core/ipv4/acd.c (revision 97dc5e692c7d94a280158af58036a0efee5b0e56)
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 <[email protected]>
35  * Copyright (c) 2018 Jasper Verschueren <[email protected]>
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 <[email protected]>
61  * Author: Dominik Spies <[email protected]>
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  * Start ACD client
147  *
148  * @param netif   network interface on which to start the acd client
149  * @param acd     acd module to start
150  * @param ipaddr  ip address to perform acd on
151  */
152 err_t
acd_start(struct netif * netif,struct acd * acd,ip4_addr_t ipaddr)153 acd_start(struct netif *netif, struct acd *acd, ip4_addr_t ipaddr)
154 {
155   err_t result = ERR_OK;
156 
157   LWIP_UNUSED_ARG(netif);
158   LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
159               ("acd_start(netif=%p) %c%c%"U16_F"\n",
160               (void *)netif, netif->name[0],
161                netif->name[1], (u16_t)netif->num));
162 
163   /* init probing state */
164   acd->sent_num = 0;
165   acd->lastconflict = 0;
166   ip4_addr_copy(acd->ipaddr, ipaddr);
167   acd->state = ACD_STATE_PROBE_WAIT;
168 
169   acd->ttw = (u16_t)(ACD_RANDOM_PROBE_WAIT(netif, acd));
170 
171   return result;
172 }
173 
174 /**
175  * @ingroup acd
176  * Stop ACD client
177  *
178  * @param acd   acd module to stop
179  */
180 err_t
acd_stop(struct acd * acd)181 acd_stop(struct acd *acd)
182 {
183   LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("acd_stop\n"));
184 
185   if (acd != NULL) {
186     acd->state = ACD_STATE_OFF;
187   }
188   return ERR_OK;
189 }
190 
191 /**
192  * @ingroup acd
193  * Inform the ACD modules when the link goes down
194  *
195  * @param netif network interface on which to inform the ACD clients
196  */
197 void
acd_network_changed_link_down(struct netif * netif)198 acd_network_changed_link_down(struct netif *netif)
199 {
200   struct acd *acd;
201   /* loop over the acd's*/
202   ACD_FOREACH(acd, netif->acd_list) {
203     acd_stop(acd);
204   }
205 }
206 
207 /**
208  * Has to be called in loop every ACD_TMR_INTERVAL milliseconds
209  */
210 void
acd_tmr(void)211 acd_tmr(void)
212 {
213   struct netif *netif;
214   struct acd *acd;
215   /* loop through netif's */
216   NETIF_FOREACH(netif) {
217     ACD_FOREACH(acd, netif->acd_list) {
218       if (acd->lastconflict > 0) {
219         acd->lastconflict--;
220       }
221 
222       LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE,
223                   ("acd_tmr() ACD-State: %"U16_F", ttw=%"U16_F"\n",
224                    (u16_t)(acd->state), acd->ttw));
225 
226       if (acd->ttw > 0) {
227         acd->ttw--;
228       }
229 
230       switch (acd->state) {
231         case ACD_STATE_PROBE_WAIT:
232         case ACD_STATE_PROBING:
233           if (acd->ttw == 0) {
234             acd->state = ACD_STATE_PROBING;
235             etharp_acd_probe(netif, &acd->ipaddr);
236             LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE,
237                         ("acd_tmr() PROBING Sent Probe\n"));
238             acd->sent_num++;
239             if (acd->sent_num >= PROBE_NUM) {
240               /* Switch to ANNOUNCE_WAIT: last probe is sent*/
241               acd->state = ACD_STATE_ANNOUNCE_WAIT;
242 
243               acd->sent_num = 0;
244 
245               /* calculate time to wait before announcing */
246               acd->ttw = (u16_t)(ANNOUNCE_WAIT * ACD_TICKS_PER_SECOND);
247             } else {
248               /* calculate time to wait to next probe */
249               acd->ttw = (u16_t)(ACD_RANDOM_PROBE_INTERVAL(netif, acd));
250             }
251           }
252           break;
253 
254         case ACD_STATE_ANNOUNCE_WAIT:
255         case ACD_STATE_ANNOUNCING:
256           if (acd->ttw == 0) {
257             if (acd->sent_num == 0) {
258               acd->state = ACD_STATE_ANNOUNCING;
259 
260               /* let acd user know that the address is good and can be used */
261               acd->acd_conflict_callback(netif, ACD_IP_OK);
262 
263               LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
264                     ("acd_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
265                      ip4_addr1_16(&acd->ipaddr), ip4_addr2_16(&acd->ipaddr),
266                      ip4_addr3_16(&acd->ipaddr), ip4_addr4_16(&acd->ipaddr)));
267             }
268 
269             etharp_acd_announce(netif, &acd->ipaddr);
270             LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE,
271                         ("acd_tmr() ANNOUNCING Sent Announce\n"));
272             acd->ttw = ANNOUNCE_INTERVAL * ACD_TICKS_PER_SECOND;
273             acd->sent_num++;
274 
275             if (acd->sent_num >= ANNOUNCE_NUM) {
276               acd->state = ACD_STATE_ONGOING;
277               acd->sent_num = 0;
278               acd->ttw = 0;
279               LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
280                     ("acd_tmr(): changing state to ONGOING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
281                      ip4_addr1_16(&acd->ipaddr), ip4_addr2_16(&acd->ipaddr),
282                      ip4_addr3_16(&acd->ipaddr), ip4_addr4_16(&acd->ipaddr)));
283             }
284           }
285           break;
286 
287         case ACD_STATE_RATE_LIMIT:
288           if (acd->ttw == 0) {
289             /* acd should be stopped because ipaddr isn't valid any more */
290             acd_stop(acd);
291             /* let the acd user (after rate limit interval) know that their is
292              * a conflict detected. So it can restart the address acquiring
293              * process.*/
294             acd->acd_conflict_callback(netif, ACD_RESTART_CLIENT);
295           }
296           break;
297 
298         default:
299           /* nothing to do in other states */
300           break;
301       }
302     }
303   }
304 }
305 
306 /**
307  * Restarts the acd module
308  *
309  * The number of conflicts is increased and the upper layer is informed.
310  */
311 static void
acd_restart(struct netif * netif,struct acd * acd)312 acd_restart(struct netif *netif, struct acd *acd)
313 {
314   /* increase conflict counter. */
315   acd->num_conflicts++;
316 
317   /* Decline the address */
318   acd->acd_conflict_callback(netif, ACD_DECLINE);
319 
320   /* if we tried more then MAX_CONFLICTS we must limit our rate for
321    * acquiring and probing addresses. compliant to RFC 5227 Section 2.1.1 */
322   if (acd->num_conflicts > MAX_CONFLICTS) {
323     acd->state = ACD_STATE_RATE_LIMIT;
324     acd->ttw = (u16_t)(RATE_LIMIT_INTERVAL * ACD_TICKS_PER_SECOND);
325     LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
326                 ("acd_restart(): rate limiting initiated. too many conflicts\n"));
327   }
328   else {
329     /* acd should be stopped because ipaddr isn't valid any more */
330     acd_stop(acd);
331     /* let the acd user know right away that their is a conflict detected.
332      * So it can restart the address acquiring process. */
333     acd->acd_conflict_callback(netif, ACD_RESTART_CLIENT);
334   }
335 }
336 
337 /**
338  * Handles every incoming ARP Packet, called by etharp_input().
339  *
340  * @param netif network interface to use for acd processing
341  * @param hdr   Incoming ARP packet
342  */
343 void
acd_arp_reply(struct netif * netif,struct etharp_hdr * hdr)344 acd_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
345 {
346   struct acd *acd;
347   ip4_addr_t sipaddr, dipaddr;
348   struct eth_addr netifaddr;
349   SMEMCPY(netifaddr.addr, netif->hwaddr, ETH_HWADDR_LEN);
350 
351   /* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support
352    * compilers without structure packing (not using structure copy which
353    * breaks strict-aliasing rules).
354    */
355   IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr);
356   IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&dipaddr, &hdr->dipaddr);
357 
358   LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE, ("acd_arp_reply()\n"));
359 
360   /* loop over the acd's*/
361   ACD_FOREACH(acd, netif->acd_list) {
362     switch(acd->state) {
363       case ACD_STATE_OFF:
364       case ACD_STATE_RATE_LIMIT:
365       default:
366         /* do nothing */
367         break;
368 
369       case ACD_STATE_PROBE_WAIT:
370       case ACD_STATE_PROBING:
371       case ACD_STATE_ANNOUNCE_WAIT:
372         /* RFC 5227 Section 2.1.1:
373          * from beginning to after ANNOUNCE_WAIT seconds we have a conflict if
374          * ip.src == ipaddr (someone is already using the address)
375          * OR
376          * ip.dst == ipaddr && hw.src != own hwaddr (someone else is probing it)
377          */
378         if ((ip4_addr_cmp(&sipaddr, &acd->ipaddr)) ||
379             (ip4_addr_isany_val(sipaddr) &&
380              ip4_addr_cmp(&dipaddr, &acd->ipaddr) &&
381              !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
382           LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
383                       ("acd_arp_reply(): Probe Conflict detected\n"));
384           acd_restart(netif, acd);
385         }
386         break;
387 
388       case ACD_STATE_ANNOUNCING:
389       case ACD_STATE_ONGOING:
390       case ACD_STATE_PASSIVE_ONGOING:
391         /* RFC 5227 Section 2.4:
392          * in any state we have a conflict if
393          * ip.src == ipaddr && hw.src != own hwaddr (someone is using our address)
394          */
395         if (ip4_addr_cmp(&sipaddr, &acd->ipaddr) &&
396             !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
397           LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
398                       ("acd_arp_reply(): Conflicting ARP-Packet detected\n"));
399           acd_handle_arp_conflict(netif, acd);
400         }
401         break;
402     }
403   }
404 }
405 
406 /**
407  * Handle a IP address conflict after an ARP conflict detection
408  */
409 static void
acd_handle_arp_conflict(struct netif * netif,struct acd * acd)410 acd_handle_arp_conflict(struct netif *netif, struct acd *acd)
411 {
412   /* RFC5227, 2.4 "Ongoing Address Conflict Detection and Address Defense"
413      allows three options where:
414      a) means retreat on the first conflict,
415      b) allows to keep an already configured address when having only one
416         conflict in DEFEND_INTERVAL seconds and
417      c) the host will not give up it's address and defend it indefinitely
418 
419      We use option b) when the acd module represents the netif address, since it
420      helps to improve the chance that one of the two conflicting hosts may be
421      able to retain its address. while we are flexible enough to help network
422      performance
423 
424      We use option a) when the acd module does not represent the netif address,
425      since we cannot have the acd module announcing or restarting. This
426      situation occurs for the LL acd module when a routable address is used on
427      the netif but the LL address is still open in the background. */
428 
429   if (acd->state == ACD_STATE_PASSIVE_ONGOING) {
430     /* Imediatly back off on a conflict. */
431     LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
432       ("acd_handle_arp_conflict(): conflict when we are in passive mode -> back off\n"));
433     acd_stop(acd);
434     acd->acd_conflict_callback(netif, ACD_DECLINE);
435   }
436   else {
437     if (acd->lastconflict > 0) {
438       /* retreat, there was a conflicting ARP in the last DEFEND_INTERVAL seconds */
439       LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
440         ("acd_handle_arp_conflict(): conflict within DEFEND_INTERVAL -> retreating\n"));
441 
442       /* Active TCP sessions are aborted when removing the ip address but a bad
443        * connection was inevitable anyway with conflicting hosts */
444        acd_restart(netif, acd);
445     } else {
446       LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
447           ("acd_handle_arp_conflict(): we are defending, send ARP Announce\n"));
448       etharp_acd_announce(netif, &acd->ipaddr);
449       acd->lastconflict = DEFEND_INTERVAL * ACD_TICKS_PER_SECOND;
450     }
451   }
452 }
453 
454 /**
455  * Put the acd module in passive ongoing conflict detection.
456  */
457 static void
acd_put_in_passive_mode(struct netif * netif,struct acd * acd)458 acd_put_in_passive_mode(struct netif *netif, struct acd *acd)
459 {
460   switch(acd->state) {
461     case ACD_STATE_OFF:
462     case ACD_STATE_PASSIVE_ONGOING:
463     default:
464       /* do nothing */
465       break;
466 
467     case ACD_STATE_PROBE_WAIT:
468     case ACD_STATE_PROBING:
469     case ACD_STATE_ANNOUNCE_WAIT:
470     case ACD_STATE_RATE_LIMIT:
471       acd_stop(acd);
472       acd->acd_conflict_callback(netif, ACD_DECLINE);
473       break;
474 
475     case ACD_STATE_ANNOUNCING:
476     case ACD_STATE_ONGOING:
477       acd->state = ACD_STATE_PASSIVE_ONGOING;
478       LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
479         ("acd_put_in_passive_mode()\n"));
480       break;
481   }
482 }
483 
484 /**
485  * @ingroup acd
486  * Inform the ACD modules of address changes
487  *
488  * @param netif     network interface on which the address is changing
489  * @param old_addr  old ip address
490  * @param new_addr  new ip address
491  */
492 void
acd_netif_ip_addr_changed(struct netif * netif,const ip_addr_t * old_addr,const ip_addr_t * new_addr)493 acd_netif_ip_addr_changed(struct netif *netif, const ip_addr_t *old_addr,
494                           const ip_addr_t *new_addr)
495 {
496   struct acd *acd;
497 
498   LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
499     ("acd_netif_ip_addr_changed(): Address changed\n"));
500 
501   LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
502     ("acd_netif_ip_addr_changed(): old address = %s\n", ipaddr_ntoa(old_addr)));
503   LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
504     ("acd_netif_ip_addr_changed(): new address = %s\n", ipaddr_ntoa(new_addr)));
505 
506   /* If we change from ANY to an IP or from an IP to ANY we do nothing */
507   if (ip_addr_isany(old_addr) || ip_addr_isany(new_addr)) {
508     return;
509   }
510 
511   ACD_FOREACH(acd, netif->acd_list) {
512     /* Find ACD module of old address */
513     if(ip4_addr_cmp(&acd->ipaddr, ip_2_ip4(old_addr))) {
514       /* Did we change from a LL address to a routable address? */
515       if (ip_addr_islinklocal(old_addr) && !ip_addr_islinklocal(new_addr)) {
516         LWIP_DEBUGF(ACD_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
517           ("acd_netif_ip_addr_changed(): changed from LL to routable address\n"));
518         /* Put the module in passive conflict detection mode */
519         acd_put_in_passive_mode(netif, acd);
520       }
521     }
522   }
523 }
524 
525 #endif /* LWIP_IPV4 && LWIP_ACD */
526