]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/ipv6/ndisc.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
[karo-tx-linux.git] / net / ipv6 / ndisc.c
index 9da6e02eaaebffdb47949ff0c0fbf43dc1b9a208..44e5b7f2a6c1badcbf4dbb5ed2a844ae2daa199c 100644 (file)
@@ -370,17 +370,14 @@ static int ndisc_constructor(struct neighbour *neigh)
        struct neigh_parms *parms;
        int is_multicast = ipv6_addr_is_multicast(addr);
 
-       rcu_read_lock();
        in6_dev = in6_dev_get(dev);
        if (in6_dev == NULL) {
-               rcu_read_unlock();
                return -EINVAL;
        }
 
        parms = in6_dev->nd_parms;
        __neigh_parms_put(neigh->parms);
        neigh->parms = neigh_parms_clone(parms);
-       rcu_read_unlock();
 
        neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST;
        if (!dev->header_ops) {
@@ -533,7 +530,8 @@ void ndisc_send_skb(struct sk_buff *skb,
 
        skb_dst_set(skb, dst);
 
-       idev = in6_dev_get(dst->dev);
+       rcu_read_lock();
+       idev = __in6_dev_get(dst->dev);
        IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
 
        err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
@@ -543,8 +541,7 @@ void ndisc_send_skb(struct sk_buff *skb,
                ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
        }
 
-       if (likely(idev != NULL))
-               in6_dev_put(idev);
+       rcu_read_unlock();
 }
 
 EXPORT_SYMBOL(ndisc_send_skb);
@@ -1039,7 +1036,7 @@ static void ndisc_recv_rs(struct sk_buff *skb)
        if (skb->len < sizeof(*rs_msg))
                return;
 
-       idev = in6_dev_get(skb->dev);
+       idev = __in6_dev_get(skb->dev);
        if (!idev) {
                if (net_ratelimit())
                        ND_PRINTK1("ICMP6 RS: can't find in6 device\n");
@@ -1080,7 +1077,7 @@ static void ndisc_recv_rs(struct sk_buff *skb)
                neigh_release(neigh);
        }
 out:
-       in6_dev_put(idev);
+       return;
 }
 
 static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
@@ -1179,7 +1176,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
         *      set the RA_RECV flag in the interface
         */
 
-       in6_dev = in6_dev_get(skb->dev);
+       in6_dev = __in6_dev_get(skb->dev);
        if (in6_dev == NULL) {
                ND_PRINTK0(KERN_ERR
                           "ICMPv6 RA: can't find inet6 device for %s.\n",
@@ -1188,7 +1185,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
        }
 
        if (!ndisc_parse_options(opt, optlen, &ndopts)) {
-               in6_dev_put(in6_dev);
                ND_PRINTK2(KERN_WARNING
                           "ICMP6 RA: invalid ND options\n");
                return;
@@ -1225,6 +1221,9 @@ static void ndisc_router_discovery(struct sk_buff *skb)
        if (!in6_dev->cnf.accept_ra_defrtr)
                goto skip_defrtr;
 
+       if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
+               goto skip_defrtr;
+
        lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);
 
 #ifdef CONFIG_IPV6_ROUTER_PREF
@@ -1255,7 +1254,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                        ND_PRINTK0(KERN_ERR
                                   "ICMPv6 RA: %s() failed to add default route.\n",
                                   __func__);
-                       in6_dev_put(in6_dev);
                        return;
                }
 
@@ -1265,7 +1263,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
                                   "ICMPv6 RA: %s() got default router without neighbour.\n",
                                   __func__);
                        dst_release(&rt->dst);
-                       in6_dev_put(in6_dev);
                        return;
                }
                neigh->flags |= NTF_ROUTER;
@@ -1349,6 +1346,9 @@ skip_linkparms:
                goto out;
 
 #ifdef CONFIG_IPV6_ROUTE_INFO
+       if (ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, NULL, 0))
+               goto skip_routeinfo;
+
        if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) {
                struct nd_opt_hdr *p;
                for (p = ndopts.nd_opts_ri;
@@ -1366,6 +1366,8 @@ skip_linkparms:
                                      &ipv6_hdr(skb)->saddr);
                }
        }
+
+skip_routeinfo:
 #endif
 
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
@@ -1422,7 +1424,6 @@ out:
                dst_release(&rt->dst);
        else if (neigh)
                neigh_release(neigh);
-       in6_dev_put(in6_dev);
 }
 
 static void ndisc_redirect_rcv(struct sk_buff *skb)
@@ -1481,13 +1482,11 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
                return;
        }
 
-       in6_dev = in6_dev_get(skb->dev);
+       in6_dev = __in6_dev_get(skb->dev);
        if (!in6_dev)
                return;
-       if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) {
-               in6_dev_put(in6_dev);
+       if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
                return;
-       }
 
        /* RFC2461 8.1:
         *      The IP source address of the Redirect MUST be the same as the current
@@ -1497,7 +1496,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
        if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
                ND_PRINTK2(KERN_WARNING
                           "ICMPv6 Redirect: invalid ND options\n");
-               in6_dev_put(in6_dev);
                return;
        }
        if (ndopts.nd_opts_tgt_lladdr) {
@@ -1506,7 +1504,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
                if (!lladdr) {
                        ND_PRINTK2(KERN_WARNING
                                   "ICMPv6 Redirect: invalid link-layer address length\n");
-                       in6_dev_put(in6_dev);
                        return;
                }
        }
@@ -1518,7 +1515,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
                             on_link);
                neigh_release(neigh);
        }
-       in6_dev_put(in6_dev);
 }
 
 void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
@@ -1651,7 +1647,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
                                             csum_partial(icmph, len, 0));
 
        skb_dst_set(buff, dst);
-       idev = in6_dev_get(dst->dev);
+       rcu_read_lock();
+       idev = __in6_dev_get(dst->dev);
        IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
        err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
                      dst_output);
@@ -1660,8 +1657,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
                ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
        }
 
-       if (likely(idev != NULL))
-               in6_dev_put(idev);
+       rcu_read_unlock();
        return;
 
 release: