diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 30 |
1 files changed, 18 insertions, 12 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 8d00a9d77f01..bd4cf175ff10 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -481,17 +481,23 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, | |||
481 | } | 481 | } |
482 | #endif | 482 | #endif |
483 | 483 | ||
484 | #define BACKTRACK() \ | 484 | #define BACKTRACK(saddr) \ |
485 | if (rt == &ip6_null_entry && flags & RT6_F_STRICT) { \ | 485 | do { \ |
486 | while ((fn = fn->parent) != NULL) { \ | 486 | if (rt == &ip6_null_entry) { \ |
487 | if (fn->fn_flags & RTN_TL_ROOT) { \ | 487 | struct fib6_node *pn; \ |
488 | dst_hold(&rt->u.dst); \ | 488 | while (fn) { \ |
489 | goto out; \ | 489 | if (fn->fn_flags & RTN_TL_ROOT) \ |
490 | goto out; \ | ||
491 | pn = fn->parent; \ | ||
492 | if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn) \ | ||
493 | fn = fib6_lookup(pn->subtree, NULL, saddr); \ | ||
494 | else \ | ||
495 | fn = pn; \ | ||
496 | if (fn->fn_flags & RTN_RTINFO) \ | ||
497 | goto restart; \ | ||
490 | } \ | 498 | } \ |
491 | if (fn->fn_flags & RTN_RTINFO) \ | ||
492 | goto restart; \ | ||
493 | } \ | 499 | } \ |
494 | } | 500 | } while(0) |
495 | 501 | ||
496 | static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table, | 502 | static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table, |
497 | struct flowi *fl, int flags) | 503 | struct flowi *fl, int flags) |
@@ -504,7 +510,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table, | |||
504 | restart: | 510 | restart: |
505 | rt = fn->leaf; | 511 | rt = fn->leaf; |
506 | rt = rt6_device_match(rt, fl->oif, flags & RT6_F_STRICT); | 512 | rt = rt6_device_match(rt, fl->oif, flags & RT6_F_STRICT); |
507 | BACKTRACK(); | 513 | BACKTRACK(&fl->fl6_src); |
508 | dst_hold(&rt->u.dst); | 514 | dst_hold(&rt->u.dst); |
509 | out: | 515 | out: |
510 | read_unlock_bh(&table->tb6_lock); | 516 | read_unlock_bh(&table->tb6_lock); |
@@ -638,7 +644,7 @@ restart_2: | |||
638 | 644 | ||
639 | restart: | 645 | restart: |
640 | rt = rt6_select(&fn->leaf, fl->iif, strict | reachable); | 646 | rt = rt6_select(&fn->leaf, fl->iif, strict | reachable); |
641 | BACKTRACK(); | 647 | BACKTRACK(&fl->fl6_src); |
642 | if (rt == &ip6_null_entry || | 648 | if (rt == &ip6_null_entry || |
643 | rt->rt6i_flags & RTF_CACHE) | 649 | rt->rt6i_flags & RTF_CACHE) |
644 | goto out; | 650 | goto out; |
@@ -733,7 +739,7 @@ restart_2: | |||
733 | 739 | ||
734 | restart: | 740 | restart: |
735 | rt = rt6_select(&fn->leaf, fl->oif, strict | reachable); | 741 | rt = rt6_select(&fn->leaf, fl->oif, strict | reachable); |
736 | BACKTRACK(); | 742 | BACKTRACK(&fl->fl6_src); |
737 | if (rt == &ip6_null_entry || | 743 | if (rt == &ip6_null_entry || |
738 | rt->rt6i_flags & RTF_CACHE) | 744 | rt->rt6i_flags & RTF_CACHE) |
739 | goto out; | 745 | goto out; |