diff options
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r-- | net/ipv6/ndisc.c | 42 |
1 files changed, 19 insertions, 23 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 9da6e02eaaeb..44e5b7f2a6c1 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -370,17 +370,14 @@ static int ndisc_constructor(struct neighbour *neigh) | |||
370 | struct neigh_parms *parms; | 370 | struct neigh_parms *parms; |
371 | int is_multicast = ipv6_addr_is_multicast(addr); | 371 | int is_multicast = ipv6_addr_is_multicast(addr); |
372 | 372 | ||
373 | rcu_read_lock(); | ||
374 | in6_dev = in6_dev_get(dev); | 373 | in6_dev = in6_dev_get(dev); |
375 | if (in6_dev == NULL) { | 374 | if (in6_dev == NULL) { |
376 | rcu_read_unlock(); | ||
377 | return -EINVAL; | 375 | return -EINVAL; |
378 | } | 376 | } |
379 | 377 | ||
380 | parms = in6_dev->nd_parms; | 378 | parms = in6_dev->nd_parms; |
381 | __neigh_parms_put(neigh->parms); | 379 | __neigh_parms_put(neigh->parms); |
382 | neigh->parms = neigh_parms_clone(parms); | 380 | neigh->parms = neigh_parms_clone(parms); |
383 | rcu_read_unlock(); | ||
384 | 381 | ||
385 | neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST; | 382 | neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST; |
386 | if (!dev->header_ops) { | 383 | if (!dev->header_ops) { |
@@ -533,7 +530,8 @@ void ndisc_send_skb(struct sk_buff *skb, | |||
533 | 530 | ||
534 | skb_dst_set(skb, dst); | 531 | skb_dst_set(skb, dst); |
535 | 532 | ||
536 | idev = in6_dev_get(dst->dev); | 533 | rcu_read_lock(); |
534 | idev = __in6_dev_get(dst->dev); | ||
537 | IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); | 535 | IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); |
538 | 536 | ||
539 | err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, | 537 | err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev, |
@@ -543,8 +541,7 @@ void ndisc_send_skb(struct sk_buff *skb, | |||
543 | ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); | 541 | ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); |
544 | } | 542 | } |
545 | 543 | ||
546 | if (likely(idev != NULL)) | 544 | rcu_read_unlock(); |
547 | in6_dev_put(idev); | ||
548 | } | 545 | } |
549 | 546 | ||
550 | EXPORT_SYMBOL(ndisc_send_skb); | 547 | EXPORT_SYMBOL(ndisc_send_skb); |
@@ -1039,7 +1036,7 @@ static void ndisc_recv_rs(struct sk_buff *skb) | |||
1039 | if (skb->len < sizeof(*rs_msg)) | 1036 | if (skb->len < sizeof(*rs_msg)) |
1040 | return; | 1037 | return; |
1041 | 1038 | ||
1042 | idev = in6_dev_get(skb->dev); | 1039 | idev = __in6_dev_get(skb->dev); |
1043 | if (!idev) { | 1040 | if (!idev) { |
1044 | if (net_ratelimit()) | 1041 | if (net_ratelimit()) |
1045 | ND_PRINTK1("ICMP6 RS: can't find in6 device\n"); | 1042 | ND_PRINTK1("ICMP6 RS: can't find in6 device\n"); |
@@ -1080,7 +1077,7 @@ static void ndisc_recv_rs(struct sk_buff *skb) | |||
1080 | neigh_release(neigh); | 1077 | neigh_release(neigh); |
1081 | } | 1078 | } |
1082 | out: | 1079 | out: |
1083 | in6_dev_put(idev); | 1080 | return; |
1084 | } | 1081 | } |
1085 | 1082 | ||
1086 | static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) | 1083 | static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) |
@@ -1179,7 +1176,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1179 | * set the RA_RECV flag in the interface | 1176 | * set the RA_RECV flag in the interface |
1180 | */ | 1177 | */ |
1181 | 1178 | ||
1182 | in6_dev = in6_dev_get(skb->dev); | 1179 | in6_dev = __in6_dev_get(skb->dev); |
1183 | if (in6_dev == NULL) { | 1180 | if (in6_dev == NULL) { |
1184 | ND_PRINTK0(KERN_ERR | 1181 | ND_PRINTK0(KERN_ERR |
1185 | "ICMPv6 RA: can't find inet6 device for %s.\n", | 1182 | "ICMPv6 RA: can't find inet6 device for %s.\n", |
@@ -1188,7 +1185,6 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1188 | } | 1185 | } |
1189 | 1186 | ||
1190 | if (!ndisc_parse_options(opt, optlen, &ndopts)) { | 1187 | if (!ndisc_parse_options(opt, optlen, &ndopts)) { |
1191 | in6_dev_put(in6_dev); | ||
1192 | ND_PRINTK2(KERN_WARNING | 1188 | ND_PRINTK2(KERN_WARNING |
1193 | "ICMP6 RA: invalid ND options\n"); | 1189 | "ICMP6 RA: invalid ND options\n"); |
1194 | return; | 1190 | return; |
@@ -1225,6 +1221,9 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1225 | if (!in6_dev->cnf.accept_ra_defrtr) | 1221 | if (!in6_dev->cnf.accept_ra_defrtr) |
1226 | goto skip_defrtr; | 1222 | goto skip_defrtr; |
1227 | 1223 | ||
1224 | if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0)) | ||
1225 | goto skip_defrtr; | ||
1226 | |||
1228 | lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); | 1227 | lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); |
1229 | 1228 | ||
1230 | #ifdef CONFIG_IPV6_ROUTER_PREF | 1229 | #ifdef CONFIG_IPV6_ROUTER_PREF |
@@ -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; |
@@ -1349,6 +1346,9 @@ skip_linkparms: | |||
1349 | goto out; | 1346 | goto out; |
1350 | 1347 | ||
1351 | #ifdef CONFIG_IPV6_ROUTE_INFO | 1348 | #ifdef CONFIG_IPV6_ROUTE_INFO |
1349 | if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0)) | ||
1350 | goto skip_routeinfo; | ||
1351 | |||
1352 | if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) { | 1352 | if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) { |
1353 | struct nd_opt_hdr *p; | 1353 | struct nd_opt_hdr *p; |
1354 | for (p = ndopts.nd_opts_ri; | 1354 | for (p = ndopts.nd_opts_ri; |
@@ -1366,6 +1366,8 @@ skip_linkparms: | |||
1366 | &ipv6_hdr(skb)->saddr); | 1366 | &ipv6_hdr(skb)->saddr); |
1367 | } | 1367 | } |
1368 | } | 1368 | } |
1369 | |||
1370 | skip_routeinfo: | ||
1369 | #endif | 1371 | #endif |
1370 | 1372 | ||
1371 | #ifdef CONFIG_IPV6_NDISC_NODETYPE | 1373 | #ifdef CONFIG_IPV6_NDISC_NODETYPE |
@@ -1422,7 +1424,6 @@ out: | |||
1422 | dst_release(&rt->dst); | 1424 | dst_release(&rt->dst); |
1423 | else if (neigh) | 1425 | else if (neigh) |
1424 | neigh_release(neigh); | 1426 | neigh_release(neigh); |
1425 | in6_dev_put(in6_dev); | ||
1426 | } | 1427 | } |
1427 | 1428 | ||
1428 | static void ndisc_redirect_rcv(struct sk_buff *skb) | 1429 | static void ndisc_redirect_rcv(struct sk_buff *skb) |
@@ -1481,13 +1482,11 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1481 | return; | 1482 | return; |
1482 | } | 1483 | } |
1483 | 1484 | ||
1484 | in6_dev = in6_dev_get(skb->dev); | 1485 | in6_dev = __in6_dev_get(skb->dev); |
1485 | if (!in6_dev) | 1486 | if (!in6_dev) |
1486 | return; | 1487 | return; |
1487 | if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) { | 1488 | if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) |
1488 | in6_dev_put(in6_dev); | ||
1489 | return; | 1489 | return; |
1490 | } | ||
1491 | 1490 | ||
1492 | /* RFC2461 8.1: | 1491 | /* RFC2461 8.1: |
1493 | * The IP source address of the Redirect MUST be the same as the current | 1492 | * The IP source address of the Redirect MUST be the same as the current |
@@ -1497,7 +1496,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1497 | if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) { | 1496 | if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) { |
1498 | ND_PRINTK2(KERN_WARNING | 1497 | ND_PRINTK2(KERN_WARNING |
1499 | "ICMPv6 Redirect: invalid ND options\n"); | 1498 | "ICMPv6 Redirect: invalid ND options\n"); |
1500 | in6_dev_put(in6_dev); | ||
1501 | return; | 1499 | return; |
1502 | } | 1500 | } |
1503 | if (ndopts.nd_opts_tgt_lladdr) { | 1501 | if (ndopts.nd_opts_tgt_lladdr) { |
@@ -1506,7 +1504,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1506 | if (!lladdr) { | 1504 | if (!lladdr) { |
1507 | ND_PRINTK2(KERN_WARNING | 1505 | ND_PRINTK2(KERN_WARNING |
1508 | "ICMPv6 Redirect: invalid link-layer address length\n"); | 1506 | "ICMPv6 Redirect: invalid link-layer address length\n"); |
1509 | in6_dev_put(in6_dev); | ||
1510 | return; | 1507 | return; |
1511 | } | 1508 | } |
1512 | } | 1509 | } |
@@ -1518,7 +1515,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1518 | on_link); | 1515 | on_link); |
1519 | neigh_release(neigh); | 1516 | neigh_release(neigh); |
1520 | } | 1517 | } |
1521 | in6_dev_put(in6_dev); | ||
1522 | } | 1518 | } |
1523 | 1519 | ||
1524 | void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | 1520 | void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, |
@@ -1651,7 +1647,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1651 | csum_partial(icmph, len, 0)); | 1647 | csum_partial(icmph, len, 0)); |
1652 | 1648 | ||
1653 | skb_dst_set(buff, dst); | 1649 | skb_dst_set(buff, dst); |
1654 | idev = in6_dev_get(dst->dev); | 1650 | rcu_read_lock(); |
1651 | idev = __in6_dev_get(dst->dev); | ||
1655 | IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); | 1652 | 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, | 1653 | err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev, |
1657 | dst_output); | 1654 | dst_output); |
@@ -1660,8 +1657,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1660 | ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); | 1657 | ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); |
1661 | } | 1658 | } |
1662 | 1659 | ||
1663 | if (likely(idev != NULL)) | 1660 | rcu_read_unlock(); |
1664 | in6_dev_put(idev); | ||
1665 | return; | 1661 | return; |
1666 | 1662 | ||
1667 | release: | 1663 | release: |