diff options
Diffstat (limited to 'net/ipv6/reassembly.c')
| -rw-r--r-- | net/ipv6/reassembly.c | 20 | 
1 files changed, 16 insertions, 4 deletions
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 3c6a77290c6..0ba10e53a62 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -26,6 +26,9 @@   *	YOSHIFUJI,H. @USAGI	Always remove fragment header to   *				calculate ICV correctly.   */ + +#define pr_fmt(fmt) "IPv6: " fmt +  #include <linux/errno.h>  #include <linux/types.h>  #include <linux/string.h> @@ -185,9 +188,10 @@ fq_find(struct net *net, __be32 id, const struct in6_addr *src, const struct in6  	hash = inet6_hash_frag(id, src, dst, ip6_frags.rnd);  	q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); -	if (q == NULL) +	if (IS_ERR_OR_NULL(q)) { +		inet_frag_maybe_warn_overflow(q, pr_fmt());  		return NULL; - +	}  	return container_of(q, struct frag_queue, q);  } @@ -326,9 +330,17 @@ found:  	}  	if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && -	    fq->q.meat == fq->q.len) -		return ip6_frag_reasm(fq, prev, dev); +	    fq->q.meat == fq->q.len) { +		int res; +		unsigned long orefdst = skb->_skb_refdst; + +		skb->_skb_refdst = 0UL; +		res = ip6_frag_reasm(fq, prev, dev); +		skb->_skb_refdst = orefdst; +		return res; +	} +	skb_dst_drop(skb);  	inet_frag_lru_move(&fq->q);  	return -1;  |