diff options
Diffstat (limited to 'net/ipv6/ip6_input.c')
-rw-r--r-- | net/ipv6/ip6_input.c | 42 |
1 files changed, 28 insertions, 14 deletions
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 6b8e6d76a58..ad0b8abcdf4 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -60,14 +60,22 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt { struct ipv6hdr *hdr; u32 pkt_len; + struct inet6_dev *idev; - if (skb->pkt_type == PACKET_OTHERHOST) - goto drop; + if (skb->pkt_type == PACKET_OTHERHOST) { + kfree_skb(skb); + return 0; + } + + rcu_read_lock(); - IP6_INC_STATS_BH(IPSTATS_MIB_INRECEIVES); + idev = __in6_dev_get(skb->dev); + + IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES); if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - IP6_INC_STATS_BH(IPSTATS_MIB_INDISCARDS); + IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS); + rcu_read_unlock(); goto out; } @@ -84,7 +92,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt * arrived via the sending interface (ethX), because of the * nature of scoping architecture. --yoshfuji */ - IP6CB(skb)->iif = skb->dst ? ((struct rt6_info *)skb->dst)->rt6i_idev->dev->ifindex : dev->ifindex; + IP6CB(skb)->iif = skb->dst ? ip6_dst_idev(skb->dst)->dev->ifindex : dev->ifindex; if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) goto err; @@ -104,7 +112,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt if (pkt_len + sizeof(struct ipv6hdr) > skb->len) goto truncated; if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) { - IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); + IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS); goto drop; } hdr = skb->nh.ipv6h; @@ -112,17 +120,21 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt if (hdr->nexthdr == NEXTHDR_HOP) { if (ipv6_parse_hopopts(&skb) < 0) { - IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); + IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS); + rcu_read_unlock(); return 0; } } + rcu_read_unlock(); + return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish); truncated: - IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS); + IP6_INC_STATS_BH(idev, IPSTATS_MIB_INTRUNCATEDPKTS); err: - IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); + IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS); drop: + rcu_read_unlock(); kfree_skb(skb); out: return 0; @@ -140,6 +152,7 @@ static inline int ip6_input_finish(struct sk_buff *skb) unsigned int nhoff; int nexthdr; u8 hash; + struct inet6_dev *idev; /* * Parse extension headers @@ -147,6 +160,7 @@ static inline int ip6_input_finish(struct sk_buff *skb) rcu_read_lock(); resubmit: + idev = ip6_dst_idev(skb->dst); if (!pskb_pull(skb, skb->h.raw - skb->data)) goto discard; nhoff = IP6CB(skb)->nhoff; @@ -185,24 +199,24 @@ resubmit: if (ret > 0) goto resubmit; else if (ret == 0) - IP6_INC_STATS_BH(IPSTATS_MIB_INDELIVERS); + IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS); } else { if (!raw_sk) { if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { - IP6_INC_STATS_BH(IPSTATS_MIB_INUNKNOWNPROTOS); + IP6_INC_STATS_BH(idev, IPSTATS_MIB_INUNKNOWNPROTOS); icmpv6_send(skb, ICMPV6_PARAMPROB, ICMPV6_UNK_NEXTHDR, nhoff, skb->dev); } } else - IP6_INC_STATS_BH(IPSTATS_MIB_INDELIVERS); + IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS); kfree_skb(skb); } rcu_read_unlock(); return 0; discard: - IP6_INC_STATS_BH(IPSTATS_MIB_INDISCARDS); + IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS); rcu_read_unlock(); kfree_skb(skb); return 0; @@ -219,7 +233,7 @@ int ip6_mc_input(struct sk_buff *skb) struct ipv6hdr *hdr; int deliver; - IP6_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS); + IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCASTPKTS); hdr = skb->nh.ipv6h; deliver = likely(!(skb->dev->flags & (IFF_PROMISC|IFF_ALLMULTI))) || |