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/reassembly.c | |
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/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 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 | ||