diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 46 |
1 files changed, 37 insertions, 9 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c979dd96d82a..f54e3a101098 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -476,6 +476,24 @@ out: | |||
476 | } | 476 | } |
477 | 477 | ||
478 | #ifdef CONFIG_IPV6_ROUTER_PREF | 478 | #ifdef CONFIG_IPV6_ROUTER_PREF |
479 | struct __rt6_probe_work { | ||
480 | struct work_struct work; | ||
481 | struct in6_addr target; | ||
482 | struct net_device *dev; | ||
483 | }; | ||
484 | |||
485 | static void rt6_probe_deferred(struct work_struct *w) | ||
486 | { | ||
487 | struct in6_addr mcaddr; | ||
488 | struct __rt6_probe_work *work = | ||
489 | container_of(w, struct __rt6_probe_work, work); | ||
490 | |||
491 | addrconf_addr_solict_mult(&work->target, &mcaddr); | ||
492 | ndisc_send_ns(work->dev, NULL, &work->target, &mcaddr, NULL); | ||
493 | dev_put(work->dev); | ||
494 | kfree(w); | ||
495 | } | ||
496 | |||
479 | static void rt6_probe(struct rt6_info *rt) | 497 | static void rt6_probe(struct rt6_info *rt) |
480 | { | 498 | { |
481 | struct neighbour *neigh; | 499 | struct neighbour *neigh; |
@@ -499,17 +517,23 @@ static void rt6_probe(struct rt6_info *rt) | |||
499 | 517 | ||
500 | if (!neigh || | 518 | if (!neigh || |
501 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { | 519 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { |
502 | struct in6_addr mcaddr; | 520 | struct __rt6_probe_work *work; |
503 | struct in6_addr *target; | ||
504 | 521 | ||
505 | if (neigh) { | 522 | work = kmalloc(sizeof(*work), GFP_ATOMIC); |
523 | |||
524 | if (neigh && work) | ||
506 | neigh->updated = jiffies; | 525 | neigh->updated = jiffies; |
526 | |||
527 | if (neigh) | ||
507 | write_unlock(&neigh->lock); | 528 | write_unlock(&neigh->lock); |
508 | } | ||
509 | 529 | ||
510 | target = (struct in6_addr *)&rt->rt6i_gateway; | 530 | if (work) { |
511 | addrconf_addr_solict_mult(target, &mcaddr); | 531 | INIT_WORK(&work->work, rt6_probe_deferred); |
512 | ndisc_send_ns(rt->dst.dev, NULL, target, &mcaddr, NULL); | 532 | work->target = rt->rt6i_gateway; |
533 | dev_hold(rt->dst.dev); | ||
534 | work->dev = rt->dst.dev; | ||
535 | schedule_work(&work->work); | ||
536 | } | ||
513 | } else { | 537 | } else { |
514 | out: | 538 | out: |
515 | write_unlock(&neigh->lock); | 539 | write_unlock(&neigh->lock); |
@@ -851,7 +875,6 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, | |||
851 | if (ort->rt6i_dst.plen != 128 && | 875 | if (ort->rt6i_dst.plen != 128 && |
852 | ipv6_addr_equal(&ort->rt6i_dst.addr, daddr)) | 876 | ipv6_addr_equal(&ort->rt6i_dst.addr, daddr)) |
853 | rt->rt6i_flags |= RTF_ANYCAST; | 877 | rt->rt6i_flags |= RTF_ANYCAST; |
854 | rt->rt6i_gateway = *daddr; | ||
855 | } | 878 | } |
856 | 879 | ||
857 | rt->rt6i_flags |= RTF_CACHE; | 880 | rt->rt6i_flags |= RTF_CACHE; |
@@ -1338,6 +1361,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
1338 | rt->dst.flags |= DST_HOST; | 1361 | rt->dst.flags |= DST_HOST; |
1339 | rt->dst.output = ip6_output; | 1362 | rt->dst.output = ip6_output; |
1340 | atomic_set(&rt->dst.__refcnt, 1); | 1363 | atomic_set(&rt->dst.__refcnt, 1); |
1364 | rt->rt6i_gateway = fl6->daddr; | ||
1341 | rt->rt6i_dst.addr = fl6->daddr; | 1365 | rt->rt6i_dst.addr = fl6->daddr; |
1342 | rt->rt6i_dst.plen = 128; | 1366 | rt->rt6i_dst.plen = 128; |
1343 | rt->rt6i_idev = idev; | 1367 | rt->rt6i_idev = idev; |
@@ -1873,7 +1897,10 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort, | |||
1873 | in6_dev_hold(rt->rt6i_idev); | 1897 | in6_dev_hold(rt->rt6i_idev); |
1874 | rt->dst.lastuse = jiffies; | 1898 | rt->dst.lastuse = jiffies; |
1875 | 1899 | ||
1876 | rt->rt6i_gateway = ort->rt6i_gateway; | 1900 | if (ort->rt6i_flags & RTF_GATEWAY) |
1901 | rt->rt6i_gateway = ort->rt6i_gateway; | ||
1902 | else | ||
1903 | rt->rt6i_gateway = *dest; | ||
1877 | rt->rt6i_flags = ort->rt6i_flags; | 1904 | rt->rt6i_flags = ort->rt6i_flags; |
1878 | if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) == | 1905 | if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) == |
1879 | (RTF_DEFAULT | RTF_ADDRCONF)) | 1906 | (RTF_DEFAULT | RTF_ADDRCONF)) |
@@ -2160,6 +2187,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
2160 | else | 2187 | else |
2161 | rt->rt6i_flags |= RTF_LOCAL; | 2188 | rt->rt6i_flags |= RTF_LOCAL; |
2162 | 2189 | ||
2190 | rt->rt6i_gateway = *addr; | ||
2163 | rt->rt6i_dst.addr = *addr; | 2191 | rt->rt6i_dst.addr = *addr; |
2164 | rt->rt6i_dst.plen = 128; | 2192 | rt->rt6i_dst.plen = 128; |
2165 | rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL); | 2193 | rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL); |