diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/netfilter/nf_reject_ipv6.c | 35 |
1 files changed, 35 insertions, 0 deletions
diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c index d05b36440e8b..68e0bb4db1bf 100644 --- a/net/ipv6/netfilter/nf_reject_ipv6.c +++ b/net/ipv6/netfilter/nf_reject_ipv6.c | |||
@@ -208,4 +208,39 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook) | |||
208 | } | 208 | } |
209 | EXPORT_SYMBOL_GPL(nf_send_reset6); | 209 | EXPORT_SYMBOL_GPL(nf_send_reset6); |
210 | 210 | ||
211 | static bool reject6_csum_ok(struct sk_buff *skb, int hook) | ||
212 | { | ||
213 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); | ||
214 | int thoff; | ||
215 | __be16 fo; | ||
216 | u8 proto; | ||
217 | |||
218 | if (skb->csum_bad) | ||
219 | return false; | ||
220 | |||
221 | if (skb_csum_unnecessary(skb)) | ||
222 | return true; | ||
223 | |||
224 | proto = ip6h->nexthdr; | ||
225 | thoff = ipv6_skip_exthdr(skb, ((u8*)(ip6h+1) - skb->data), &proto, &fo); | ||
226 | |||
227 | if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0) | ||
228 | return false; | ||
229 | |||
230 | return nf_ip6_checksum(skb, hook, thoff, proto) == 0; | ||
231 | } | ||
232 | |||
233 | void nf_send_unreach6(struct net *net, struct sk_buff *skb_in, | ||
234 | unsigned char code, unsigned int hooknum) | ||
235 | { | ||
236 | if (!reject6_csum_ok(skb_in, hooknum)) | ||
237 | return; | ||
238 | |||
239 | if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) | ||
240 | skb_in->dev = net->loopback_dev; | ||
241 | |||
242 | icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); | ||
243 | } | ||
244 | EXPORT_SYMBOL_GPL(nf_send_unreach6); | ||
245 | |||
211 | MODULE_LICENSE("GPL"); | 246 | MODULE_LICENSE("GPL"); |