Skip to content

Commit 5fdd723

Browse files
author
Mika Leppänen
committed
Corrections to lwip ipv6 neighbor discovery
Merged lwip 2.0.2 stable path 1 from https://github.com/ARMmbed/lwip Patch allows lwip to do autonomous address configuration for prefixes that are not on-link. ad7cf16 Add David's IPv6 improvements to CHANGELOG af9d783 Fix (bogus) MSVC 2010 warning about uninitialized variable usage in ip6.c It's wrong because the variables are initialized during first loop iteration due to best_addr == NULL 68358d7 nd6: cull destination cache on router removal 7323fa1 nd6: some work on basic RFC 4861 compliance 10eb2ca ip6: improve source address selection 6c06ecd ip6/nd6: route using on-link prefixes, not addresses 9f1714d nd6: improve router selection 2486b41 netif: more ip6 state changes invoke status callback 519d809 nd6: fix Duplicate Address Detection 9f3c6dd nd6: check link status before sending packets 8c761a2 nd6: improve address autoconfiguration support
1 parent 316c875 commit 5fdd723

File tree

8 files changed

+563
-261
lines changed

8 files changed

+563
-261
lines changed

features/FEATURE_LWIP/lwip-interface/lwip/CHANGELOG

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ HISTORY
1515

1616
++ Bugfixes:
1717

18+
2017-01-11: David van Moolenbroek
19+
* Lots of IPv6 related fixes and improvements
20+
1821
2017-03-08
1922
* tcp: do not keep sending SYNs when getting ACKs
2023

features/FEATURE_LWIP/lwip-interface/lwip/src/core/ipv6/lwip_ip6.c

Lines changed: 85 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
* this is a tricky case because with multiple netifs, link-local addresses only have
7373
* meaning within a particular subnet/link.
7474
* 3) tries to match the destination subnet to a configured address
75-
* 4) tries to find a router
75+
* 4) tries to find a router-announced route
7676
* 5) tries to match the source address to the netif
7777
* 6) returns the default netif, if configured
7878
*
@@ -134,22 +134,29 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
134134
}
135135
#endif
136136

137-
/* See if the destination subnet matches a configured address. */
137+
/* See if the destination subnet matches a configured address. In accordance
138+
* with RFC 5942, dynamically configured addresses do not have an implied
139+
* local subnet, and thus should be considered /128 assignments. However, as
140+
* such, the destination address may still match a local address, and so we
141+
* still need to check for exact matches here. By (lwIP) policy, statically
142+
* configured addresses do always have an implied local /64 subnet. */
138143
for (netif = netif_list; netif != NULL; netif = netif->next) {
139144
if (!netif_is_up(netif) || !netif_is_link_up(netif)) {
140145
continue;
141146
}
142147
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
143148
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
144-
ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) {
149+
ip6_addr_netcmp(dest, netif_ip6_addr(netif, i)) &&
150+
(netif_ip6_addr_isstatic(netif, i) ||
151+
ip6_addr_nethostcmp(dest, netif_ip6_addr(netif, i)))) {
145152
return netif;
146153
}
147154
}
148155
}
149156

150-
/* Get the netif for a suitable router. */
157+
/* Get the netif for a suitable router-announced route. */
151158
netif = nd6_find_route(dest);
152-
if ((netif != NULL) && netif_is_up(netif) && netif_is_link_up(netif)) {
159+
if (netif != NULL) {
153160
return netif;
154161
}
155162

@@ -194,9 +201,22 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
194201

195202
/**
196203
* @ingroup ip6
197-
* Select the best IPv6 source address for a given destination
198-
* IPv6 address. Loosely follows RFC 3484. "Strong host" behavior
199-
* is assumed.
204+
* Select the best IPv6 source address for a given destination IPv6 address.
205+
*
206+
* This implementation follows RFC 6724 Sec. 5 to the following extent:
207+
* - Rules 1, 2, 3: fully implemented
208+
* - Rules 4, 5, 5.5: not applicable
209+
* - Rule 6: not implemented
210+
* - Rule 7: not applicable
211+
* - Rule 8: limited to "prefer /64 subnet match over non-match"
212+
*
213+
* For Rule 2, we deliberately deviate from RFC 6724 Sec. 3.1 by considering
214+
* ULAs to be of smaller scope than global addresses, to avoid that a preferred
215+
* ULA is picked over a deprecated global address when given a global address
216+
* as destination, as that would likely result in broken two-way communication.
217+
*
218+
* As long as temporary addresses are not supported (as used in Rule 7), a
219+
* proper implementation of Rule 8 would obviate the need to implement Rule 6.
200220
*
201221
* @param netif the netif on which to send a packet
202222
* @param dest the destination we are trying to reach
@@ -206,73 +226,72 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
206226
const ip_addr_t *
207227
ip6_select_source_address(struct netif *netif, const ip6_addr_t *dest)
208228
{
209-
const ip_addr_t *src = NULL;
210-
u8_t i;
211-
212-
/* If dest is link-local, choose a link-local source. */
213-
if (ip6_addr_islinklocal(dest) || ip6_addr_ismulticast_linklocal(dest) || ip6_addr_ismulticast_iflocal(dest)) {
214-
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
215-
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
216-
ip6_addr_islinklocal(netif_ip6_addr(netif, i))) {
217-
return netif_ip_addr6(netif, i);
218-
}
219-
}
229+
const ip_addr_t *best_addr;
230+
const ip6_addr_t *cand_addr;
231+
s8_t dest_scope, cand_scope;
232+
s8_t best_scope = IP6_MULTICAST_SCOPE_RESERVED;
233+
u8_t i, cand_pref, cand_bits;
234+
u8_t best_pref = 0;
235+
u8_t best_bits = 0;
236+
237+
/* Start by determining the scope of the given destination address. These
238+
* tests are hopefully (roughly) in order of likeliness to match. */
239+
if (ip6_addr_isglobal(dest)) {
240+
dest_scope = IP6_MULTICAST_SCOPE_GLOBAL;
241+
} else if (ip6_addr_islinklocal(dest) || ip6_addr_isloopback(dest)) {
242+
dest_scope = IP6_MULTICAST_SCOPE_LINK_LOCAL;
243+
} else if (ip6_addr_isuniquelocal(dest)) {
244+
dest_scope = IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL;
245+
} else if (ip6_addr_ismulticast(dest)) {
246+
dest_scope = ip6_addr_multicast_scope(dest);
247+
} else if (ip6_addr_issitelocal(dest)) {
248+
dest_scope = IP6_MULTICAST_SCOPE_SITE_LOCAL;
249+
} else {
250+
/* no match, consider scope global */
251+
dest_scope = IP6_MULTICAST_SCOPE_GLOBAL;
220252
}
221253

222-
/* Choose a site-local with matching prefix. */
223-
if (ip6_addr_issitelocal(dest) || ip6_addr_ismulticast_sitelocal(dest)) {
224-
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
225-
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
226-
ip6_addr_issitelocal(netif_ip6_addr(netif, i)) &&
227-
ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) {
228-
return netif_ip_addr6(netif, i);
229-
}
230-
}
231-
}
254+
best_addr = NULL;
232255

233-
/* Choose a unique-local with matching prefix. */
234-
if (ip6_addr_isuniquelocal(dest) || ip6_addr_ismulticast_orglocal(dest)) {
235-
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
236-
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
237-
ip6_addr_isuniquelocal(netif_ip6_addr(netif, i)) &&
238-
ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) {
239-
return netif_ip_addr6(netif, i);
240-
}
256+
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
257+
/* Consider only valid (= preferred and deprecated) addresses. */
258+
if (!ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
259+
continue;
241260
}
242-
}
243-
244-
/* Choose a global with best matching prefix. */
245-
if (ip6_addr_isglobal(dest) || ip6_addr_ismulticast_global(dest)) {
246-
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
247-
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
248-
ip6_addr_isglobal(netif_ip6_addr(netif, i))) {
249-
if (src == NULL) {
250-
src = netif_ip_addr6(netif, i);
251-
}
252-
else {
253-
/* Replace src only if we find a prefix match. */
254-
/* @todo find longest matching prefix. */
255-
if ((!(ip6_addr_netcmp(ip_2_ip6(src), dest))) &&
256-
ip6_addr_netcmp(netif_ip6_addr(netif, i), dest)) {
257-
src = netif_ip_addr6(netif, i);
258-
}
259-
}
260-
}
261+
/* Determine the scope of this candidate address. Same ordering idea. */
262+
cand_addr = netif_ip6_addr(netif, i);
263+
if (ip6_addr_isglobal(cand_addr)) {
264+
cand_scope = IP6_MULTICAST_SCOPE_GLOBAL;
265+
} else if (ip6_addr_islinklocal(cand_addr)) {
266+
cand_scope = IP6_MULTICAST_SCOPE_LINK_LOCAL;
267+
} else if (ip6_addr_isuniquelocal(cand_addr)) {
268+
cand_scope = IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL;
269+
} else if (ip6_addr_issitelocal(cand_addr)) {
270+
cand_scope = IP6_MULTICAST_SCOPE_SITE_LOCAL;
271+
} else {
272+
/* no match, treat as low-priority global scope */
273+
cand_scope = IP6_MULTICAST_SCOPE_RESERVEDF;
261274
}
262-
if (src != NULL) {
263-
return src;
275+
cand_pref = ip6_addr_ispreferred(netif_ip6_addr_state(netif, i));
276+
/* @todo compute the actual common bits, for longest matching prefix. */
277+
cand_bits = ip6_addr_netcmp(cand_addr, dest); /* just 1 or 0 for now */
278+
if (cand_bits && ip6_addr_nethostcmp(cand_addr, dest)) {
279+
return netif_ip_addr6(netif, i); /* Rule 1 */
264280
}
265-
}
266-
267-
/* Last resort: see if arbitrary prefix matches. */
268-
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
269-
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
270-
ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) {
271-
return netif_ip_addr6(netif, i);
281+
if ((best_addr == NULL) || /* no alternative yet */
282+
((cand_scope < best_scope) && (cand_scope >= dest_scope)) ||
283+
((cand_scope > best_scope) && (best_scope < dest_scope)) || /* Rule 2 */
284+
((cand_scope == best_scope) && ((cand_pref > best_pref) || /* Rule 3 */
285+
((cand_pref == best_pref) && (cand_bits > best_bits))))) { /* Rule 8 */
286+
/* We found a new "winning" candidate. */
287+
best_addr = netif_ip_addr6(netif, i);
288+
best_scope = cand_scope;
289+
best_pref = cand_pref;
290+
best_bits = cand_bits;
272291
}
273292
}
274293

275-
return NULL;
294+
return best_addr; /* may be NULL */
276295
}
277296

278297
#if LWIP_IPV6_FORWARD

0 commit comments

Comments
 (0)