ndisc: Reduce number of arguments for ndisc_fill_addr_option().
[deliverable/linux.git] / net / ipv6 / ndisc.c
index f2a007b7bde34d38f5b9b7f49c41ce77b136d04c..49dfc2a73ee04bbc543d669e1a384a0476d8154c 100644 (file)
@@ -148,10 +148,11 @@ static inline int ndisc_opt_addr_space(struct net_device *dev)
        return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type));
 }
 
-static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data, int data_len,
-                                 unsigned short addr_type)
+static u8 *ndisc_fill_addr_option(u8 *opt, int type, void *data,
+                                 struct net_device *dev)
 {
-       int pad   = ndisc_addr_option_pad(addr_type);
+       int pad   = ndisc_addr_option_pad(dev->type);
+       int data_len = dev->addr_len;
        int space = NDISC_OPT_SPACE(data_len + pad);
 
        opt[0] = type;
@@ -395,7 +396,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
                len += ndisc_opt_addr_space(dev);
 
        skb = sock_alloc_send_skb(sk,
-                                 (MAX_HEADER + sizeof(struct ipv6hdr) +
+                                 (sizeof(struct ipv6hdr) +
                                   len + hlen + tlen),
                                  1, &err);
        if (!skb) {
@@ -420,8 +421,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
        }
 
        if (llinfo)
-               ndisc_fill_addr_option(opt, llinfo, dev->dev_addr,
-                                      dev->addr_len, dev->type);
+               ndisc_fill_addr_option(opt, llinfo, dev->dev_addr, dev);
 
        hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len,
                                           IPPROTO_ICMPV6,
@@ -432,7 +432,6 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
 }
 
 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)
@@ -448,7 +447,7 @@ static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev,
        type = icmp6h->icmp6_type;
 
        icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex);
-       dst = icmp6_dst_alloc(dev, neigh, &fl6);
+       dst = icmp6_dst_alloc(dev, &fl6);
        if (IS_ERR(dst)) {
                kfree_skb(skb);
                return;
@@ -474,7 +473,6 @@ static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev,
  *     Send a Neighbour Discover packet
  */
 static void __ndisc_send(struct net_device *dev,
-                        struct neighbour *neigh,
                         const struct in6_addr *daddr,
                         const struct in6_addr *saddr,
                         struct icmp6hdr *icmp6h, const struct in6_addr *target,
@@ -486,13 +484,13 @@ static void __ndisc_send(struct net_device *dev,
        if (!skb)
                return;
 
-       ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h);
+       ndisc_send_skb(skb, dev, daddr, saddr, icmp6h);
 }
 
 static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
                          const struct in6_addr *daddr,
                          const struct in6_addr *solicited_addr,
-                         int router, int solicited, int override, int inc_opt)
+                         bool router, bool solicited, bool override, bool inc_opt)
 {
        struct in6_addr tmpaddr;
        struct inet6_ifaddr *ifp;
@@ -521,8 +519,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
        icmp6h.icmp6_solicited = solicited;
        icmp6h.icmp6_override = override;
 
-       __ndisc_send(dev, neigh, daddr, src_addr,
-                    &icmp6h, solicited_addr,
+       __ndisc_send(dev, daddr, src_addr, &icmp6h, solicited_addr,
                     inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
 }
 
@@ -563,8 +560,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
                saddr = &addr_buf;
        }
 
-       __ndisc_send(dev, neigh, daddr, saddr,
-                    &icmp6h, solicit,
+       __ndisc_send(dev, daddr, saddr, &icmp6h, solicit,
                     !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);
 }
 
@@ -598,8 +594,7 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
                }
        }
 #endif
-       __ndisc_send(dev, NULL, daddr, saddr,
-                    &icmp6h, NULL,
+       __ndisc_send(dev, daddr, saddr, &icmp6h, NULL,
                     send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0);
 }
 
@@ -676,6 +671,11 @@ static void ndisc_recv_ns(struct sk_buff *skb)
        bool inc;
        int is_router = -1;
 
+       if (skb->len < sizeof(struct nd_msg)) {
+               ND_PRINTK(2, warn, "NS: packet too short\n");
+               return;
+       }
+
        if (ipv6_addr_is_multicast(&msg->target)) {
                ND_PRINTK(2, warn, "NS: multicast target address\n");
                return;
@@ -685,11 +685,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
         * RFC2461 7.1.1:
         * DAD has to be destined for solicited node multicast address.
         */
-       if (dad &&
-           !(daddr->s6_addr32[0] == htonl(0xff020000) &&
-             daddr->s6_addr32[1] == htonl(0x00000000) &&
-             daddr->s6_addr32[2] == htonl(0x00000001) &&
-             daddr->s6_addr [12] == 0xff )) {
+       if (dad && !ipv6_addr_is_solict_mult(daddr)) {
                ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n");
                return;
        }
@@ -780,11 +776,11 @@ static void ndisc_recv_ns(struct sk_buff *skb)
        }
 
        if (is_router < 0)
-               is_router = !!idev->cnf.forwarding;
+               is_router = idev->cnf.forwarding;
 
        if (dad) {
                ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target,
-                             is_router, 0, (ifp != NULL), 1);
+                             !!is_router, false, (ifp != NULL), true);
                goto out;
        }
 
@@ -805,8 +801,8 @@ static void ndisc_recv_ns(struct sk_buff *skb)
                             NEIGH_UPDATE_F_OVERRIDE);
        if (neigh || !dev->header_ops) {
                ndisc_send_na(dev, neigh, saddr, &msg->target,
-                             is_router,
-                             1, (ifp != NULL && inc), inc);
+                             !!is_router,
+                             true, (ifp != NULL && inc), inc);
                if (neigh)
                        neigh_release(neigh);
        }
@@ -1314,6 +1310,12 @@ out:
 
 static void ndisc_redirect_rcv(struct sk_buff *skb)
 {
+       u8 *hdr;
+       struct ndisc_options ndopts;
+       struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb);
+       u32 ndoptlen = skb->tail - (skb->transport_header +
+                                   offsetof(struct rd_msg, opt));
+
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
        switch (skb->ndisc_nodetype) {
        case NDISC_NODETYPE_HOST:
@@ -1330,6 +1332,17 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
                return;
        }
 
+       if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts))
+               return;
+
+       if (!ndopts.nd_opts_rh)
+               return;
+
+       hdr = (u8 *)ndopts.nd_opts_rh;
+       hdr += 8;
+       if (!pskb_pull(skb, hdr - skb_transport_header(skb)))
+               return;
+
        icmpv6_notify(skb, NDISC_REDIRECT, 0, 0);
 }
 
@@ -1338,12 +1351,11 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
        struct net_device *dev = skb->dev;
        struct net *net = dev_net(dev);
        struct sock *sk = net->ipv6.ndisc_sk;
-       int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
+       int len = sizeof(struct rd_msg);
        struct inet_peer *peer;
        struct sk_buff *buff;
-       struct icmp6hdr *icmph;
+       struct rd_msg *msg;
        struct in6_addr saddr_buf;
-       struct in6_addr *addrp;
        struct rt6_info *rt;
        struct dst_entry *dst;
        struct inet6_dev *idev;
@@ -1422,7 +1434,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
        hlen = LL_RESERVED_SPACE(dev);
        tlen = dev->needed_tailroom;
        buff = sock_alloc_send_skb(sk,
-                                  (MAX_HEADER + sizeof(struct ipv6hdr) +
+                                  (sizeof(struct ipv6hdr) +
                                    len + hlen + tlen),
                                   1, &err);
        if (buff == NULL) {
@@ -1438,29 +1450,26 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 
        skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data);
        skb_put(buff, len);
-       icmph = icmp6_hdr(buff);
+       msg = (struct rd_msg *)icmp6_hdr(buff);
 
-       memset(icmph, 0, sizeof(struct icmp6hdr));
-       icmph->icmp6_type = NDISC_REDIRECT;
+       memset(&msg->icmph, 0, sizeof(struct icmp6hdr));
+       msg->icmph.icmp6_type = NDISC_REDIRECT;
 
        /*
         *      copy target and destination addresses
         */
 
-       addrp = (struct in6_addr *)(icmph + 1);
-       *addrp = *target;
-       addrp++;
-       *addrp = ipv6_hdr(skb)->daddr;
+       msg->target = *target;
+       msg->dest = ipv6_hdr(skb)->daddr;
 
-       opt = (u8*) (addrp + 1);
+       opt = msg->opt;
 
        /*
         *      include target_address option
         */
 
        if (ha)
-               opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha,
-                                            dev->addr_len, dev->type);
+               opt = ndisc_fill_addr_option(opt, ND_OPT_TARGET_LL_ADDR, ha, dev);
 
        /*
         *      build redirect option and copy skb over to the new packet.
@@ -1473,9 +1482,9 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
 
        memcpy(opt, ipv6_hdr(skb), rd_len - 8);
 
-       icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
-                                            len, IPPROTO_ICMPV6,
-                                            csum_partial(icmph, len, 0));
+       msg->icmph.icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr,
+                                                len, IPPROTO_ICMPV6,
+                                                csum_partial(msg, len, 0));
 
        skb_dst_set(buff, dst);
        rcu_read_lock();
This page took 0.030243 seconds and 5 git commands to generate.