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 | ||
