diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2012-02-09 16:13:19 -0500 |
---|---|---|
committer | Luis Henriques <luis.henriques@canonical.com> | 2012-03-08 07:23:31 -0500 |
commit | 1fd4aa39b59cf19231abd742d8b00561b4d5d7a1 (patch) | |
tree | 4fa63f5184f09ed2d8142401d7e6da353f3f9aa3 /net/ipv6 | |
parent | 47024c94e55428e8cac942cde4d11c613aecaa70 (diff) |
net: fix NULL dereferences in check_peer_redir()
BugLink: http://bugs.launchpad.net/bugs/931719
[ Upstream commit d3aaeb38c40e5a6c08dd31a1b64da65c4352be36, along
with dependent backports of commits:
69cce1d1404968f78b177a0314f5822d5afdbbfb
9de79c127cccecb11ae6a21ab1499e87aa222880
218fa90f072e4aeff9003d57e390857f4f35513e
580da35a31f91a594f3090b7a2c39b85cb051a12
f7e57044eeb1841847c24aa06766c8290c202583
e049f28883126c689cf95859480d9ee4ab23b7fa ]
Gergely Kalman reported crashes in check_peer_redir().
It appears commit f39925dbde778 (ipv4: Cache learned redirect
information in inetpeer.) added a race, leading to possible NULL ptr
dereference.
Since we can now change dst neighbour, we should make sure a reader can
safely use a neighbour.
Add RCU protection to dst neighbour, and make sure check_peer_redir()
can be called safely by different cpus in parallel.
As neighbours are already freed after one RCU grace period, this patch
should not add typical RCU penalty (cache cold effects)
Many thanks to Gergely for providing a pretty report pointing to the
bug.
Reported-by: Gergely Kalman <synapse@hippy.csoma.elte.hu>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_fib.c | 2 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 40 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 4 | ||||
-rw-r--r-- | net/ipv6/route.c | 59 | ||||
-rw-r--r-- | net/ipv6/sit.c | 4 |
6 files changed, 74 insertions, 37 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 498b927f68b..0f335c67eb8 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -656,7 +656,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
656 | * layer address of our nexhop router | 656 | * layer address of our nexhop router |
657 | */ | 657 | */ |
658 | 658 | ||
659 | if (rt->rt6i_nexthop == NULL) | 659 | if (dst_get_neighbour_raw(&rt->dst) == NULL) |
660 | ifa->flags &= ~IFA_F_OPTIMISTIC; | 660 | ifa->flags &= ~IFA_F_OPTIMISTIC; |
661 | 661 | ||
662 | ifa->idev = idev; | 662 | ifa->idev = idev; |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 4076a0b14b2..0f9b37a1c1d 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -1455,7 +1455,7 @@ static int fib6_age(struct rt6_info *rt, void *arg) | |||
1455 | RT6_TRACE("aging clone %p\n", rt); | 1455 | RT6_TRACE("aging clone %p\n", rt); |
1456 | return -1; | 1456 | return -1; |
1457 | } else if ((rt->rt6i_flags & RTF_GATEWAY) && | 1457 | } else if ((rt->rt6i_flags & RTF_GATEWAY) && |
1458 | (!(rt->rt6i_nexthop->flags & NTF_ROUTER))) { | 1458 | (!(dst_get_neighbour_raw(&rt->dst)->flags & NTF_ROUTER))) { |
1459 | RT6_TRACE("purging route %p via non-router but gateway\n", | 1459 | RT6_TRACE("purging route %p via non-router but gateway\n", |
1460 | rt); | 1460 | rt); |
1461 | return -1; | 1461 | return -1; |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index e17596b8407..9cbf17686a1 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -100,6 +100,8 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
100 | { | 100 | { |
101 | struct dst_entry *dst = skb_dst(skb); | 101 | struct dst_entry *dst = skb_dst(skb); |
102 | struct net_device *dev = dst->dev; | 102 | struct net_device *dev = dst->dev; |
103 | struct neighbour *neigh; | ||
104 | int res; | ||
103 | 105 | ||
104 | skb->protocol = htons(ETH_P_IPV6); | 106 | skb->protocol = htons(ETH_P_IPV6); |
105 | skb->dev = dev; | 107 | skb->dev = dev; |
@@ -134,10 +136,22 @@ static int ip6_finish_output2(struct sk_buff *skb) | |||
134 | skb->len); | 136 | skb->len); |
135 | } | 137 | } |
136 | 138 | ||
137 | if (dst->hh) | 139 | rcu_read_lock(); |
138 | return neigh_hh_output(dst->hh, skb); | 140 | if (dst->hh) { |
139 | else if (dst->neighbour) | 141 | res = neigh_hh_output(dst->hh, skb); |
140 | return dst->neighbour->output(skb); | 142 | |
143 | rcu_read_unlock(); | ||
144 | return res; | ||
145 | } else { | ||
146 | neigh = dst_get_neighbour(dst); | ||
147 | if (neigh) { | ||
148 | res = neigh->output(skb); | ||
149 | |||
150 | rcu_read_unlock(); | ||
151 | return res; | ||
152 | } | ||
153 | rcu_read_unlock(); | ||
154 | } | ||
141 | 155 | ||
142 | IP6_INC_STATS_BH(dev_net(dst->dev), | 156 | IP6_INC_STATS_BH(dev_net(dst->dev), |
143 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | 157 | ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
@@ -385,6 +399,7 @@ int ip6_forward(struct sk_buff *skb) | |||
385 | struct ipv6hdr *hdr = ipv6_hdr(skb); | 399 | struct ipv6hdr *hdr = ipv6_hdr(skb); |
386 | struct inet6_skb_parm *opt = IP6CB(skb); | 400 | struct inet6_skb_parm *opt = IP6CB(skb); |
387 | struct net *net = dev_net(dst->dev); | 401 | struct net *net = dev_net(dst->dev); |
402 | struct neighbour *n; | ||
388 | u32 mtu; | 403 | u32 mtu; |
389 | 404 | ||
390 | if (net->ipv6.devconf_all->forwarding == 0) | 405 | if (net->ipv6.devconf_all->forwarding == 0) |
@@ -459,11 +474,10 @@ int ip6_forward(struct sk_buff *skb) | |||
459 | send redirects to source routed frames. | 474 | send redirects to source routed frames. |
460 | We don't send redirects to frames decapsulated from IPsec. | 475 | We don't send redirects to frames decapsulated from IPsec. |
461 | */ | 476 | */ |
462 | if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0 && | 477 | n = dst_get_neighbour(dst); |
463 | !skb_sec_path(skb)) { | 478 | if (skb->dev == dst->dev && n && opt->srcrt == 0 && !skb_sec_path(skb)) { |
464 | struct in6_addr *target = NULL; | 479 | struct in6_addr *target = NULL; |
465 | struct rt6_info *rt; | 480 | struct rt6_info *rt; |
466 | struct neighbour *n = dst->neighbour; | ||
467 | 481 | ||
468 | /* | 482 | /* |
469 | * incoming and outgoing devices are the same | 483 | * incoming and outgoing devices are the same |
@@ -949,8 +963,11 @@ out: | |||
949 | static int ip6_dst_lookup_tail(struct sock *sk, | 963 | static int ip6_dst_lookup_tail(struct sock *sk, |
950 | struct dst_entry **dst, struct flowi6 *fl6) | 964 | struct dst_entry **dst, struct flowi6 *fl6) |
951 | { | 965 | { |
952 | int err; | ||
953 | struct net *net = sock_net(sk); | 966 | struct net *net = sock_net(sk); |
967 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | ||
968 | struct neighbour *n; | ||
969 | #endif | ||
970 | int err; | ||
954 | 971 | ||
955 | if (*dst == NULL) | 972 | if (*dst == NULL) |
956 | *dst = ip6_route_output(net, sk, fl6); | 973 | *dst = ip6_route_output(net, sk, fl6); |
@@ -976,11 +993,14 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
976 | * dst entry and replace it instead with the | 993 | * dst entry and replace it instead with the |
977 | * dst entry of the nexthop router | 994 | * dst entry of the nexthop router |
978 | */ | 995 | */ |
979 | if ((*dst)->neighbour && !((*dst)->neighbour->nud_state & NUD_VALID)) { | 996 | rcu_read_lock(); |
997 | n = dst_get_neighbour(*dst); | ||
998 | if (n && !(n->nud_state & NUD_VALID)) { | ||
980 | struct inet6_ifaddr *ifp; | 999 | struct inet6_ifaddr *ifp; |
981 | struct flowi6 fl_gw6; | 1000 | struct flowi6 fl_gw6; |
982 | int redirect; | 1001 | int redirect; |
983 | 1002 | ||
1003 | rcu_read_unlock(); | ||
984 | ifp = ipv6_get_ifaddr(net, &fl6->saddr, | 1004 | ifp = ipv6_get_ifaddr(net, &fl6->saddr, |
985 | (*dst)->dev, 1); | 1005 | (*dst)->dev, 1); |
986 | 1006 | ||
@@ -1000,6 +1020,8 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
1000 | if ((err = (*dst)->error)) | 1020 | if ((err = (*dst)->error)) |
1001 | goto out_err_release; | 1021 | goto out_err_release; |
1002 | } | 1022 | } |
1023 | } else { | ||
1024 | rcu_read_unlock(); | ||
1003 | } | 1025 | } |
1004 | #endif | 1026 | #endif |
1005 | 1027 | ||
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 7596f071d30..10a8d411707 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -1244,7 +1244,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1244 | rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev); | 1244 | rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev); |
1245 | 1245 | ||
1246 | if (rt) | 1246 | if (rt) |
1247 | neigh = rt->rt6i_nexthop; | 1247 | neigh = dst_get_neighbour(&rt->dst); |
1248 | 1248 | ||
1249 | if (rt && lifetime == 0) { | 1249 | if (rt && lifetime == 0) { |
1250 | neigh_clone(neigh); | 1250 | neigh_clone(neigh); |
@@ -1265,7 +1265,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1265 | return; | 1265 | return; |
1266 | } | 1266 | } |
1267 | 1267 | ||
1268 | neigh = rt->rt6i_nexthop; | 1268 | neigh = dst_get_neighbour(&rt->dst); |
1269 | if (neigh == NULL) { | 1269 | if (neigh == NULL) { |
1270 | ND_PRINTK0(KERN_ERR | 1270 | ND_PRINTK0(KERN_ERR |
1271 | "ICMPv6 RA: %s() got default router without neighbour.\n", | 1271 | "ICMPv6 RA: %s() got default router without neighbour.\n", |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0ef1f086feb..e70e902a5d0 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -356,7 +356,7 @@ out: | |||
356 | #ifdef CONFIG_IPV6_ROUTER_PREF | 356 | #ifdef CONFIG_IPV6_ROUTER_PREF |
357 | static void rt6_probe(struct rt6_info *rt) | 357 | static void rt6_probe(struct rt6_info *rt) |
358 | { | 358 | { |
359 | struct neighbour *neigh = rt ? rt->rt6i_nexthop : NULL; | 359 | struct neighbour *neigh; |
360 | /* | 360 | /* |
361 | * Okay, this does not seem to be appropriate | 361 | * Okay, this does not seem to be appropriate |
362 | * for now, however, we need to check if it | 362 | * for now, however, we need to check if it |
@@ -365,8 +365,10 @@ static void rt6_probe(struct rt6_info *rt) | |||
365 | * Router Reachability Probe MUST be rate-limited | 365 | * Router Reachability Probe MUST be rate-limited |
366 | * to no more than one per minute. | 366 | * to no more than one per minute. |
367 | */ | 367 | */ |
368 | rcu_read_lock(); | ||
369 | neigh = rt ? dst_get_neighbour(&rt->dst) : NULL; | ||
368 | if (!neigh || (neigh->nud_state & NUD_VALID)) | 370 | if (!neigh || (neigh->nud_state & NUD_VALID)) |
369 | return; | 371 | goto out; |
370 | read_lock_bh(&neigh->lock); | 372 | read_lock_bh(&neigh->lock); |
371 | if (!(neigh->nud_state & NUD_VALID) && | 373 | if (!(neigh->nud_state & NUD_VALID) && |
372 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { | 374 | time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { |
@@ -379,8 +381,11 @@ static void rt6_probe(struct rt6_info *rt) | |||
379 | target = (struct in6_addr *)&neigh->primary_key; | 381 | target = (struct in6_addr *)&neigh->primary_key; |
380 | addrconf_addr_solict_mult(target, &mcaddr); | 382 | addrconf_addr_solict_mult(target, &mcaddr); |
381 | ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL); | 383 | ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL); |
382 | } else | 384 | } else { |
383 | read_unlock_bh(&neigh->lock); | 385 | read_unlock_bh(&neigh->lock); |
386 | } | ||
387 | out: | ||
388 | rcu_read_unlock(); | ||
384 | } | 389 | } |
385 | #else | 390 | #else |
386 | static inline void rt6_probe(struct rt6_info *rt) | 391 | static inline void rt6_probe(struct rt6_info *rt) |
@@ -404,8 +409,11 @@ static inline int rt6_check_dev(struct rt6_info *rt, int oif) | |||
404 | 409 | ||
405 | static inline int rt6_check_neigh(struct rt6_info *rt) | 410 | static inline int rt6_check_neigh(struct rt6_info *rt) |
406 | { | 411 | { |
407 | struct neighbour *neigh = rt->rt6i_nexthop; | 412 | struct neighbour *neigh; |
408 | int m; | 413 | int m; |
414 | |||
415 | rcu_read_lock(); | ||
416 | neigh = dst_get_neighbour(&rt->dst); | ||
409 | if (rt->rt6i_flags & RTF_NONEXTHOP || | 417 | if (rt->rt6i_flags & RTF_NONEXTHOP || |
410 | !(rt->rt6i_flags & RTF_GATEWAY)) | 418 | !(rt->rt6i_flags & RTF_GATEWAY)) |
411 | m = 1; | 419 | m = 1; |
@@ -422,6 +430,7 @@ static inline int rt6_check_neigh(struct rt6_info *rt) | |||
422 | read_unlock_bh(&neigh->lock); | 430 | read_unlock_bh(&neigh->lock); |
423 | } else | 431 | } else |
424 | m = 0; | 432 | m = 0; |
433 | rcu_read_unlock(); | ||
425 | return m; | 434 | return m; |
426 | } | 435 | } |
427 | 436 | ||
@@ -745,8 +754,7 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_add | |||
745 | dst_free(&rt->dst); | 754 | dst_free(&rt->dst); |
746 | return NULL; | 755 | return NULL; |
747 | } | 756 | } |
748 | rt->rt6i_nexthop = neigh; | 757 | dst_set_neighbour(&rt->dst, neigh); |
749 | |||
750 | } | 758 | } |
751 | 759 | ||
752 | return rt; | 760 | return rt; |
@@ -760,7 +768,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, const struct in6_a | |||
760 | rt->rt6i_dst.plen = 128; | 768 | rt->rt6i_dst.plen = 128; |
761 | rt->rt6i_flags |= RTF_CACHE; | 769 | rt->rt6i_flags |= RTF_CACHE; |
762 | rt->dst.flags |= DST_HOST; | 770 | rt->dst.flags |= DST_HOST; |
763 | rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop); | 771 | dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_raw(&ort->dst))); |
764 | } | 772 | } |
765 | return rt; | 773 | return rt; |
766 | } | 774 | } |
@@ -794,7 +802,7 @@ restart: | |||
794 | dst_hold(&rt->dst); | 802 | dst_hold(&rt->dst); |
795 | read_unlock_bh(&table->tb6_lock); | 803 | read_unlock_bh(&table->tb6_lock); |
796 | 804 | ||
797 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 805 | if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
798 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); | 806 | nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); |
799 | else if (!(rt->dst.flags & DST_HOST)) | 807 | else if (!(rt->dst.flags & DST_HOST)) |
800 | nrt = rt6_alloc_clone(rt, &fl6->daddr); | 808 | nrt = rt6_alloc_clone(rt, &fl6->daddr); |
@@ -1058,7 +1066,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, | |||
1058 | } | 1066 | } |
1059 | 1067 | ||
1060 | rt->rt6i_idev = idev; | 1068 | rt->rt6i_idev = idev; |
1061 | rt->rt6i_nexthop = neigh; | 1069 | dst_set_neighbour(&rt->dst, neigh); |
1062 | atomic_set(&rt->dst.__refcnt, 1); | 1070 | atomic_set(&rt->dst.__refcnt, 1); |
1063 | dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255); | 1071 | dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255); |
1064 | rt->dst.output = ip6_output; | 1072 | rt->dst.output = ip6_output; |
@@ -1338,12 +1346,12 @@ int ip6_route_add(struct fib6_config *cfg) | |||
1338 | rt->rt6i_prefsrc.plen = 0; | 1346 | rt->rt6i_prefsrc.plen = 0; |
1339 | 1347 | ||
1340 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { | 1348 | if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { |
1341 | rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); | 1349 | struct neighbour *neigh = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); |
1342 | if (IS_ERR(rt->rt6i_nexthop)) { | 1350 | if (IS_ERR(neigh)) { |
1343 | err = PTR_ERR(rt->rt6i_nexthop); | 1351 | err = PTR_ERR(neigh); |
1344 | rt->rt6i_nexthop = NULL; | ||
1345 | goto out; | 1352 | goto out; |
1346 | } | 1353 | } |
1354 | dst_set_neighbour(&rt->dst, neigh); | ||
1347 | } | 1355 | } |
1348 | 1356 | ||
1349 | rt->rt6i_flags = cfg->fc_flags; | 1357 | rt->rt6i_flags = cfg->fc_flags; |
@@ -1574,7 +1582,7 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, | |||
1574 | dst_confirm(&rt->dst); | 1582 | dst_confirm(&rt->dst); |
1575 | 1583 | ||
1576 | /* Duplicate redirect: silently ignore. */ | 1584 | /* Duplicate redirect: silently ignore. */ |
1577 | if (neigh == rt->dst.neighbour) | 1585 | if (neigh == dst_get_neighbour_raw(&rt->dst)) |
1578 | goto out; | 1586 | goto out; |
1579 | 1587 | ||
1580 | nrt = ip6_rt_copy(rt); | 1588 | nrt = ip6_rt_copy(rt); |
@@ -1590,7 +1598,7 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, | |||
1590 | nrt->dst.flags |= DST_HOST; | 1598 | nrt->dst.flags |= DST_HOST; |
1591 | 1599 | ||
1592 | ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); | 1600 | ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); |
1593 | nrt->rt6i_nexthop = neigh_clone(neigh); | 1601 | dst_set_neighbour(&nrt->dst, neigh_clone(neigh)); |
1594 | 1602 | ||
1595 | if (ip6_ins_rt(nrt)) | 1603 | if (ip6_ins_rt(nrt)) |
1596 | goto out; | 1604 | goto out; |
@@ -1670,7 +1678,7 @@ again: | |||
1670 | 1. It is connected route. Action: COW | 1678 | 1. It is connected route. Action: COW |
1671 | 2. It is gatewayed route or NONEXTHOP route. Action: clone it. | 1679 | 2. It is gatewayed route or NONEXTHOP route. Action: clone it. |
1672 | */ | 1680 | */ |
1673 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) | 1681 | if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) |
1674 | nrt = rt6_alloc_cow(rt, daddr, saddr); | 1682 | nrt = rt6_alloc_cow(rt, daddr, saddr); |
1675 | else | 1683 | else |
1676 | nrt = rt6_alloc_clone(rt, daddr); | 1684 | nrt = rt6_alloc_clone(rt, daddr); |
@@ -2035,7 +2043,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
2035 | 2043 | ||
2036 | return ERR_CAST(neigh); | 2044 | return ERR_CAST(neigh); |
2037 | } | 2045 | } |
2038 | rt->rt6i_nexthop = neigh; | 2046 | dst_set_neighbour(&rt->dst, neigh); |
2039 | 2047 | ||
2040 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); | 2048 | ipv6_addr_copy(&rt->rt6i_dst.addr, addr); |
2041 | rt->rt6i_dst.plen = 128; | 2049 | rt->rt6i_dst.plen = 128; |
@@ -2312,6 +2320,7 @@ static int rt6_fill_node(struct net *net, | |||
2312 | struct nlmsghdr *nlh; | 2320 | struct nlmsghdr *nlh; |
2313 | long expires; | 2321 | long expires; |
2314 | u32 table; | 2322 | u32 table; |
2323 | struct neighbour *n; | ||
2315 | 2324 | ||
2316 | if (prefix) { /* user wants prefix routes only */ | 2325 | if (prefix) { /* user wants prefix routes only */ |
2317 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { | 2326 | if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { |
@@ -2400,8 +2409,11 @@ static int rt6_fill_node(struct net *net, | |||
2400 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) | 2409 | if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) |
2401 | goto nla_put_failure; | 2410 | goto nla_put_failure; |
2402 | 2411 | ||
2403 | if (rt->dst.neighbour) | 2412 | rcu_read_lock(); |
2404 | NLA_PUT(skb, RTA_GATEWAY, 16, &rt->dst.neighbour->primary_key); | 2413 | n = dst_get_neighbour(&rt->dst); |
2414 | if (n) | ||
2415 | NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key); | ||
2416 | rcu_read_unlock(); | ||
2405 | 2417 | ||
2406 | if (rt->dst.dev) | 2418 | if (rt->dst.dev) |
2407 | NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); | 2419 | NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); |
@@ -2585,6 +2597,7 @@ struct rt6_proc_arg | |||
2585 | static int rt6_info_route(struct rt6_info *rt, void *p_arg) | 2597 | static int rt6_info_route(struct rt6_info *rt, void *p_arg) |
2586 | { | 2598 | { |
2587 | struct seq_file *m = p_arg; | 2599 | struct seq_file *m = p_arg; |
2600 | struct neighbour *n; | ||
2588 | 2601 | ||
2589 | seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); | 2602 | seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); |
2590 | 2603 | ||
@@ -2593,12 +2606,14 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) | |||
2593 | #else | 2606 | #else |
2594 | seq_puts(m, "00000000000000000000000000000000 00 "); | 2607 | seq_puts(m, "00000000000000000000000000000000 00 "); |
2595 | #endif | 2608 | #endif |
2596 | 2609 | rcu_read_lock(); | |
2597 | if (rt->rt6i_nexthop) { | 2610 | n = dst_get_neighbour(&rt->dst); |
2598 | seq_printf(m, "%pi6", rt->rt6i_nexthop->primary_key); | 2611 | if (n) { |
2612 | seq_printf(m, "%pi6", n->primary_key); | ||
2599 | } else { | 2613 | } else { |
2600 | seq_puts(m, "00000000000000000000000000000000"); | 2614 | seq_puts(m, "00000000000000000000000000000000"); |
2601 | } | 2615 | } |
2616 | rcu_read_unlock(); | ||
2602 | seq_printf(m, " %08x %08x %08x %08x %8s\n", | 2617 | seq_printf(m, " %08x %08x %08x %08x %8s\n", |
2603 | rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), | 2618 | rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), |
2604 | rt->dst.__use, rt->rt6i_flags, | 2619 | rt->dst.__use, rt->rt6i_flags, |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 38490d5c7e1..f56acd09659 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -679,7 +679,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
679 | struct neighbour *neigh = NULL; | 679 | struct neighbour *neigh = NULL; |
680 | 680 | ||
681 | if (skb_dst(skb)) | 681 | if (skb_dst(skb)) |
682 | neigh = skb_dst(skb)->neighbour; | 682 | neigh = dst_get_neighbour(skb_dst(skb)); |
683 | 683 | ||
684 | if (neigh == NULL) { | 684 | if (neigh == NULL) { |
685 | if (net_ratelimit()) | 685 | if (net_ratelimit()) |
@@ -704,7 +704,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, | |||
704 | struct neighbour *neigh = NULL; | 704 | struct neighbour *neigh = NULL; |
705 | 705 | ||
706 | if (skb_dst(skb)) | 706 | if (skb_dst(skb)) |
707 | neigh = skb_dst(skb)->neighbour; | 707 | neigh = dst_get_neighbour(skb_dst(skb)); |
708 | 708 | ||
709 | if (neigh == NULL) { | 709 | if (neigh == NULL) { |
710 | if (net_ratelimit()) | 710 | if (net_ratelimit()) |