ndisc: Fix padding error in link-layer address option.
[cascardo/linux.git] / net / ipv6 / ndisc.c
index 2edce30..f2a007b 100644 (file)
@@ -151,8 +151,8 @@ static inline int ndisc_opt_addr_space(struct net_device *dev)
 static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len,
                                  unsigned short addr_type)
 {
-       int space = NDISC_OPT_SPACE(data_len);
        int pad   = ndisc_addr_option_pad(addr_type);
+       int space = NDISC_OPT_SPACE(data_len + pad);
 
        opt[0] = type;
        opt[1] = space>>3;
@@ -370,12 +370,12 @@ static void pndisc_destructor(struct pneigh_entry *n)
        ipv6_dev_mc_dec(dev, &maddr);
 }
 
-struct sk_buff *ndisc_build_skb(struct net_device *dev,
-                               const struct in6_addr *daddr,
-                               const struct in6_addr *saddr,
-                               struct icmp6hdr *icmp6h,
-                               const struct in6_addr *target,
-                               int llinfo)
+static struct sk_buff *ndisc_build_skb(struct net_device *dev,
+                                      const struct in6_addr *daddr,
+                                      const struct in6_addr *saddr,
+                                      struct icmp6hdr *icmp6h,
+                                      const struct in6_addr *target,
+                                      int llinfo)
 {
        struct net *net = dev_net(dev);
        struct sock *sk = net->ipv6.ndisc_sk;
@@ -431,14 +431,11 @@ struct sk_buff *ndisc_build_skb(struct net_device *dev,
        return skb;
 }
 
-EXPORT_SYMBOL(ndisc_build_skb);
-
-void ndisc_send_skb(struct sk_buff *skb,
-                   struct net_device *dev,
-                   struct neighbour *neigh,
-                   const struct in6_addr *daddr,
-                   const struct in6_addr *saddr,
-                   struct icmp6hdr *icmp6h)
+static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev,
+                          struct neighbour *neigh,
+                          const struct in6_addr *daddr,
+                          const struct in6_addr *saddr,
+                          struct icmp6hdr *icmp6h)
 {
        struct flowi6 fl6;
        struct dst_entry *dst;
@@ -473,8 +470,6 @@ void ndisc_send_skb(struct sk_buff *skb,
        rcu_read_unlock();
 }
 
-EXPORT_SYMBOL(ndisc_send_skb);
-
 /*
  *     Send a Neighbour Discover packet
  */
@@ -535,7 +530,6 @@ static void ndisc_send_unsol_na(struct net_device *dev)
 {
        struct inet6_dev *idev;
        struct inet6_ifaddr *ifa;
-       struct in6_addr mcaddr = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
 
        idev = in6_dev_get(dev);
        if (!idev)
@@ -543,7 +537,7 @@ static void ndisc_send_unsol_na(struct net_device *dev)
 
        read_lock_bh(&idev->lock);
        list_for_each_entry(ifa, &idev->addr_list, if_list) {
-               ndisc_send_na(dev, NULL, &mcaddr, &ifa->addr,
+               ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &ifa->addr,
                              /*router=*/ !!idev->cnf.forwarding,
                              /*solicited=*/ false, /*override=*/ true,
                              /*inc_opt=*/ true);
@@ -905,7 +899,7 @@ static void ndisc_recv_na(struct sk_buff *skb)
                if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
                    net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp &&
                    pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) {
-                       /* XXX: idev->cnf.prixy_ndp */
+                       /* XXX: idev->cnf.proxy_ndp */
                        goto out;
                }
 
@@ -1033,18 +1027,6 @@ errout:
        rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err);
 }
 
-static inline int accept_ra(struct inet6_dev *in6_dev)
-{
-       /*
-        * If forwarding is enabled, RA are not accepted unless the special
-        * hybrid mode (accept_ra=2) is enabled.
-        */
-       if (in6_dev->cnf.forwarding && in6_dev->cnf.accept_ra < 2)
-               return 0;
-
-       return in6_dev->cnf.accept_ra;
-}
-
 static void ndisc_router_discovery(struct sk_buff *skb)
 {
        struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb);
@@ -1092,7 +1074,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                return;
        }
 
-       if (!accept_ra(in6_dev))
+       if (!ipv6_accept_ra(in6_dev))
                goto skip_linkparms;
 
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
@@ -1144,7 +1126,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                        ND_PRINTK(0, err,
                                  "RA: %s got default router without neighbour\n",
                                  __func__);
-                       dst_release(&rt->dst);
+                       ip6_rt_put(rt);
                        return;
                }
        }
@@ -1169,7 +1151,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                        ND_PRINTK(0, err,
                                  "RA: %s got default router without neighbour\n",
                                  __func__);
-                       dst_release(&rt->dst);
+                       ip6_rt_put(rt);
                        return;
                }
                neigh->flags |= NTF_ROUTER;
@@ -1248,7 +1230,7 @@ skip_linkparms:
                             NEIGH_UPDATE_F_ISROUTER);
        }
 
-       if (!accept_ra(in6_dev))
+       if (!ipv6_accept_ra(in6_dev))
                goto out;
 
 #ifdef CONFIG_IPV6_ROUTE_INFO
@@ -1325,8 +1307,7 @@ skip_routeinfo:
                ND_PRINTK(2, warn, "RA: invalid RA options\n");
        }
 out:
-       if (rt)
-               dst_release(&rt->dst);
+       ip6_rt_put(rt);
        if (neigh)
                neigh_release(neigh);
 }
@@ -1574,11 +1555,18 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
 {
        struct net_device *dev = ptr;
        struct net *net = dev_net(dev);
+       struct inet6_dev *idev;
 
        switch (event) {
        case NETDEV_CHANGEADDR:
                neigh_changeaddr(&nd_tbl, dev);
                fib6_run_gc(~0UL, net);
+               idev = in6_dev_get(dev);
+               if (!idev)
+                       break;
+               if (idev->cnf.ndisc_notify)
+                       ndisc_send_unsol_na(dev);
+               in6_dev_put(idev);
                break;
        case NETDEV_DOWN:
                neigh_ifdown(&nd_tbl, dev);