diff options
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r-- | net/ipv6/ndisc.c | 139 |
1 files changed, 77 insertions, 62 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 0d33a7d32125..24e76ed98884 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -89,8 +89,6 @@ | |||
89 | #include <linux/netfilter.h> | 89 | #include <linux/netfilter.h> |
90 | #include <linux/netfilter_ipv6.h> | 90 | #include <linux/netfilter_ipv6.h> |
91 | 91 | ||
92 | static struct socket *ndisc_socket; | ||
93 | |||
94 | static u32 ndisc_hash(const void *pkey, const struct net_device *dev); | 92 | static u32 ndisc_hash(const void *pkey, const struct net_device *dev); |
95 | static int ndisc_constructor(struct neighbour *neigh); | 93 | static int ndisc_constructor(struct neighbour *neigh); |
96 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); | 94 | static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); |
@@ -270,7 +268,7 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, | |||
270 | if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { | 268 | if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { |
271 | ND_PRINTK2(KERN_WARNING | 269 | ND_PRINTK2(KERN_WARNING |
272 | "%s(): duplicated ND6 option found: type=%d\n", | 270 | "%s(): duplicated ND6 option found: type=%d\n", |
273 | __FUNCTION__, | 271 | __func__, |
274 | nd_opt->nd_opt_type); | 272 | nd_opt->nd_opt_type); |
275 | } else { | 273 | } else { |
276 | ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; | 274 | ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; |
@@ -301,7 +299,7 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, | |||
301 | */ | 299 | */ |
302 | ND_PRINTK2(KERN_NOTICE | 300 | ND_PRINTK2(KERN_NOTICE |
303 | "%s(): ignored unsupported option; type=%d, len=%d\n", | 301 | "%s(): ignored unsupported option; type=%d, len=%d\n", |
304 | __FUNCTION__, | 302 | __func__, |
305 | nd_opt->nd_opt_type, nd_opt->nd_opt_len); | 303 | nd_opt->nd_opt_type, nd_opt->nd_opt_len); |
306 | } | 304 | } |
307 | } | 305 | } |
@@ -441,21 +439,6 @@ static void pndisc_destructor(struct pneigh_entry *n) | |||
441 | /* | 439 | /* |
442 | * Send a Neighbour Advertisement | 440 | * Send a Neighbour Advertisement |
443 | */ | 441 | */ |
444 | |||
445 | static inline void ndisc_flow_init(struct flowi *fl, u8 type, | ||
446 | struct in6_addr *saddr, struct in6_addr *daddr, | ||
447 | int oif) | ||
448 | { | ||
449 | memset(fl, 0, sizeof(*fl)); | ||
450 | ipv6_addr_copy(&fl->fl6_src, saddr); | ||
451 | ipv6_addr_copy(&fl->fl6_dst, daddr); | ||
452 | fl->proto = IPPROTO_ICMPV6; | ||
453 | fl->fl_icmp_type = type; | ||
454 | fl->fl_icmp_code = 0; | ||
455 | fl->oif = oif; | ||
456 | security_sk_classify_flow(ndisc_socket->sk, fl); | ||
457 | } | ||
458 | |||
459 | static void __ndisc_send(struct net_device *dev, | 442 | static void __ndisc_send(struct net_device *dev, |
460 | struct neighbour *neigh, | 443 | struct neighbour *neigh, |
461 | struct in6_addr *daddr, struct in6_addr *saddr, | 444 | struct in6_addr *daddr, struct in6_addr *saddr, |
@@ -464,7 +447,8 @@ static void __ndisc_send(struct net_device *dev, | |||
464 | { | 447 | { |
465 | struct flowi fl; | 448 | struct flowi fl; |
466 | struct dst_entry *dst; | 449 | struct dst_entry *dst; |
467 | struct sock *sk = ndisc_socket->sk; | 450 | struct net *net = dev->nd_net; |
451 | struct sock *sk = net->ipv6.ndisc_sk; | ||
468 | struct sk_buff *skb; | 452 | struct sk_buff *skb; |
469 | struct icmp6hdr *hdr; | 453 | struct icmp6hdr *hdr; |
470 | struct inet6_dev *idev; | 454 | struct inet6_dev *idev; |
@@ -474,10 +458,9 @@ static void __ndisc_send(struct net_device *dev, | |||
474 | 458 | ||
475 | type = icmp6h->icmp6_type; | 459 | type = icmp6h->icmp6_type; |
476 | 460 | ||
477 | ndisc_flow_init(&fl, type, saddr, daddr, | 461 | icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex); |
478 | dev->ifindex); | ||
479 | 462 | ||
480 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); | 463 | dst = icmp6_dst_alloc(dev, neigh, daddr); |
481 | if (!dst) | 464 | if (!dst) |
482 | return; | 465 | return; |
483 | 466 | ||
@@ -499,7 +482,7 @@ static void __ndisc_send(struct net_device *dev, | |||
499 | if (!skb) { | 482 | if (!skb) { |
500 | ND_PRINTK0(KERN_ERR | 483 | ND_PRINTK0(KERN_ERR |
501 | "ICMPv6 ND: %s() failed to allocate an skb.\n", | 484 | "ICMPv6 ND: %s() failed to allocate an skb.\n", |
502 | __FUNCTION__); | 485 | __func__); |
503 | dst_release(dst); | 486 | dst_release(dst); |
504 | return; | 487 | return; |
505 | } | 488 | } |
@@ -556,7 +539,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
556 | }; | 539 | }; |
557 | 540 | ||
558 | /* for anycast or proxy, solicited_addr != src_addr */ | 541 | /* for anycast or proxy, solicited_addr != src_addr */ |
559 | ifp = ipv6_get_ifaddr(&init_net, solicited_addr, dev, 1); | 542 | ifp = ipv6_get_ifaddr(dev->nd_net, solicited_addr, dev, 1); |
560 | if (ifp) { | 543 | if (ifp) { |
561 | src_addr = solicited_addr; | 544 | src_addr = solicited_addr; |
562 | if (ifp->flags & IFA_F_OPTIMISTIC) | 545 | if (ifp->flags & IFA_F_OPTIMISTIC) |
@@ -616,7 +599,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, | |||
616 | * suppress the inclusion of the sllao. | 599 | * suppress the inclusion of the sllao. |
617 | */ | 600 | */ |
618 | if (send_sllao) { | 601 | if (send_sllao) { |
619 | struct inet6_ifaddr *ifp = ipv6_get_ifaddr(&init_net, saddr, | 602 | struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev->nd_net, saddr, |
620 | dev, 1); | 603 | dev, 1); |
621 | if (ifp) { | 604 | if (ifp) { |
622 | if (ifp->flags & IFA_F_OPTIMISTIC) { | 605 | if (ifp->flags & IFA_F_OPTIMISTIC) { |
@@ -654,7 +637,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
654 | struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; | 637 | struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; |
655 | int probes = atomic_read(&neigh->probes); | 638 | int probes = atomic_read(&neigh->probes); |
656 | 639 | ||
657 | if (skb && ipv6_chk_addr(&init_net, &ipv6_hdr(skb)->saddr, dev, 1)) | 640 | if (skb && ipv6_chk_addr(dev->nd_net, &ipv6_hdr(skb)->saddr, dev, 1)) |
658 | saddr = &ipv6_hdr(skb)->saddr; | 641 | saddr = &ipv6_hdr(skb)->saddr; |
659 | 642 | ||
660 | if ((probes -= neigh->parms->ucast_probes) < 0) { | 643 | if ((probes -= neigh->parms->ucast_probes) < 0) { |
@@ -662,7 +645,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
662 | ND_PRINTK1(KERN_DEBUG | 645 | ND_PRINTK1(KERN_DEBUG |
663 | "%s(): trying to ucast probe in NUD_INVALID: " | 646 | "%s(): trying to ucast probe in NUD_INVALID: " |
664 | NIP6_FMT "\n", | 647 | NIP6_FMT "\n", |
665 | __FUNCTION__, | 648 | __func__, |
666 | NIP6(*target)); | 649 | NIP6(*target)); |
667 | } | 650 | } |
668 | ndisc_send_ns(dev, neigh, target, target, saddr); | 651 | ndisc_send_ns(dev, neigh, target, target, saddr); |
@@ -742,7 +725,8 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
742 | 725 | ||
743 | inc = ipv6_addr_is_multicast(daddr); | 726 | inc = ipv6_addr_is_multicast(daddr); |
744 | 727 | ||
745 | if ((ifp = ipv6_get_ifaddr(&init_net, &msg->target, dev, 1)) != NULL) { | 728 | ifp = ipv6_get_ifaddr(dev->nd_net, &msg->target, dev, 1); |
729 | if (ifp) { | ||
746 | 730 | ||
747 | if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { | 731 | if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { |
748 | if (dad) { | 732 | if (dad) { |
@@ -790,7 +774,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
790 | if (ipv6_chk_acast_addr(dev, &msg->target) || | 774 | if (ipv6_chk_acast_addr(dev, &msg->target) || |
791 | (idev->cnf.forwarding && | 775 | (idev->cnf.forwarding && |
792 | (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && | 776 | (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && |
793 | (pneigh = pneigh_lookup(&nd_tbl, &init_net, | 777 | (pneigh = pneigh_lookup(&nd_tbl, dev->nd_net, |
794 | &msg->target, dev, 0)) != NULL)) { | 778 | &msg->target, dev, 0)) != NULL)) { |
795 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && | 779 | if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && |
796 | skb->pkt_type != PACKET_HOST && | 780 | skb->pkt_type != PACKET_HOST && |
@@ -900,7 +884,8 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
900 | return; | 884 | return; |
901 | } | 885 | } |
902 | } | 886 | } |
903 | if ((ifp = ipv6_get_ifaddr(&init_net, &msg->target, dev, 1))) { | 887 | ifp = ipv6_get_ifaddr(dev->nd_net, &msg->target, dev, 1); |
888 | if (ifp) { | ||
904 | if (ifp->flags & IFA_F_TENTATIVE) { | 889 | if (ifp->flags & IFA_F_TENTATIVE) { |
905 | addrconf_dad_failure(ifp); | 890 | addrconf_dad_failure(ifp); |
906 | return; | 891 | return; |
@@ -931,7 +916,7 @@ static void ndisc_recv_na(struct sk_buff *skb) | |||
931 | */ | 916 | */ |
932 | if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && | 917 | if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && |
933 | ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp && | 918 | ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp && |
934 | pneigh_lookup(&nd_tbl, &init_net, &msg->target, dev, 0)) { | 919 | pneigh_lookup(&nd_tbl, dev->nd_net, &msg->target, dev, 0)) { |
935 | /* XXX: idev->cnf.prixy_ndp */ | 920 | /* XXX: idev->cnf.prixy_ndp */ |
936 | goto out; | 921 | goto out; |
937 | } | 922 | } |
@@ -1021,6 +1006,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) | |||
1021 | struct sk_buff *skb; | 1006 | struct sk_buff *skb; |
1022 | struct nlmsghdr *nlh; | 1007 | struct nlmsghdr *nlh; |
1023 | struct nduseroptmsg *ndmsg; | 1008 | struct nduseroptmsg *ndmsg; |
1009 | struct net *net = ra->dev->nd_net; | ||
1024 | int err; | 1010 | int err; |
1025 | int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg) | 1011 | int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg) |
1026 | + (opt->nd_opt_len << 3)); | 1012 | + (opt->nd_opt_len << 3)); |
@@ -1050,7 +1036,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) | |||
1050 | &ipv6_hdr(ra)->saddr); | 1036 | &ipv6_hdr(ra)->saddr); |
1051 | nlmsg_end(skb, nlh); | 1037 | nlmsg_end(skb, nlh); |
1052 | 1038 | ||
1053 | err = rtnl_notify(skb, &init_net, 0, RTNLGRP_ND_USEROPT, NULL, | 1039 | err = rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, |
1054 | GFP_ATOMIC); | 1040 | GFP_ATOMIC); |
1055 | if (err < 0) | 1041 | if (err < 0) |
1056 | goto errout; | 1042 | goto errout; |
@@ -1061,7 +1047,7 @@ nla_put_failure: | |||
1061 | nlmsg_free(skb); | 1047 | nlmsg_free(skb); |
1062 | err = -EMSGSIZE; | 1048 | err = -EMSGSIZE; |
1063 | errout: | 1049 | errout: |
1064 | rtnl_set_sk_err(&init_net, RTNLGRP_ND_USEROPT, err); | 1050 | rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); |
1065 | } | 1051 | } |
1066 | 1052 | ||
1067 | static void ndisc_router_discovery(struct sk_buff *skb) | 1053 | static void ndisc_router_discovery(struct sk_buff *skb) |
@@ -1164,7 +1150,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1164 | if (rt == NULL) { | 1150 | if (rt == NULL) { |
1165 | ND_PRINTK0(KERN_ERR | 1151 | ND_PRINTK0(KERN_ERR |
1166 | "ICMPv6 RA: %s() failed to add default route.\n", | 1152 | "ICMPv6 RA: %s() failed to add default route.\n", |
1167 | __FUNCTION__); | 1153 | __func__); |
1168 | in6_dev_put(in6_dev); | 1154 | in6_dev_put(in6_dev); |
1169 | return; | 1155 | return; |
1170 | } | 1156 | } |
@@ -1173,7 +1159,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1173 | if (neigh == NULL) { | 1159 | if (neigh == NULL) { |
1174 | ND_PRINTK0(KERN_ERR | 1160 | ND_PRINTK0(KERN_ERR |
1175 | "ICMPv6 RA: %s() got default router without neighbour.\n", | 1161 | "ICMPv6 RA: %s() got default router without neighbour.\n", |
1176 | __FUNCTION__); | 1162 | __func__); |
1177 | dst_release(&rt->u.dst); | 1163 | dst_release(&rt->u.dst); |
1178 | in6_dev_put(in6_dev); | 1164 | in6_dev_put(in6_dev); |
1179 | return; | 1165 | return; |
@@ -1406,13 +1392,14 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1406 | void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | 1392 | void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, |
1407 | struct in6_addr *target) | 1393 | struct in6_addr *target) |
1408 | { | 1394 | { |
1409 | struct sock *sk = ndisc_socket->sk; | 1395 | struct net_device *dev = skb->dev; |
1396 | struct net *net = dev->nd_net; | ||
1397 | struct sock *sk = net->ipv6.ndisc_sk; | ||
1410 | int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); | 1398 | int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); |
1411 | struct sk_buff *buff; | 1399 | struct sk_buff *buff; |
1412 | struct icmp6hdr *icmph; | 1400 | struct icmp6hdr *icmph; |
1413 | struct in6_addr saddr_buf; | 1401 | struct in6_addr saddr_buf; |
1414 | struct in6_addr *addrp; | 1402 | struct in6_addr *addrp; |
1415 | struct net_device *dev; | ||
1416 | struct rt6_info *rt; | 1403 | struct rt6_info *rt; |
1417 | struct dst_entry *dst; | 1404 | struct dst_entry *dst; |
1418 | struct inet6_dev *idev; | 1405 | struct inet6_dev *idev; |
@@ -1423,8 +1410,6 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1423 | int hlen; | 1410 | int hlen; |
1424 | u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; | 1411 | u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; |
1425 | 1412 | ||
1426 | dev = skb->dev; | ||
1427 | |||
1428 | if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { | 1413 | if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { |
1429 | ND_PRINTK2(KERN_WARNING | 1414 | ND_PRINTK2(KERN_WARNING |
1430 | "ICMPv6 Redirect: no link-local address on %s\n", | 1415 | "ICMPv6 Redirect: no link-local address on %s\n", |
@@ -1439,10 +1424,10 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1439 | return; | 1424 | return; |
1440 | } | 1425 | } |
1441 | 1426 | ||
1442 | ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &ipv6_hdr(skb)->saddr, | 1427 | icmpv6_flow_init(sk, &fl, NDISC_REDIRECT, |
1443 | dev->ifindex); | 1428 | &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); |
1444 | 1429 | ||
1445 | dst = ip6_route_output(NULL, &fl); | 1430 | dst = ip6_route_output(net, NULL, &fl); |
1446 | if (dst == NULL) | 1431 | if (dst == NULL) |
1447 | return; | 1432 | return; |
1448 | 1433 | ||
@@ -1486,7 +1471,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1486 | if (buff == NULL) { | 1471 | if (buff == NULL) { |
1487 | ND_PRINTK0(KERN_ERR | 1472 | ND_PRINTK0(KERN_ERR |
1488 | "ICMPv6 Redirect: %s() failed to allocate an skb.\n", | 1473 | "ICMPv6 Redirect: %s() failed to allocate an skb.\n", |
1489 | __FUNCTION__); | 1474 | __func__); |
1490 | dst_release(dst); | 1475 | dst_release(dst); |
1491 | return; | 1476 | return; |
1492 | } | 1477 | } |
@@ -1613,18 +1598,16 @@ int ndisc_rcv(struct sk_buff *skb) | |||
1613 | static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) | 1598 | static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) |
1614 | { | 1599 | { |
1615 | struct net_device *dev = ptr; | 1600 | struct net_device *dev = ptr; |
1616 | 1601 | struct net *net = dev->nd_net; | |
1617 | if (dev->nd_net != &init_net) | ||
1618 | return NOTIFY_DONE; | ||
1619 | 1602 | ||
1620 | switch (event) { | 1603 | switch (event) { |
1621 | case NETDEV_CHANGEADDR: | 1604 | case NETDEV_CHANGEADDR: |
1622 | neigh_changeaddr(&nd_tbl, dev); | 1605 | neigh_changeaddr(&nd_tbl, dev); |
1623 | fib6_run_gc(~0UL); | 1606 | fib6_run_gc(~0UL, net); |
1624 | break; | 1607 | break; |
1625 | case NETDEV_DOWN: | 1608 | case NETDEV_DOWN: |
1626 | neigh_ifdown(&nd_tbl, dev); | 1609 | neigh_ifdown(&nd_tbl, dev); |
1627 | fib6_run_gc(~0UL); | 1610 | fib6_run_gc(~0UL, net); |
1628 | break; | 1611 | break; |
1629 | default: | 1612 | default: |
1630 | break; | 1613 | break; |
@@ -1733,22 +1716,24 @@ static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name, | |||
1733 | 1716 | ||
1734 | #endif | 1717 | #endif |
1735 | 1718 | ||
1736 | int __init ndisc_init(struct net_proto_family *ops) | 1719 | static int ndisc_net_init(struct net *net) |
1737 | { | 1720 | { |
1721 | struct socket *sock; | ||
1738 | struct ipv6_pinfo *np; | 1722 | struct ipv6_pinfo *np; |
1739 | struct sock *sk; | 1723 | struct sock *sk; |
1740 | int err; | 1724 | int err; |
1741 | 1725 | ||
1742 | err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &ndisc_socket); | 1726 | err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock); |
1743 | if (err < 0) { | 1727 | if (err < 0) { |
1744 | ND_PRINTK0(KERN_ERR | 1728 | ND_PRINTK0(KERN_ERR |
1745 | "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n", | 1729 | "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n", |
1746 | err); | 1730 | err); |
1747 | ndisc_socket = NULL; /* For safety. */ | ||
1748 | return err; | 1731 | return err; |
1749 | } | 1732 | } |
1750 | 1733 | ||
1751 | sk = ndisc_socket->sk; | 1734 | net->ipv6.ndisc_sk = sk = sock->sk; |
1735 | sk_change_net(sk, net); | ||
1736 | |||
1752 | np = inet6_sk(sk); | 1737 | np = inet6_sk(sk); |
1753 | sk->sk_allocation = GFP_ATOMIC; | 1738 | sk->sk_allocation = GFP_ATOMIC; |
1754 | np->hop_limit = 255; | 1739 | np->hop_limit = 255; |
@@ -1756,21 +1741,52 @@ int __init ndisc_init(struct net_proto_family *ops) | |||
1756 | np->mc_loop = 0; | 1741 | np->mc_loop = 0; |
1757 | sk->sk_prot->unhash(sk); | 1742 | sk->sk_prot->unhash(sk); |
1758 | 1743 | ||
1744 | return 0; | ||
1745 | } | ||
1746 | |||
1747 | static void ndisc_net_exit(struct net *net) | ||
1748 | { | ||
1749 | sk_release_kernel(net->ipv6.ndisc_sk); | ||
1750 | } | ||
1751 | |||
1752 | static struct pernet_operations ndisc_net_ops = { | ||
1753 | .init = ndisc_net_init, | ||
1754 | .exit = ndisc_net_exit, | ||
1755 | }; | ||
1756 | |||
1757 | int __init ndisc_init(void) | ||
1758 | { | ||
1759 | int err; | ||
1760 | |||
1761 | err = register_pernet_subsys(&ndisc_net_ops); | ||
1762 | if (err) | ||
1763 | return err; | ||
1759 | /* | 1764 | /* |
1760 | * Initialize the neighbour table | 1765 | * Initialize the neighbour table |
1761 | */ | 1766 | */ |
1762 | |||
1763 | neigh_table_init(&nd_tbl); | 1767 | neigh_table_init(&nd_tbl); |
1764 | 1768 | ||
1765 | #ifdef CONFIG_SYSCTL | 1769 | #ifdef CONFIG_SYSCTL |
1766 | neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, | 1770 | err = neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, |
1767 | "ipv6", | 1771 | NET_IPV6_NEIGH, "ipv6", |
1768 | &ndisc_ifinfo_sysctl_change, | 1772 | &ndisc_ifinfo_sysctl_change, |
1769 | &ndisc_ifinfo_sysctl_strategy); | 1773 | &ndisc_ifinfo_sysctl_strategy); |
1774 | if (err) | ||
1775 | goto out_unregister_pernet; | ||
1770 | #endif | 1776 | #endif |
1777 | err = register_netdevice_notifier(&ndisc_netdev_notifier); | ||
1778 | if (err) | ||
1779 | goto out_unregister_sysctl; | ||
1780 | out: | ||
1781 | return err; | ||
1771 | 1782 | ||
1772 | register_netdevice_notifier(&ndisc_netdev_notifier); | 1783 | out_unregister_sysctl: |
1773 | return 0; | 1784 | #ifdef CONFIG_SYSCTL |
1785 | neigh_sysctl_unregister(&nd_tbl.parms); | ||
1786 | out_unregister_pernet: | ||
1787 | #endif | ||
1788 | unregister_pernet_subsys(&ndisc_net_ops); | ||
1789 | goto out; | ||
1774 | } | 1790 | } |
1775 | 1791 | ||
1776 | void ndisc_cleanup(void) | 1792 | void ndisc_cleanup(void) |
@@ -1780,6 +1796,5 @@ void ndisc_cleanup(void) | |||
1780 | neigh_sysctl_unregister(&nd_tbl.parms); | 1796 | neigh_sysctl_unregister(&nd_tbl.parms); |
1781 | #endif | 1797 | #endif |
1782 | neigh_table_clear(&nd_tbl); | 1798 | neigh_table_clear(&nd_tbl); |
1783 | sock_release(ndisc_socket); | 1799 | unregister_pernet_subsys(&ndisc_net_ops); |
1784 | ndisc_socket = NULL; /* For safety. */ | ||
1785 | } | 1800 | } |