|
@@ -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
|
|