ndisc: Add missing strategies for per-device retrans timer/reachable time settings.
[safe/jmp/linux-2.6] / net / ipv6 / ndisc.c
index 53b5460..282fdb3 100644 (file)
@@ -84,6 +84,7 @@
 
 #include <net/flow.h>
 #include <net/ip6_checksum.h>
+#include <net/inet_common.h>
 #include <linux/proc_fs.h>
 
 #include <linux/netfilter.h>
@@ -441,8 +442,9 @@ static void pndisc_destructor(struct pneigh_entry *n)
  */
 static void __ndisc_send(struct net_device *dev,
                         struct neighbour *neigh,
-                        struct in6_addr *daddr, struct in6_addr *saddr,
-                        struct icmp6hdr *icmp6h, struct in6_addr *target,
+                        const struct in6_addr *daddr,
+                        const struct in6_addr *saddr,
+                        struct icmp6hdr *icmp6h, const struct in6_addr *target,
                         int llinfo)
 {
        struct flowi fl;
@@ -477,7 +479,7 @@ static void __ndisc_send(struct net_device *dev,
 
        skb = sock_alloc_send_skb(sk,
                                  (MAX_HEADER + sizeof(struct ipv6hdr) +
-                                  len + LL_RESERVED_SPACE(dev)),
+                                  len + LL_ALLOCATED_SPACE(dev)),
                                  1, &err);
        if (!skb) {
                ND_PRINTK0(KERN_ERR
@@ -528,12 +530,13 @@ static void __ndisc_send(struct net_device *dev,
 }
 
 static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
-                  struct in6_addr *daddr, struct in6_addr *solicited_addr,
-                  int router, int solicited, int override, int inc_opt)
+                         const struct in6_addr *daddr,
+                         const struct in6_addr *solicited_addr,
+                         int router, int solicited, int override, int inc_opt)
 {
        struct in6_addr tmpaddr;
        struct inet6_ifaddr *ifp;
-       struct in6_addr *src_addr;
+       const struct in6_addr *src_addr;
        struct icmp6hdr icmp6h = {
                .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,
        };
@@ -563,8 +566,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
 }
 
 void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
-                  struct in6_addr *solicit,
-                  struct in6_addr *daddr, struct in6_addr *saddr)
+                  const struct in6_addr *solicit,
+                  const struct in6_addr *daddr, const struct in6_addr *saddr)
 {
        struct in6_addr addr_buf;
        struct icmp6hdr icmp6h = {
@@ -583,8 +586,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
                     !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);
 }
 
-void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
-                  struct in6_addr *daddr)
+void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
+                  const struct in6_addr *daddr)
 {
        struct icmp6hdr icmp6h = {
                .icmp6_type = NDISC_ROUTER_SOLICITATION,
@@ -815,10 +818,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
                is_router = !!idev->cnf.forwarding;
 
        if (dad) {
-               struct in6_addr maddr;
-
-               ipv6_addr_all_nodes(&maddr);
-               ndisc_send_na(dev, NULL, &maddr, &msg->target,
+               ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
                              is_router, 0, (ifp != NULL), 1);
                goto out;
        }
@@ -1092,11 +1092,13 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                return;
        }
 
+#ifdef CONFIG_IPV6_NDISC_NODETYPE
        if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) {
                ND_PRINTK2(KERN_WARNING
                           "ICMPv6 RA: from host or unauthorized router\n");
                return;
        }
+#endif
 
        /*
         *      set the RA_RECV flag in the interface
@@ -1121,9 +1123,11 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                return;
        }
 
+#ifdef CONFIG_IPV6_NDISC_NODETYPE
        /* skip link-specific parameters from interior routers */
        if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT)
                goto skip_linkparms;
+#endif
 
        if (in6_dev->if_flags & IF_RS_SENT) {
                /*
@@ -1239,7 +1243,9 @@ skip_defrtr:
                }
        }
 
+#ifdef CONFIG_IPV6_NDISC_NODETYPE
 skip_linkparms:
+#endif
 
        /*
         *      Process options.
@@ -1272,7 +1278,13 @@ skip_linkparms:
                for (p = ndopts.nd_opts_ri;
                     p;
                     p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) {
-                       if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
+                       struct route_info *ri = (struct route_info *)p;
+#ifdef CONFIG_IPV6_NDISC_NODETYPE
+                       if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT &&
+                           ri->prefix_len == 0)
+                               continue;
+#endif
+                       if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen)
                                continue;
                        rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3,
                                      &ipv6_hdr(skb)->saddr);
@@ -1280,9 +1292,11 @@ skip_linkparms:
        }
 #endif
 
+#ifdef CONFIG_IPV6_NDISC_NODETYPE
        /* skip link-specific ndopts from interior routers */
        if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT)
                goto out;
+#endif
 
        if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) {
                struct nd_opt_hdr *p;
@@ -1347,6 +1361,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
        int optlen;
        u8 *lladdr = NULL;
 
+#ifdef CONFIG_IPV6_NDISC_NODETYPE
        switch (skb->ndisc_nodetype) {
        case NDISC_NODETYPE_HOST:
        case NDISC_NODETYPE_NODEFAULT:
@@ -1354,6 +1369,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
                           "ICMPv6 Redirect: from host or unauthorized router\n");
                return;
        }
+#endif
 
        if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) {
                ND_PRINTK2(KERN_WARNING
@@ -1430,7 +1446,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
 }
 
 void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
-                        struct in6_addr *target)
+                        const struct in6_addr *target)
 {
        struct net_device *dev = skb->dev;
        struct net *net = dev_net(dev);
@@ -1505,7 +1521,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
 
        buff = sock_alloc_send_skb(sk,
                                   (MAX_HEADER + sizeof(struct ipv6hdr) +
-                                   len + LL_RESERVED_SPACE(dev)),
+                                   len + LL_ALLOCATED_SPACE(dev)),
                                   1, &err);
        if (buff == NULL) {
                ND_PRINTK0(KERN_ERR
@@ -1711,10 +1727,10 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, struct file * f
        return ret;
 }
 
-static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
-                                       int nlen, void __user *oldval,
-                                       size_t __user *oldlenp,
-                                       void __user *newval, size_t newlen)
+int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
+                                int nlen, void __user *oldval,
+                                size_t __user *oldlenp,
+                                void __user *newval, size_t newlen)
 {
        struct net_device *dev = ctl->extra1;
        struct inet6_dev *idev;
@@ -1755,12 +1771,12 @@ static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
 
 static int ndisc_net_init(struct net *net)
 {
-       struct socket *sock;
        struct ipv6_pinfo *np;
        struct sock *sk;
        int err;
 
-       err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock);
+       err = inet_ctl_sock_create(&sk, PF_INET6,
+                                  SOCK_RAW, IPPROTO_ICMPV6, net);
        if (err < 0) {
                ND_PRINTK0(KERN_ERR
                           "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n",
@@ -1768,22 +1784,19 @@ static int ndisc_net_init(struct net *net)
                return err;
        }
 
-       net->ipv6.ndisc_sk = sk = sock->sk;
-       sk_change_net(sk, net);
+       net->ipv6.ndisc_sk = sk;
 
        np = inet6_sk(sk);
-       sk->sk_allocation = GFP_ATOMIC;
        np->hop_limit = 255;
        /* Do not loopback ndisc messages */
        np->mc_loop = 0;
-       sk->sk_prot->unhash(sk);
 
        return 0;
 }
 
 static void ndisc_net_exit(struct net *net)
 {
-       sk_release_kernel(net->ipv6.ndisc_sk);
+       inet_ctl_sock_destroy(net->ipv6.ndisc_sk);
 }
 
 static struct pernet_operations ndisc_net_ops = {