aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/netfilter/nf_reject_ipv6.c35
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}
209EXPORT_SYMBOL_GPL(nf_send_reset6); 209EXPORT_SYMBOL_GPL(nf_send_reset6);
210 210
211static 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
233void 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}
244EXPORT_SYMBOL_GPL(nf_send_unreach6);
245
211MODULE_LICENSE("GPL"); 246MODULE_LICENSE("GPL");