diff options
-rw-r--r-- | include/net/netns/ipv6.h | 1 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 77 |
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 | ||
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); |
@@ -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) | |||
1394 | void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | 1392 | void 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 | ||
1722 | int __init ndisc_init(void) | 1719 | static 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 | |||
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; | ||
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; | ||
1780 | out: | ||
1781 | return err; | ||
1757 | 1782 | ||
1758 | register_netdevice_notifier(&ndisc_netdev_notifier); | 1783 | out_unregister_sysctl: |
1759 | 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; | ||
1760 | } | 1790 | } |
1761 | 1791 | ||
1762 | void ndisc_cleanup(void) | 1792 | void 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 | } |