ReactOS 0.4.16-dev-338-g34e76ad
acd.c
Go to the documentation of this file.
1
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 */
103static void acd_restart(struct netif *netif, struct acd *acd);
104static void acd_handle_arp_conflict(struct netif *netif, struct acd *acd);
105static void acd_put_in_passive_mode(struct netif *netif, struct acd *acd);
106
117err_t
118acd_add(struct netif *netif, struct acd *acd,
119 acd_conflict_callback_t acd_conflict_callback)
120{
121 struct acd *acd2;
122
123 /* Set callback */
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) {
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
151void
152acd_remove(struct netif *netif, struct acd *acd)
153{
154 struct acd *acd2, *prev = NULL;
155
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
181err_t
182acd_start(struct netif *netif, struct acd *acd, ip4_addr_t ipaddr)
183{
185
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
209err_t
210acd_stop(struct acd *acd)
211{
213
214 if (acd != NULL) {
215 acd->state = ACD_STATE_OFF;
216 }
217 return ERR_OK;
218}
219
226void
227acd_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
239void
240acd_tmr(void)
241{
242 struct netif *netif;
243 struct acd *acd;
244 /* loop through netif's */
246 ACD_FOREACH(acd, netif->acd_list) {
247 if (acd->lastconflict > 0) {
248 acd->lastconflict--;
249 }
250
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) {
262 if (acd->ttw == 0) {
263 acd->state = ACD_STATE_PROBING;
264 etharp_acd_probe(netif, &acd->ipaddr);
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
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
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);
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;
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
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
343static void
344acd_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);
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
375void
376acd_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:
397 default:
398 /* do nothing */
399 break;
400
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))) {
415 ("acd_arp_reply(): Probe Conflict detected\n"));
416 acd_restart(netif, acd);
417 }
418 break;
419
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)) {
430 ("acd_arp_reply(): Conflicting ARP-Packet detected\n"));
431 acd_handle_arp_conflict(netif, acd);
432 }
433 break;
434 }
435 }
436}
437
441static void
442acd_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. */
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 */
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 {
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
489static void
490acd_put_in_passive_mode(struct netif *netif, struct acd *acd)
491{
492 switch(acd->state) {
493 case ACD_STATE_OFF:
495 default:
496 /* do nothing */
497 break;
498
503 acd_stop(acd);
504 acd->acd_conflict_callback(netif, ACD_DECLINE);
505 break;
506
509 acd->state = ACD_STATE_PASSIVE_ONGOING;
511 ("acd_put_in_passive_mode()\n"));
512 break;
513 }
514}
515
524void
525acd_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
531 ("acd_netif_ip_addr_changed(): Address changed\n"));
532
534 ("acd_netif_ip_addr_changed(): old address = %s\n", ipaddr_ntoa(old_addr)));
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)) {
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 */
#define NULL
Definition: types.h:112
#define U16_F
Definition: cc.h:19
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:158
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
GLuint64EXT * result
Definition: glext.h:11304
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:373
uint16_t u16_t
Definition: arch.h:127
#define LWIP_DBG_STATE
Definition: debug.h:85
#define LWIP_DBG_LEVEL_WARNING
Definition: debug.h:55
#define LWIP_DBG_TRACE
Definition: debug.h:83
s8_t err_t
Definition: err.h:96
@ ERR_OK
Definition: err.h:55
#define ACD_DEBUG
Definition: opt.h:3540
#define LWIP_ASSERT_CORE_LOCKED()
Definition: opt.h:227
#define SMEMCPY(dst, src, len)
Definition: opt.h:145
#define ip_addr_isany(ipaddr)
Definition: ip_addr.h:377
#define ip_addr_islinklocal(ipaddr)
Definition: ip_addr.h:380
ip6_addr_t ip_addr_t
Definition: ip_addr.h:344
#define ipaddr_ntoa(ipaddr)
Definition: ip_addr.h:385
char hdr[14]
Definition: iptest.cpp:33
#define IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(dest, src)
Definition: etharp.h:71
#define eth_addr_eq(addr1, addr2)
Definition: ethernet.h:121
#define ETH_HWADDR_LEN
Definition: ethernet.h:51
#define NETIF_FOREACH(netif)
Definition: netif.h:424
#define MAX_CONFLICTS
Definition: acd.h:53
#define ANNOUNCE_WAIT
Definition: acd.h:52
#define ANNOUNCE_NUM
Definition: acd.h:50
#define PROBE_NUM
Definition: acd.h:49
#define RATE_LIMIT_INTERVAL
Definition: acd.h:54
#define DEFEND_INTERVAL
Definition: acd.h:55
#define ANNOUNCE_INTERVAL
Definition: acd.h:51
@ ACD_RESTART_CLIENT
Definition: acd.h:83
@ ACD_IP_OK
Definition: acd.h:82
@ ACD_DECLINE
Definition: acd.h:84
@ ACD_STATE_PROBE_WAIT
Definition: acd.h:62
@ ACD_STATE_PASSIVE_ONGOING
Definition: acd.h:75
@ ACD_STATE_ANNOUNCE_WAIT
Definition: acd.h:66
@ ACD_STATE_PROBING
Definition: acd.h:64
@ ACD_STATE_RATE_LIMIT
Definition: acd.h:78
@ ACD_STATE_ONGOING
Definition: acd.h:70
@ ACD_STATE_OFF
Definition: acd.h:60
@ ACD_STATE_ANNOUNCING
Definition: acd.h:68
struct define * next
Definition: compiler.c:65
Definition: netif.h:269
char name[2]
Definition: netif.h:356
u8_t num
Definition: netif.h:359
u8_t hwaddr[NETIF_MAX_HWADDR_LEN]
Definition: netif.h:350
struct netif * next
Definition: netif.h:272