diff options
| author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2013-03-22 04:24:44 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-03-24 17:16:30 -0400 |
| commit | eec2e6185ff6eab18c2cae9b01a9fbc5c33248fc (patch) | |
| tree | 65cef64452ff052e7b57dc92523f20cf5d120338 /net/ipv6 | |
| parent | be991971d53e0f5b6d13e3940192054216590072 (diff) | |
ipv6: implement RFC3168 5.3 (ecn protection) for ipv6 fragmentation handling
Hello!
After patch 1 got accepted to net-next I will also send a patch to
netfilter-devel to make the corresponding changes to the netfilter
reassembly logic.
Thanks,
Hannes
-- >8 --
[PATCH 2/2] ipv6: implement RFC3168 5.3 (ecn protection) for ipv6 fragmentation handling
This patch also ensures that INET_ECN_CE is propagated if one fragment
had the codepoint set.
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Jesper Dangaard Brouer <jbrouer@redhat.com>
Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Acked-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
| -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 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 | ||
