diff options
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r-- | net/ipv6/ndisc.c | 31 |
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 | ||
550 | EXPORT_SYMBOL(ndisc_send_skb); | 550 | EXPORT_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 | } |
1082 | out: | 1082 | out: |
1083 | in6_dev_put(idev); | 1083 | return; |
1084 | } | 1084 | } |
1085 | 1085 | ||
1086 | static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) | 1086 | static 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 | ||
1428 | static void ndisc_redirect_rcv(struct sk_buff *skb) | 1424 | static 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 | ||
1524 | void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | 1515 | void 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 | ||
1667 | release: | 1658 | release: |