diff options
Diffstat (limited to 'net/ipv4/ip_fragment.c')
| -rw-r--r-- | net/ipv4/ip_fragment.c | 25 | 
1 files changed, 14 insertions, 11 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index b6d30acb600..52c273ea05c 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -248,8 +248,7 @@ static void ip_expire(unsigned long arg)  		if (!head->dev)  			goto out_rcu_unlock; -		/* skb dst is stale, drop it, and perform route lookup again */ -		skb_dst_drop(head); +		/* skb has no dst, perform route lookup again */  		iph = ip_hdr(head);  		err = ip_route_input_noref(head, iph->daddr, iph->saddr,  					   iph->tos, head->dev); @@ -292,14 +291,11 @@ static inline struct ipq *ip_find(struct net *net, struct iphdr *iph, u32 user)  	hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol);  	q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash); -	if (q == NULL) -		goto out_nomem; - +	if (IS_ERR_OR_NULL(q)) { +		inet_frag_maybe_warn_overflow(q, pr_fmt()); +		return NULL; +	}  	return container_of(q, struct ipq, q); - -out_nomem: -	LIMIT_NETDEBUG(KERN_ERR pr_fmt("ip_frag_create: no memory left !\n")); -	return NULL;  }  /* Is the fragment too far ahead to be part of ipq? */ @@ -526,9 +522,16 @@ found:  		qp->q.max_size = skb->len + ihl;  	if (qp->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && -	    qp->q.meat == qp->q.len) -		return ip_frag_reasm(qp, prev, dev); +	    qp->q.meat == qp->q.len) { +		unsigned long orefdst = skb->_skb_refdst; + +		skb->_skb_refdst = 0UL; +		err = ip_frag_reasm(qp, prev, dev); +		skb->_skb_refdst = orefdst; +		return err; +	} +	skb_dst_drop(skb);  	inet_frag_lru_move(&qp->q);  	return -EINPROGRESS;  |