aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/netns/ipv6.h1
-rw-r--r--net/ipv6/ndisc.c77
2 files changed, 54 insertions, 24 deletions
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 90e6e24df858..b773256d0d1d 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -51,5 +51,6 @@ struct netns_ipv6 {
51 struct fib_rules_ops *fib6_rules_ops; 51 struct fib_rules_ops *fib6_rules_ops;
52#endif 52#endif
53 struct sock **icmp_sk; 53 struct sock **icmp_sk;
54 struct sock *ndisc_sk;
54}; 55};
55#endif 56#endif
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index a539b9ea53fd..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
92static struct socket *ndisc_socket;
93
94static u32 ndisc_hash(const void *pkey, const struct net_device *dev); 92static u32 ndisc_hash(const void *pkey, const struct net_device *dev);
95static int ndisc_constructor(struct neighbour *neigh); 93static int ndisc_constructor(struct neighbour *neigh);
96static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); 94static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb);
@@ -449,7 +447,8 @@ static void __ndisc_send(struct net_device *dev,
449{ 447{
450 struct flowi fl; 448 struct flowi fl;
451 struct dst_entry *dst; 449 struct dst_entry *dst;
452 struct sock *sk = ndisc_socket->sk; 450 struct net *net = dev->nd_net;
451 struct sock *sk = net->ipv6.ndisc_sk;
453 struct sk_buff *skb; 452 struct sk_buff *skb;
454 struct icmp6hdr *hdr; 453 struct icmp6hdr *hdr;
455 struct inet6_dev *idev; 454 struct inet6_dev *idev;
@@ -459,8 +458,7 @@ static void __ndisc_send(struct net_device *dev,
459 458
460 type = icmp6h->icmp6_type; 459 type = icmp6h->icmp6_type;
461 460
462 icmpv6_flow_init(ndisc_socket->sk, &fl, type, 461 icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex);
463 saddr, daddr, dev->ifindex);
464 462
465 dst = icmp6_dst_alloc(dev, neigh, daddr); 463 dst = icmp6_dst_alloc(dev, neigh, daddr);
466 if (!dst) 464 if (!dst)
@@ -1394,13 +1392,14 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
1394void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, 1392void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
1395 struct in6_addr *target) 1393 struct in6_addr *target)
1396{ 1394{
1397 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;
1398 int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); 1398 int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
1399 struct sk_buff *buff; 1399 struct sk_buff *buff;
1400 struct icmp6hdr *icmph; 1400 struct icmp6hdr *icmph;
1401 struct in6_addr saddr_buf; 1401 struct in6_addr saddr_buf;
1402 struct in6_addr *addrp; 1402 struct in6_addr *addrp;
1403 struct net_device *dev;
1404 struct rt6_info *rt; 1403 struct rt6_info *rt;
1405 struct dst_entry *dst; 1404 struct dst_entry *dst;
1406 struct inet6_dev *idev; 1405 struct inet6_dev *idev;
@@ -1411,8 +1410,6 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
1411 int hlen; 1410 int hlen;
1412 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; 1411 u8 ha_buf[MAX_ADDR_LEN], *ha = NULL;
1413 1412
1414 dev = skb->dev;
1415
1416 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { 1413 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
1417 ND_PRINTK2(KERN_WARNING 1414 ND_PRINTK2(KERN_WARNING
1418 "ICMPv6 Redirect: no link-local address on %s\n", 1415 "ICMPv6 Redirect: no link-local address on %s\n",
@@ -1427,10 +1424,10 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
1427 return; 1424 return;
1428 } 1425 }
1429 1426
1430 icmpv6_flow_init(ndisc_socket->sk, &fl, NDISC_REDIRECT, 1427 icmpv6_flow_init(sk, &fl, NDISC_REDIRECT,
1431 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); 1428 &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex);
1432 1429
1433 dst = ip6_route_output(&init_net, NULL, &fl); 1430 dst = ip6_route_output(net, NULL, &fl);
1434 if (dst == NULL) 1431 if (dst == NULL)
1435 return; 1432 return;
1436 1433
@@ -1719,22 +1716,24 @@ static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
1719 1716
1720#endif 1717#endif
1721 1718
1722int __init ndisc_init(void) 1719static int ndisc_net_init(struct net *net)
1723{ 1720{
1721 struct socket *sock;
1724 struct ipv6_pinfo *np; 1722 struct ipv6_pinfo *np;
1725 struct sock *sk; 1723 struct sock *sk;
1726 int err; 1724 int err;
1727 1725
1728 err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &ndisc_socket); 1726 err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock);
1729 if (err < 0) { 1727 if (err < 0) {
1730 ND_PRINTK0(KERN_ERR 1728 ND_PRINTK0(KERN_ERR
1731 "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n", 1729 "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n",
1732 err); 1730 err);
1733 ndisc_socket = NULL; /* For safety. */
1734 return err; 1731 return err;
1735 } 1732 }
1736 1733
1737 sk = ndisc_socket->sk; 1734 net->ipv6.ndisc_sk = sk = sock->sk;
1735 sk_change_net(sk, net);
1736
1738 np = inet6_sk(sk); 1737 np = inet6_sk(sk);
1739 sk->sk_allocation = GFP_ATOMIC; 1738 sk->sk_allocation = GFP_ATOMIC;
1740 np->hop_limit = 255; 1739 np->hop_limit = 255;
@@ -1742,21 +1741,52 @@ int __init ndisc_init(void)
1742 np->mc_loop = 0; 1741 np->mc_loop = 0;
1743 sk->sk_prot->unhash(sk); 1742 sk->sk_prot->unhash(sk);
1744 1743
1744 return 0;
1745}
1746
1747static void ndisc_net_exit(struct net *net)
1748{
1749 sk_release_kernel(net->ipv6.ndisc_sk);
1750}
1751
1752static struct pernet_operations ndisc_net_ops = {
1753 .init = ndisc_net_init,
1754 .exit = ndisc_net_exit,
1755};
1756
1757int __init ndisc_init(void)
1758{
1759 int err;
1760
1761 err = register_pernet_subsys(&ndisc_net_ops);
1762 if (err)
1763 return err;
1745 /* 1764 /*
1746 * Initialize the neighbour table 1765 * Initialize the neighbour table
1747 */ 1766 */
1748
1749 neigh_table_init(&nd_tbl); 1767 neigh_table_init(&nd_tbl);
1750 1768
1751#ifdef CONFIG_SYSCTL 1769#ifdef CONFIG_SYSCTL
1752 neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, 1770 err = neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6,
1753 "ipv6", 1771 NET_IPV6_NEIGH, "ipv6",
1754 &ndisc_ifinfo_sysctl_change, 1772 &ndisc_ifinfo_sysctl_change,
1755 &ndisc_ifinfo_sysctl_strategy); 1773 &ndisc_ifinfo_sysctl_strategy);
1774 if (err)
1775 goto out_unregister_pernet;
1756#endif 1776#endif
1777 err = register_netdevice_notifier(&ndisc_netdev_notifier);
1778 if (err)
1779 goto out_unregister_sysctl;
1780out:
1781 return err;
1757 1782
1758 register_netdevice_notifier(&ndisc_netdev_notifier); 1783out_unregister_sysctl:
1759 return 0; 1784#ifdef CONFIG_SYSCTL
1785 neigh_sysctl_unregister(&nd_tbl.parms);
1786out_unregister_pernet:
1787#endif
1788 unregister_pernet_subsys(&ndisc_net_ops);
1789 goto out;
1760} 1790}
1761 1791
1762void ndisc_cleanup(void) 1792void ndisc_cleanup(void)
@@ -1766,6 +1796,5 @@ void ndisc_cleanup(void)
1766 neigh_sysctl_unregister(&nd_tbl.parms); 1796 neigh_sysctl_unregister(&nd_tbl.parms);
1767#endif 1797#endif
1768 neigh_table_clear(&nd_tbl); 1798 neigh_table_clear(&nd_tbl);
1769 sock_release(ndisc_socket); 1799 unregister_pernet_subsys(&ndisc_net_ops);
1770 ndisc_socket = NULL; /* For safety. */
1771} 1800}