aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r--net/ipv6/route.c46
1 files changed, 37 insertions, 9 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index c3130ffc3bca..5dc6ca6b6686 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
479struct __rt6_probe_work {
480 struct work_struct work;
481 struct in6_addr target;
482 struct net_device *dev;
483};
484
485static 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
479static void rt6_probe(struct rt6_info *rt) 497static 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 {
514out: 538out:
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;
@@ -1335,6 +1358,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
1335 rt->dst.flags |= DST_HOST; 1358 rt->dst.flags |= DST_HOST;
1336 rt->dst.output = ip6_output; 1359 rt->dst.output = ip6_output;
1337 atomic_set(&rt->dst.__refcnt, 1); 1360 atomic_set(&rt->dst.__refcnt, 1);
1361 rt->rt6i_gateway = fl6->daddr;
1338 rt->rt6i_dst.addr = fl6->daddr; 1362 rt->rt6i_dst.addr = fl6->daddr;
1339 rt->rt6i_dst.plen = 128; 1363 rt->rt6i_dst.plen = 128;
1340 rt->rt6i_idev = idev; 1364 rt->rt6i_idev = idev;
@@ -1870,7 +1894,10 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort,
1870 in6_dev_hold(rt->rt6i_idev); 1894 in6_dev_hold(rt->rt6i_idev);
1871 rt->dst.lastuse = jiffies; 1895 rt->dst.lastuse = jiffies;
1872 1896
1873 rt->rt6i_gateway = ort->rt6i_gateway; 1897 if (ort->rt6i_flags & RTF_GATEWAY)
1898 rt->rt6i_gateway = ort->rt6i_gateway;
1899 else
1900 rt->rt6i_gateway = *dest;
1874 rt->rt6i_flags = ort->rt6i_flags; 1901 rt->rt6i_flags = ort->rt6i_flags;
1875 if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) == 1902 if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ==
1876 (RTF_DEFAULT | RTF_ADDRCONF)) 1903 (RTF_DEFAULT | RTF_ADDRCONF))
@@ -2157,6 +2184,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
2157 else 2184 else
2158 rt->rt6i_flags |= RTF_LOCAL; 2185 rt->rt6i_flags |= RTF_LOCAL;
2159 2186
2187 rt->rt6i_gateway = *addr;
2160 rt->rt6i_dst.addr = *addr; 2188 rt->rt6i_dst.addr = *addr;
2161 rt->rt6i_dst.plen = 128; 2189 rt->rt6i_dst.plen = 128;
2162 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL); 2190 rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL);