]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - net/ipv4/ip_input.c
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/upstream-linus
[mv-sheeva.git] / net / ipv4 / ip_input.c
index d930dc5e4d85a752ddb7af15b482b47108b62241..d859bcc26cb7e568b60261e8a0703add32a92798 100644 (file)
 #include <linux/netlink.h>
 
 /*
- *     Process Router Attention IP option
+ *     Process Router Attention IP option (RFC 2113)
  */
 int ip_call_ra_chain(struct sk_buff *skb)
 {
@@ -155,8 +155,7 @@ int ip_call_ra_chain(struct sk_buff *skb)
        struct sock *last = NULL;
        struct net_device *dev = skb->dev;
 
-       read_lock(&ip_ra_lock);
-       for (ra = ip_ra_chain; ra; ra = ra->next) {
+       for (ra = rcu_dereference(ip_ra_chain); ra; ra = rcu_dereference(ra->next)) {
                struct sock *sk = ra->sk;
 
                /* If socket is bound to an interface, only report
@@ -167,10 +166,8 @@ int ip_call_ra_chain(struct sk_buff *skb)
                     sk->sk_bound_dev_if == dev->ifindex) &&
                    net_eq(sock_net(sk), dev_net(dev))) {
                        if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) {
-                               if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) {
-                                       read_unlock(&ip_ra_lock);
+                               if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN))
                                        return 1;
-                               }
                        }
                        if (last) {
                                struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
@@ -183,10 +180,8 @@ int ip_call_ra_chain(struct sk_buff *skb)
 
        if (last) {
                raw_rcv(last, skb);
-               read_unlock(&ip_ra_lock);
                return 1;
        }
-       read_unlock(&ip_ra_lock);
        return 0;
 }
 
@@ -298,18 +293,16 @@ static inline int ip_rcv_options(struct sk_buff *skb)
        }
 
        if (unlikely(opt->srr)) {
-               struct in_device *in_dev = in_dev_get(dev);
+               struct in_device *in_dev = __in_dev_get_rcu(dev);
+
                if (in_dev) {
                        if (!IN_DEV_SOURCE_ROUTE(in_dev)) {
                                if (IN_DEV_LOG_MARTIANS(in_dev) &&
                                    net_ratelimit())
                                        printk(KERN_INFO "source route option %pI4 -> %pI4\n",
                                               &iph->saddr, &iph->daddr);
-                               in_dev_put(in_dev);
                                goto drop;
                        }
-
-                       in_dev_put(in_dev);
                }
 
                if (ip_options_rcv_srr(skb))
@@ -340,13 +333,16 @@ static int ip_rcv_finish(struct sk_buff *skb)
                        else if (err == -ENETUNREACH)
                                IP_INC_STATS_BH(dev_net(skb->dev),
                                                IPSTATS_MIB_INNOROUTES);
+                       else if (err == -EXDEV)
+                               NET_INC_STATS_BH(dev_net(skb->dev),
+                                                LINUX_MIB_IPRPFILTER);
                        goto drop;
                }
        }
 
 #ifdef CONFIG_NET_CLS_ROUTE
        if (unlikely(skb_dst(skb)->tclassid)) {
-               struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id());
+               struct ip_rt_acct *st = this_cpu_ptr(ip_rt_acct);
                u32 idx = skb_dst(skb)->tclassid;
                st[idx&0xFF].o_packets++;
                st[idx&0xFF].o_bytes += skb->len;
@@ -360,10 +356,10 @@ static int ip_rcv_finish(struct sk_buff *skb)
 
        rt = skb_rtable(skb);
        if (rt->rt_type == RTN_MULTICAST) {
-               IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCAST,
+               IP_UPD_PO_STATS_BH(dev_net(rt->dst.dev), IPSTATS_MIB_INMCAST,
                                skb->len);
        } else if (rt->rt_type == RTN_BROADCAST)
-               IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCAST,
+               IP_UPD_PO_STATS_BH(dev_net(rt->dst.dev), IPSTATS_MIB_INBCAST,
                                skb->len);
 
        return dst_input(skb);