aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ndisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r--net/ipv6/ndisc.c31
1 files changed, 11 insertions, 20 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 9da6e02eaaeb..1f52dd257631 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -533,7 +533,8 @@ void ndisc_send_skb(struct sk_buff *skb,
533 533
534 skb_dst_set(skb, dst); 534 skb_dst_set(skb, dst);
535 535
536 idev = in6_dev_get(dst->dev); 536 rcu_read_lock();
537 idev = __in6_dev_get(dst->dev);
537 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); 538 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
538 539
539 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, 540 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
@@ -543,8 +544,7 @@ void ndisc_send_skb(struct sk_buff *skb,
543 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); 544 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
544 } 545 }
545 546
546 if (likely(idev != NULL)) 547 rcu_read_unlock();
547 in6_dev_put(idev);
548} 548}
549 549
550EXPORT_SYMBOL(ndisc_send_skb); 550EXPORT_SYMBOL(ndisc_send_skb);
@@ -1039,7 +1039,7 @@ static void ndisc_recv_rs(struct sk_buff *skb)
1039 if (skb->len < sizeof(*rs_msg)) 1039 if (skb->len < sizeof(*rs_msg))
1040 return; 1040 return;
1041 1041
1042 idev = in6_dev_get(skb->dev); 1042 idev = __in6_dev_get(skb->dev);
1043 if (!idev) { 1043 if (!idev) {
1044 if (net_ratelimit()) 1044 if (net_ratelimit())
1045 ND_PRINTK1("ICMP6 RS: can't find in6 device\n"); 1045 ND_PRINTK1("ICMP6 RS: can't find in6 device\n");
@@ -1080,7 +1080,7 @@ static void ndisc_recv_rs(struct sk_buff *skb)
1080 neigh_release(neigh); 1080 neigh_release(neigh);
1081 } 1081 }
1082out: 1082out:
1083 in6_dev_put(idev); 1083 return;
1084} 1084}
1085 1085
1086static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) 1086static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
@@ -1179,7 +1179,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1179 * set the RA_RECV flag in the interface 1179 * set the RA_RECV flag in the interface
1180 */ 1180 */
1181 1181
1182 in6_dev = in6_dev_get(skb->dev); 1182 in6_dev = __in6_dev_get(skb->dev);
1183 if (in6_dev == NULL) { 1183 if (in6_dev == NULL) {
1184 ND_PRINTK0(KERN_ERR 1184 ND_PRINTK0(KERN_ERR
1185 "ICMPv6 RA: can't find inet6 device for %s.\n", 1185 "ICMPv6 RA: can't find inet6 device for %s.\n",
@@ -1188,7 +1188,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1188 } 1188 }
1189 1189
1190 if (!ndisc_parse_options(opt, optlen, &ndopts)) { 1190 if (!ndisc_parse_options(opt, optlen, &ndopts)) {
1191 in6_dev_put(in6_dev);
1192 ND_PRINTK2(KERN_WARNING 1191 ND_PRINTK2(KERN_WARNING
1193 "ICMP6 RA: invalid ND options\n"); 1192 "ICMP6 RA: invalid ND options\n");
1194 return; 1193 return;
@@ -1255,7 +1254,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1255 ND_PRINTK0(KERN_ERR 1254 ND_PRINTK0(KERN_ERR
1256 "ICMPv6 RA: %s() failed to add default route.\n", 1255 "ICMPv6 RA: %s() failed to add default route.\n",
1257 __func__); 1256 __func__);
1258 in6_dev_put(in6_dev);
1259 return; 1257 return;
1260 } 1258 }
1261 1259
@@ -1265,7 +1263,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
1265 "ICMPv6 RA: %s() got default router without neighbour.\n", 1263 "ICMPv6 RA: %s() got default router without neighbour.\n",
1266 __func__); 1264 __func__);
1267 dst_release(&rt->dst); 1265 dst_release(&rt->dst);
1268 in6_dev_put(in6_dev);
1269 return; 1266 return;
1270 } 1267 }
1271 neigh->flags |= NTF_ROUTER; 1268 neigh->flags |= NTF_ROUTER;
@@ -1422,7 +1419,6 @@ out:
1422 dst_release(&rt->dst); 1419 dst_release(&rt->dst);
1423 else if (neigh) 1420 else if (neigh)
1424 neigh_release(neigh); 1421 neigh_release(neigh);
1425 in6_dev_put(in6_dev);
1426} 1422}
1427 1423
1428static void ndisc_redirect_rcv(struct sk_buff *skb) 1424static void ndisc_redirect_rcv(struct sk_buff *skb)
@@ -1481,13 +1477,11 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
1481 return; 1477 return;
1482 } 1478 }
1483 1479
1484 in6_dev = in6_dev_get(skb->dev); 1480 in6_dev = __in6_dev_get(skb->dev);
1485 if (!in6_dev) 1481 if (!in6_dev)
1486 return; 1482 return;
1487 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) { 1483 if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
1488 in6_dev_put(in6_dev);
1489 return; 1484 return;
1490 }
1491 1485
1492 /* RFC2461 8.1: 1486 /* RFC2461 8.1:
1493 * The IP source address of the Redirect MUST be the same as the current 1487 * The IP source address of the Redirect MUST be the same as the current
@@ -1497,7 +1491,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
1497 if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) { 1491 if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
1498 ND_PRINTK2(KERN_WARNING 1492 ND_PRINTK2(KERN_WARNING
1499 "ICMPv6 Redirect: invalid ND options\n"); 1493 "ICMPv6 Redirect: invalid ND options\n");
1500 in6_dev_put(in6_dev);
1501 return; 1494 return;
1502 } 1495 }
1503 if (ndopts.nd_opts_tgt_lladdr) { 1496 if (ndopts.nd_opts_tgt_lladdr) {
@@ -1506,7 +1499,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
1506 if (!lladdr) { 1499 if (!lladdr) {
1507 ND_PRINTK2(KERN_WARNING 1500 ND_PRINTK2(KERN_WARNING
1508 "ICMPv6 Redirect: invalid link-layer address length\n"); 1501 "ICMPv6 Redirect: invalid link-layer address length\n");
1509 in6_dev_put(in6_dev);
1510 return; 1502 return;
1511 } 1503 }
1512 } 1504 }
@@ -1518,7 +1510,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
1518 on_link); 1510 on_link);
1519 neigh_release(neigh); 1511 neigh_release(neigh);
1520 } 1512 }
1521 in6_dev_put(in6_dev);
1522} 1513}
1523 1514
1524void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, 1515void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
@@ -1651,7 +1642,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
1651 csum_partial(icmph, len, 0)); 1642 csum_partial(icmph, len, 0));
1652 1643
1653 skb_dst_set(buff, dst); 1644 skb_dst_set(buff, dst);
1654 idev = in6_dev_get(dst->dev); 1645 rcu_read_lock();
1646 idev = __in6_dev_get(dst->dev);
1655 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); 1647 IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
1656 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev, 1648 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
1657 dst_output); 1649 dst_output);
@@ -1660,8 +1652,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
1660 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); 1652 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
1661 } 1653 }
1662 1654
1663 if (likely(idev != NULL)) 1655 rcu_read_unlock();
1664 in6_dev_put(idev);
1665 return; 1656 return;
1666 1657
1667release: 1658release: