Преглед изворни кода

[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 година
родитељ
комит
1aa67eba16
1 измењених фајлова са 34 додато и 30 уклоњено
  1. 34
    30
      src/net/ipv6.c

+ 34
- 30
src/net/ipv6.c Прегледај датотеку

@@ -93,10 +93,10 @@ int ipv6_has_addr ( struct net_device *netdev, struct in6_addr *addr ) {
93 93
  *
94 94
  * @v miniroute		Routing table entry
95 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 100
 	unsigned int i;
101 101
 
102 102
 	for ( i = 0 ; i < ( sizeof ( address->s6_addr32 ) /
@@ -192,7 +192,6 @@ static void del_ipv6_miniroute ( struct ipv6_miniroute *miniroute ) {
192 192
 static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
193 193
 					    struct in6_addr **dest ) {
194 194
 	struct ipv6_miniroute *miniroute;
195
-	int local;
196 195
 
197 196
 	/* Find first usable route in routing table */
198 197
 	list_for_each_entry ( miniroute, &ipv6_miniroutes, list ) {
@@ -201,25 +200,32 @@ static struct ipv6_miniroute * ipv6_route ( unsigned int scope_id,
201 200
 		if ( ! netdev_is_open ( miniroute->netdev ) )
202 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 231
 	return NULL;
@@ -363,6 +369,7 @@ static int ipv6_tx ( struct io_buffer *iobuf,
363 369
 	struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest );
364 370
 	struct ipv6_miniroute *miniroute;
365 371
 	struct ipv6_header *iphdr;
372
+	struct in6_addr *src = NULL;
366 373
 	struct in6_addr *next_hop;
367 374
 	uint8_t ll_dest_buf[MAX_LL_ADDR_LEN];
368 375
 	const void *ll_dest;
@@ -381,15 +388,9 @@ static int ipv6_tx ( struct io_buffer *iobuf,
381 388
 
382 389
 	/* Use routing table to identify next hop and transmitting netdev */
383 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 394
 		netdev = miniroute->netdev;
394 395
 	}
395 396
 	if ( ! netdev ) {
@@ -398,6 +399,9 @@ static int ipv6_tx ( struct io_buffer *iobuf,
398 399
 		rc = -ENETUNREACH;
399 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 406
 	/* Fix up checksums */
403 407
 	if ( trans_csum ) {
@@ -897,7 +901,7 @@ int ipv6_slaac ( struct net_device *netdev, struct in6_addr *prefix,
897 901
 
898 902
 	/* Delete any existing SLAAC miniroutes for this prefix */
899 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 905
 			del_ipv6_miniroute ( miniroute );
902 906
 	}
903 907
 

Loading…
Откажи
Сачувај