Browse Source

[ipv6] Automatically choose source for link-local and multicast destinations

When transmitting to a link-local or multicast destination address,
use the network device's link-local address as the source address if
no explicit source address has been specified.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 11 years ago
parent
commit
1aa67eba16
1 changed files with 34 additions and 30 deletions
  1. 34
    30
      src/net/ipv6.c

+ 34
- 30
src/net/ipv6.c View File

93
  *
93
  *
94
  * @v miniroute		Routing table entry
94
  * @v miniroute		Routing table entry
95
  * @v address		IPv6 address
95
  * @v address		IPv6 address
96
- * @ret is_local	Address is within this entry's local network
96
+ * @ret is_on_link	Address is within this entry's local network
97
  */
97
  */
98
-static int ipv6_is_local ( struct ipv6_miniroute *miniroute,
99
-			   struct in6_addr *address ) {
98
+static int ipv6_is_on_link ( struct ipv6_miniroute *miniroute,
99
+			     struct in6_addr *address ) {
100
 	unsigned int i;
100
 	unsigned int i;
101
 
101
 
102
 	for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) /
102
 	for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) /
192
 static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
192
 static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
193
 					    struct in6_addr **dest ) {
193
 					    struct in6_addr **dest ) {
194
 	struct ipv6_miniroute *miniroute;
194
 	struct ipv6_miniroute *miniroute;
195
-	int local;
196
 
195
 
197
 	/* Find first usable route in routing table */
196
 	/* Find first usable route in routing table */
198
 	list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
197
 	list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
201
 		if ( ! netdev_is_open ( miniroute->netdev ) )
200
 		if ( ! netdev_is_open ( miniroute->netdev ) )
202
 			continue;
201
 			continue;
203
 
202
 
204
-		/* For link-local addresses, skip devices that are not
205
-		 * the specified network device.
206
-		 */
207
-		if ( IN6_IS_ADDR_LINKLOCAL ( *dest ) &&
208
-		     ( miniroute->netdev->index != scope_id ) )
209
-			continue;
203
+		if ( IN6_IS_ADDR_LINKLOCAL ( *dest ) ||
204
+		     IN6_IS_ADDR_MULTICAST ( *dest ) ) {
210
 
205
 
211
-		/* Skip non-gateway devices for which the prefix does
212
-		 * not match.
213
-		 */
214
-		local = ipv6_is_local ( miniroute, *dest );
215
-		if ( ! ( local || miniroute->has_router ) )
216
-			continue;
206
+			/* If destination is non-global, and the scope ID
207
+			 * matches this network device, then use this route.
208
+			 */
209
+			if ( miniroute->netdev->index == scope_id )
210
+				return miniroute;
217
 
211
 
218
-		/* Update next hop if applicable */
219
-		if ( ! local )
220
-			*dest = &miniroute->router;
212
+		} else {
221
 
213
 
222
-		return miniroute;
214
+			/* If destination is an on-link global
215
+			 * address, then use this route.
216
+			 */
217
+			if ( ipv6_is_on_link ( miniroute, *dest ) )
218
+				return miniroute;
219
+
220
+			/* If destination is an off-link global
221
+			 * address, and we have a default gateway,
222
+			 * then use this route.
223
+			 */
224
+			if ( miniroute->has_router ) {
225
+				*dest = &miniroute->router;
226
+				return miniroute;
227
+			}
228
+		}
223
 	}
229
 	}
224
 
230
 
225
 	return NULL;
231
 	return NULL;
363
 	struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest );
369
 	struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest );
364
 	struct ipv6_miniroute *miniroute;
370
 	struct ipv6_miniroute *miniroute;
365
 	struct ipv6_header *iphdr;
371
 	struct ipv6_header *iphdr;
372
+	struct in6_addr *src = NULL;
366
 	struct in6_addr *next_hop;
373
 	struct in6_addr *next_hop;
367
 	uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
374
 	uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
368
 	const void *ll_dest;
375
 	const void *ll_dest;
381
 
388
 
382
 	/* Use routing table to identify next hop and transmitting netdev */
389
 	/* Use routing table to identify next hop and transmitting netdev */
383
 	next_hop = &iphdr->dest;
390
 	next_hop = &iphdr->dest;
384
-	if ( sin6_src ) {
385
-		memcpy ( &iphdr->src, &sin6_src->sin6_addr,
386
-			 sizeof ( iphdr->src ) );
387
-	}
388
-	if ( ( ! IN6_IS_ADDR_MULTICAST ( next_hop ) ) &&
389
-	     ( ( miniroute = ipv6_route ( sin6_dest->sin6_scope_id,
390
-					  &next_hop ) ) != NULL ) ) {
391
-		memcpy ( &iphdr->src, &miniroute->address,
392
-			 sizeof ( iphdr->src ) );
391
+	if ( ( miniroute = ipv6_route ( sin6_dest->sin6_scope_id,
392
+					&next_hop ) ) != NULL ) {
393
+		src = &miniroute->address;
393
 		netdev = miniroute->netdev;
394
 		netdev = miniroute->netdev;
394
 	}
395
 	}
395
 	if ( ! netdev ) {
396
 	if ( ! netdev ) {
398
 		rc = -ENETUNREACH;
399
 		rc = -ENETUNREACH;
399
 		goto err;
400
 		goto err;
400
 	}
401
 	}
402
+	if ( sin6_src )
403
+		src = &sin6_src->sin6_addr;
404
+	memcpy ( &iphdr->src, src, sizeof ( iphdr->src ) );
401
 
405
 
402
 	/* Fix up checksums */
406
 	/* Fix up checksums */
403
 	if ( trans_csum ) {
407
 	if ( trans_csum ) {
897
 
901
 
898
 	/* Delete any existing SLAAC miniroutes for this prefix */
902
 	/* Delete any existing SLAAC miniroutes for this prefix */
899
 	list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) {
903
 	list_for_each_entry_safe ( miniroute, tmp, &ipv6_miniroutes, list ) {
900
-		if ( ipv6_is_local ( miniroute, &address ) )
904
+		if ( ipv6_is_on_link ( miniroute, &address ) )
901
 			del_ipv6_miniroute ( miniroute );
905
 			del_ipv6_miniroute ( miniroute );
902
 	}
906
 	}
903
 
907
 

Loading…
Cancel
Save