diff options
-rw-r--r-- | include/net/ipv6.h | 2 | ||||
-rw-r--r-- | net/ipv6/reassembly.c | 23 |
2 files changed, 23 insertions, 2 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 42ef6abf25c3..0810aa57c780 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -478,6 +478,7 @@ struct ip6_create_arg { | |||
478 | u32 user; | 478 | u32 user; |
479 | const struct in6_addr *src; | 479 | const struct in6_addr *src; |
480 | const struct in6_addr *dst; | 480 | const struct in6_addr *dst; |
481 | u8 ecn; | ||
481 | }; | 482 | }; |
482 | 483 | ||
483 | void ip6_frag_init(struct inet_frag_queue *q, void *a); | 484 | void ip6_frag_init(struct inet_frag_queue *q, void *a); |
@@ -497,6 +498,7 @@ struct frag_queue { | |||
497 | int iif; | 498 | int iif; |
498 | unsigned int csum; | 499 | unsigned int csum; |
499 | __u16 nhoffset; | 500 | __u16 nhoffset; |
501 | u8 ecn; | ||
500 | }; | 502 | }; |
501 | 503 | ||
502 | void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq, | 504 | void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq, |
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 196ab9347ad1..e6e44cef8db2 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c | |||
@@ -58,6 +58,7 @@ | |||
58 | #include <net/ndisc.h> | 58 | #include <net/ndisc.h> |
59 | #include <net/addrconf.h> | 59 | #include <net/addrconf.h> |
60 | #include <net/inet_frag.h> | 60 | #include <net/inet_frag.h> |
61 | #include <net/inet_ecn.h> | ||
61 | 62 | ||
62 | struct ip6frag_skb_cb | 63 | struct ip6frag_skb_cb |
63 | { | 64 | { |
@@ -67,6 +68,10 @@ struct ip6frag_skb_cb | |||
67 | 68 | ||
68 | #define FRAG6_CB(skb) ((struct ip6frag_skb_cb*)((skb)->cb)) | 69 | #define FRAG6_CB(skb) ((struct ip6frag_skb_cb*)((skb)->cb)) |
69 | 70 | ||
71 | static inline u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h) | ||
72 | { | ||
73 | return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK); | ||
74 | } | ||
70 | 75 | ||
71 | static struct inet_frags ip6_frags; | 76 | static struct inet_frags ip6_frags; |
72 | 77 | ||
@@ -119,6 +124,7 @@ void ip6_frag_init(struct inet_frag_queue *q, void *a) | |||
119 | fq->user = arg->user; | 124 | fq->user = arg->user; |
120 | fq->saddr = *arg->src; | 125 | fq->saddr = *arg->src; |
121 | fq->daddr = *arg->dst; | 126 | fq->daddr = *arg->dst; |
127 | fq->ecn = arg->ecn; | ||
122 | } | 128 | } |
123 | EXPORT_SYMBOL(ip6_frag_init); | 129 | EXPORT_SYMBOL(ip6_frag_init); |
124 | 130 | ||
@@ -173,7 +179,8 @@ static void ip6_frag_expire(unsigned long data) | |||
173 | } | 179 | } |
174 | 180 | ||
175 | static __inline__ struct frag_queue * | 181 | static __inline__ struct frag_queue * |
176 | fq_find(struct net *net, __be32 id, const struct in6_addr *src, const struct in6_addr *dst) | 182 | fq_find(struct net *net, __be32 id, const struct in6_addr *src, |
183 | const struct in6_addr *dst, u8 ecn) | ||
177 | { | 184 | { |
178 | struct inet_frag_queue *q; | 185 | struct inet_frag_queue *q; |
179 | struct ip6_create_arg arg; | 186 | struct ip6_create_arg arg; |
@@ -183,6 +190,7 @@ fq_find(struct net *net, __be32 id, const struct in6_addr *src, const struct in6 | |||
183 | arg.user = IP6_DEFRAG_LOCAL_DELIVER; | 190 | arg.user = IP6_DEFRAG_LOCAL_DELIVER; |
184 | arg.src = src; | 191 | arg.src = src; |
185 | arg.dst = dst; | 192 | arg.dst = dst; |
193 | arg.ecn = ecn; | ||
186 | 194 | ||
187 | read_lock(&ip6_frags.lock); | 195 | read_lock(&ip6_frags.lock); |
188 | hash = inet6_hash_frag(id, src, dst, ip6_frags.rnd); | 196 | 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, | |||
202 | struct net_device *dev; | 210 | struct net_device *dev; |
203 | int offset, end; | 211 | int offset, end; |
204 | struct net *net = dev_net(skb_dst(skb)->dev); | 212 | struct net *net = dev_net(skb_dst(skb)->dev); |
213 | u8 ecn; | ||
205 | 214 | ||
206 | if (fq->q.last_in & INET_FRAG_COMPLETE) | 215 | if (fq->q.last_in & INET_FRAG_COMPLETE) |
207 | goto err; | 216 | goto err; |
@@ -219,6 +228,8 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, | |||
219 | return -1; | 228 | return -1; |
220 | } | 229 | } |
221 | 230 | ||
231 | ecn = ip6_frag_ecn(ipv6_hdr(skb)); | ||
232 | |||
222 | if (skb->ip_summed == CHECKSUM_COMPLETE) { | 233 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
223 | const unsigned char *nh = skb_network_header(skb); | 234 | const unsigned char *nh = skb_network_header(skb); |
224 | skb->csum = csum_sub(skb->csum, | 235 | skb->csum = csum_sub(skb->csum, |
@@ -319,6 +330,7 @@ found: | |||
319 | } | 330 | } |
320 | fq->q.stamp = skb->tstamp; | 331 | fq->q.stamp = skb->tstamp; |
321 | fq->q.meat += skb->len; | 332 | fq->q.meat += skb->len; |
333 | fq->ecn |= ecn; | ||
322 | add_frag_mem_limit(&fq->q, skb->truesize); | 334 | add_frag_mem_limit(&fq->q, skb->truesize); |
323 | 335 | ||
324 | /* The first fragment. | 336 | /* The first fragment. |
@@ -362,9 +374,14 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
362 | int payload_len; | 374 | int payload_len; |
363 | unsigned int nhoff; | 375 | unsigned int nhoff; |
364 | int sum_truesize; | 376 | int sum_truesize; |
377 | u8 ecn; | ||
365 | 378 | ||
366 | inet_frag_kill(&fq->q, &ip6_frags); | 379 | inet_frag_kill(&fq->q, &ip6_frags); |
367 | 380 | ||
381 | ecn = ip_frag_ecn_table[fq->ecn]; | ||
382 | if (unlikely(ecn == 0xff)) | ||
383 | goto out_fail; | ||
384 | |||
368 | /* Make the one we just received the head. */ | 385 | /* Make the one we just received the head. */ |
369 | if (prev) { | 386 | if (prev) { |
370 | head = prev->next; | 387 | head = prev->next; |
@@ -463,6 +480,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, | |||
463 | head->dev = dev; | 480 | head->dev = dev; |
464 | head->tstamp = fq->q.stamp; | 481 | head->tstamp = fq->q.stamp; |
465 | ipv6_hdr(head)->payload_len = htons(payload_len); | 482 | ipv6_hdr(head)->payload_len = htons(payload_len); |
483 | ipv6_change_dsfield(ipv6_hdr(head), 0xff, ecn); | ||
466 | IP6CB(head)->nhoff = nhoff; | 484 | IP6CB(head)->nhoff = nhoff; |
467 | 485 | ||
468 | /* Yes, and fold redundant checksum back. 8) */ | 486 | /* Yes, and fold redundant checksum back. 8) */ |
@@ -526,7 +544,8 @@ static int ipv6_frag_rcv(struct sk_buff *skb) | |||
526 | IP6_ADD_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), | 544 | IP6_ADD_STATS_BH(net, ip6_dst_idev(skb_dst(skb)), |
527 | IPSTATS_MIB_REASMFAILS, evicted); | 545 | IPSTATS_MIB_REASMFAILS, evicted); |
528 | 546 | ||
529 | fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr); | 547 | fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, |
548 | ip6_frag_ecn(hdr)); | ||
530 | if (fq != NULL) { | 549 | if (fq != NULL) { |
531 | int ret; | 550 | int ret; |
532 | 551 | ||