72
72
* this is a tricky case because with multiple netifs, link-local addresses only have
73
73
* meaning within a particular subnet/link.
74
74
* 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
76
76
* 5) tries to match the source address to the netif
77
77
* 6) returns the default netif, if configured
78
78
*
@@ -134,22 +134,29 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
134
134
}
135
135
#endif
136
136
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. */
138
143
for (netif = netif_list ; netif != NULL ; netif = netif -> next ) {
139
144
if (!netif_is_up (netif ) || !netif_is_link_up (netif )) {
140
145
continue ;
141
146
}
142
147
for (i = 0 ; i < LWIP_IPV6_NUM_ADDRESSES ; i ++ ) {
143
148
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 )))) {
145
152
return netif ;
146
153
}
147
154
}
148
155
}
149
156
150
- /* Get the netif for a suitable router. */
157
+ /* Get the netif for a suitable router-announced route . */
151
158
netif = nd6_find_route (dest );
152
- if (( netif != NULL ) && netif_is_up ( netif ) && netif_is_link_up ( netif ) ) {
159
+ if (netif != NULL ) {
153
160
return netif ;
154
161
}
155
162
@@ -194,9 +201,22 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
194
201
195
202
/**
196
203
* @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.
200
220
*
201
221
* @param netif the netif on which to send a packet
202
222
* @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)
206
226
const ip_addr_t *
207
227
ip6_select_source_address (struct netif * netif , const ip6_addr_t * dest )
208
228
{
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 ;
220
252
}
221
253
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 ;
232
255
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 ;
241
260
}
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 ;
261
274
}
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 */
264
280
}
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 ;
272
291
}
273
292
}
274
293
275
- return NULL ;
294
+ return best_addr ; /* may be NULL */
276
295
}
277
296
278
297
#if LWIP_IPV6_FORWARD
@@ -1082,6 +1101,8 @@ ip6_debug_print(struct pbuf *p)
1082
1101
{
1083
1102
struct ip6_hdr * ip6hdr = (struct ip6_hdr * )p -> payload ;
1084
1103
1104
+ TRACE_TO_ASCII_HEX_DUMPF ("IP>" , IP6H_PLEN (ip6hdr ) + 40 , (char * ) ip6hdr );
1105
+
1085
1106
LWIP_DEBUGF (IP6_DEBUG , ("IPv6 header:\n" ));
1086
1107
LWIP_DEBUGF (IP6_DEBUG , ("+-------------------------------+\n" ));
1087
1108
LWIP_DEBUGF (IP6_DEBUG , ("| %2" U16_F " | %3" U16_F " | %7" U32_F " | (ver, class, flow)\n" ,
0 commit comments