diff options
Diffstat (limited to 'net/ipv6/ip6_input.c')
-rw-r--r-- | net/ipv6/ip6_input.c | 40 |
1 files changed, 27 insertions, 13 deletions
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index ebf54ae90a0c..ad0b8abcdf4b 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 | |||
60 | { | 60 | { |
61 | struct ipv6hdr *hdr; | 61 | struct ipv6hdr *hdr; |
62 | u32 pkt_len; | 62 | u32 pkt_len; |
63 | struct inet6_dev *idev; | ||
63 | 64 | ||
64 | if (skb->pkt_type == PACKET_OTHERHOST) | 65 | if (skb->pkt_type == PACKET_OTHERHOST) { |
65 | goto drop; | 66 | kfree_skb(skb); |
67 | return 0; | ||
68 | } | ||
69 | |||
70 | rcu_read_lock(); | ||
66 | 71 | ||
67 | IP6_INC_STATS_BH(IPSTATS_MIB_INRECEIVES); | 72 | idev = __in6_dev_get(skb->dev); |
73 | |||
74 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES); | ||
68 | 75 | ||
69 | if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { | 76 | if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { |
70 | IP6_INC_STATS_BH(IPSTATS_MIB_INDISCARDS); | 77 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS); |
78 | rcu_read_unlock(); | ||
71 | goto out; | 79 | goto out; |
72 | } | 80 | } |
73 | 81 | ||
@@ -104,7 +112,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
104 | if (pkt_len + sizeof(struct ipv6hdr) > skb->len) | 112 | if (pkt_len + sizeof(struct ipv6hdr) > skb->len) |
105 | goto truncated; | 113 | goto truncated; |
106 | if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) { | 114 | if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) { |
107 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 115 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS); |
108 | goto drop; | 116 | goto drop; |
109 | } | 117 | } |
110 | hdr = skb->nh.ipv6h; | 118 | hdr = skb->nh.ipv6h; |
@@ -112,17 +120,21 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt | |||
112 | 120 | ||
113 | if (hdr->nexthdr == NEXTHDR_HOP) { | 121 | if (hdr->nexthdr == NEXTHDR_HOP) { |
114 | if (ipv6_parse_hopopts(&skb) < 0) { | 122 | if (ipv6_parse_hopopts(&skb) < 0) { |
115 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 123 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS); |
124 | rcu_read_unlock(); | ||
116 | return 0; | 125 | return 0; |
117 | } | 126 | } |
118 | } | 127 | } |
119 | 128 | ||
129 | rcu_read_unlock(); | ||
130 | |||
120 | return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish); | 131 | return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish); |
121 | truncated: | 132 | truncated: |
122 | IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS); | 133 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INTRUNCATEDPKTS); |
123 | err: | 134 | err: |
124 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 135 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS); |
125 | drop: | 136 | drop: |
137 | rcu_read_unlock(); | ||
126 | kfree_skb(skb); | 138 | kfree_skb(skb); |
127 | out: | 139 | out: |
128 | return 0; | 140 | return 0; |
@@ -140,6 +152,7 @@ static inline int ip6_input_finish(struct sk_buff *skb) | |||
140 | unsigned int nhoff; | 152 | unsigned int nhoff; |
141 | int nexthdr; | 153 | int nexthdr; |
142 | u8 hash; | 154 | u8 hash; |
155 | struct inet6_dev *idev; | ||
143 | 156 | ||
144 | /* | 157 | /* |
145 | * Parse extension headers | 158 | * Parse extension headers |
@@ -147,6 +160,7 @@ static inline int ip6_input_finish(struct sk_buff *skb) | |||
147 | 160 | ||
148 | rcu_read_lock(); | 161 | rcu_read_lock(); |
149 | resubmit: | 162 | resubmit: |
163 | idev = ip6_dst_idev(skb->dst); | ||
150 | if (!pskb_pull(skb, skb->h.raw - skb->data)) | 164 | if (!pskb_pull(skb, skb->h.raw - skb->data)) |
151 | goto discard; | 165 | goto discard; |
152 | nhoff = IP6CB(skb)->nhoff; | 166 | nhoff = IP6CB(skb)->nhoff; |
@@ -185,24 +199,24 @@ resubmit: | |||
185 | if (ret > 0) | 199 | if (ret > 0) |
186 | goto resubmit; | 200 | goto resubmit; |
187 | else if (ret == 0) | 201 | else if (ret == 0) |
188 | IP6_INC_STATS_BH(IPSTATS_MIB_INDELIVERS); | 202 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS); |
189 | } else { | 203 | } else { |
190 | if (!raw_sk) { | 204 | if (!raw_sk) { |
191 | if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { | 205 | if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { |
192 | IP6_INC_STATS_BH(IPSTATS_MIB_INUNKNOWNPROTOS); | 206 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INUNKNOWNPROTOS); |
193 | icmpv6_send(skb, ICMPV6_PARAMPROB, | 207 | icmpv6_send(skb, ICMPV6_PARAMPROB, |
194 | ICMPV6_UNK_NEXTHDR, nhoff, | 208 | ICMPV6_UNK_NEXTHDR, nhoff, |
195 | skb->dev); | 209 | skb->dev); |
196 | } | 210 | } |
197 | } else | 211 | } else |
198 | IP6_INC_STATS_BH(IPSTATS_MIB_INDELIVERS); | 212 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS); |
199 | kfree_skb(skb); | 213 | kfree_skb(skb); |
200 | } | 214 | } |
201 | rcu_read_unlock(); | 215 | rcu_read_unlock(); |
202 | return 0; | 216 | return 0; |
203 | 217 | ||
204 | discard: | 218 | discard: |
205 | IP6_INC_STATS_BH(IPSTATS_MIB_INDISCARDS); | 219 | IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS); |
206 | rcu_read_unlock(); | 220 | rcu_read_unlock(); |
207 | kfree_skb(skb); | 221 | kfree_skb(skb); |
208 | return 0; | 222 | return 0; |
@@ -219,7 +233,7 @@ int ip6_mc_input(struct sk_buff *skb) | |||
219 | struct ipv6hdr *hdr; | 233 | struct ipv6hdr *hdr; |
220 | int deliver; | 234 | int deliver; |
221 | 235 | ||
222 | IP6_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS); | 236 | IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCASTPKTS); |
223 | 237 | ||
224 | hdr = skb->nh.ipv6h; | 238 | hdr = skb->nh.ipv6h; |
225 | deliver = likely(!(skb->dev->flags & (IFF_PROMISC|IFF_ALLMULTI))) || | 239 | deliver = likely(!(skb->dev->flags & (IFF_PROMISC|IFF_ALLMULTI))) || |