diff options
Diffstat (limited to 'net/ipv6/reassembly.c')
| -rw-r--r-- | net/ipv6/reassembly.c | 23 | 
1 files changed, 21 insertions, 2 deletions
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 196ab9347ad..e6e44cef8db 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -58,6 +58,7 @@  #include <net/ndisc.h>  #include <net/addrconf.h>  #include <net/inet_frag.h> +#include <net/inet_ecn.h>  struct ip6frag_skb_cb  { @@ -67,6 +68,10 @@ struct ip6frag_skb_cb  #define FRAG6_CB(skb)	((struct ip6frag_skb_cb*)((skb)->cb)) +static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h) +{ +	return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK); +}  static struct inet_frags ip6_frags; @@ -119,6 +124,7 @@ void ip6_frag_init(struct inet_frag_queue *q, void *a)  	fq->user = arg->user;  	fq->saddr = *arg->src;  	fq->daddr = *arg->dst; +	fq->ecn = arg->ecn;  }  EXPORT_SYMBOL(ip6_frag_init); @@ -173,7 +179,8 @@ static void ip6_frag_expire(unsigned long data)  }  static __inline__ struct frag_queue * -fq_find(struct net *net, __be32 id, const struct in6_addr *src, const struct in6_addr *dst) +fq_find(struct net *net, __be32 id, const struct in6_addr *src, +	const struct in6_addr *dst, u8 ecn)  {  	struct inet_frag_queue *q;  	struct ip6_create_arg arg; @@ -183,6 +190,7 @@ fq_find(struct net *net, __be32 id, const struct in6_addr *src, const struct in6  	arg.user = IP6_DEFRAG_LOCAL_DELIVER;  	arg.src = src;  	arg.dst = dst; +	arg.ecn = ecn;  	read_lock(&ip6_frags.lock);  	hash = inet6_hash_frag(id, src, dst, ip6_frags.rnd); @@ -202,6 +210,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,  	struct net_device *dev;  	int offset, end;  	struct net *net = dev_net(skb_dst(skb)->dev); +	u8 ecn;  	if (fq->q.last_in & INET_FRAG_COMPLETE)  		goto err; @@ -219,6 +228,8 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,  		return -1;  	} +	ecn = ip6_frag_ecn(ipv6_hdr(skb)); +  	if (skb->ip_summed == CHECKSUM_COMPLETE) {  		const unsigned char *nh = skb_network_header(skb);  		skb->csum = csum_sub(skb->csum, @@ -319,6 +330,7 @@ found:  	}  	fq->q.stamp = skb->tstamp;  	fq->q.meat += skb->len; +	fq->ecn |= ecn;  	add_frag_mem_limit(&fq->q, skb->truesize);  	/* The first fragment. @@ -362,9 +374,14 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,  	int    payload_len;  	unsigned int nhoff;  	int sum_truesize; +	u8 ecn;  	inet_frag_kill(&fq->q, &ip6_frags); +	ecn = ip_frag_ecn_table[fq->ecn]; +	if (unlikely(ecn == 0xff)) +		goto out_fail; +  	/* Make the one we just received the head. */  	if (prev) {  		head = prev->next; @@ -463,6 +480,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,  	head->dev = dev;  	head->tstamp = fq->q.stamp;  	ipv6_hdr(head)->payload_len = htons(payload_len); +	ipv6_change_dsfield(ipv6_hdr(head), 0xff, ecn);  	IP6CB(head)->nhoff = nhoff;  	/* Yes, and fold redundant checksum back. 8) */ @@ -526,7 +544,8 @@ static int ipv6_frag_rcv(struct sk_buff *skb)  		IP6_ADD_STATS_BH(net, ip6_dst_idev(skb_dst(skb)),  				 IPSTATS_MIB_REASMFAILS, evicted); -	fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr); +	fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, +		     ip6_frag_ecn(hdr));  	if (fq != NULL) {  		int ret;  |