diff options
| -rw-r--r-- | net/ipv4/ip_fragment.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index e6215bdd96c0..a1151b8adf3c 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c | |||
| @@ -45,6 +45,7 @@ | |||
| 45 | #include <linux/udp.h> | 45 | #include <linux/udp.h> |
| 46 | #include <linux/inet.h> | 46 | #include <linux/inet.h> |
| 47 | #include <linux/netfilter_ipv4.h> | 47 | #include <linux/netfilter_ipv4.h> |
| 48 | #include <net/inet_ecn.h> | ||
| 48 | 49 | ||
| 49 | /* NOTE. Logic of IP defragmentation is parallel to corresponding IPv6 | 50 | /* NOTE. Logic of IP defragmentation is parallel to corresponding IPv6 |
| 50 | * code now. If you change something here, _PLEASE_ update ipv6/reassembly.c | 51 | * code now. If you change something here, _PLEASE_ update ipv6/reassembly.c |
| @@ -70,11 +71,28 @@ struct ipq { | |||
| 70 | __be32 daddr; | 71 | __be32 daddr; |
| 71 | __be16 id; | 72 | __be16 id; |
| 72 | u8 protocol; | 73 | u8 protocol; |
| 74 | u8 ecn; /* RFC3168 support */ | ||
| 73 | int iif; | 75 | int iif; |
| 74 | unsigned int rid; | 76 | unsigned int rid; |
| 75 | struct inet_peer *peer; | 77 | struct inet_peer *peer; |
| 76 | }; | 78 | }; |
| 77 | 79 | ||
| 80 | #define IPFRAG_ECN_CLEAR 0x01 /* one frag had INET_ECN_NOT_ECT */ | ||
| 81 | #define IPFRAG_ECN_SET_CE 0x04 /* one frag had INET_ECN_CE */ | ||
| 82 | |||
| 83 | static inline u8 ip4_frag_ecn(u8 tos) | ||
| 84 | { | ||
| 85 | tos = (tos & INET_ECN_MASK) + 1; | ||
| 86 | /* | ||
| 87 | * After the last operation we have (in binary): | ||
| 88 | * INET_ECN_NOT_ECT => 001 | ||
| 89 | * INET_ECN_ECT_1 => 010 | ||
| 90 | * INET_ECN_ECT_0 => 011 | ||
| 91 | * INET_ECN_CE => 100 | ||
| 92 | */ | ||
| 93 | return (tos & 2) ? 0 : tos; | ||
| 94 | } | ||
| 95 | |||
| 78 | static struct inet_frags ip4_frags; | 96 | static struct inet_frags ip4_frags; |
| 79 | 97 | ||
| 80 | int ip_frag_nqueues(struct net *net) | 98 | int ip_frag_nqueues(struct net *net) |
| @@ -137,6 +155,7 @@ static void ip4_frag_init(struct inet_frag_queue *q, void *a) | |||
| 137 | 155 | ||
| 138 | qp->protocol = arg->iph->protocol; | 156 | qp->protocol = arg->iph->protocol; |
| 139 | qp->id = arg->iph->id; | 157 | qp->id = arg->iph->id; |
| 158 | qp->ecn = ip4_frag_ecn(arg->iph->tos); | ||
| 140 | qp->saddr = arg->iph->saddr; | 159 | qp->saddr = arg->iph->saddr; |
| 141 | qp->daddr = arg->iph->daddr; | 160 | qp->daddr = arg->iph->daddr; |
| 142 | qp->user = arg->user; | 161 | qp->user = arg->user; |
| @@ -316,6 +335,7 @@ static int ip_frag_reinit(struct ipq *qp) | |||
| 316 | qp->q.fragments = NULL; | 335 | qp->q.fragments = NULL; |
| 317 | qp->q.fragments_tail = NULL; | 336 | qp->q.fragments_tail = NULL; |
| 318 | qp->iif = 0; | 337 | qp->iif = 0; |
| 338 | qp->ecn = 0; | ||
| 319 | 339 | ||
| 320 | return 0; | 340 | return 0; |
| 321 | } | 341 | } |
| @@ -328,6 +348,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) | |||
| 328 | int flags, offset; | 348 | int flags, offset; |
| 329 | int ihl, end; | 349 | int ihl, end; |
| 330 | int err = -ENOENT; | 350 | int err = -ENOENT; |
| 351 | u8 ecn; | ||
| 331 | 352 | ||
| 332 | if (qp->q.last_in & INET_FRAG_COMPLETE) | 353 | if (qp->q.last_in & INET_FRAG_COMPLETE) |
| 333 | goto err; | 354 | goto err; |
| @@ -339,6 +360,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) | |||
| 339 | goto err; | 360 | goto err; |
| 340 | } | 361 | } |
| 341 | 362 | ||
| 363 | ecn = ip4_frag_ecn(ip_hdr(skb)->tos); | ||
| 342 | offset = ntohs(ip_hdr(skb)->frag_off); | 364 | offset = ntohs(ip_hdr(skb)->frag_off); |
| 343 | flags = offset & ~IP_OFFSET; | 365 | flags = offset & ~IP_OFFSET; |
| 344 | offset &= IP_OFFSET; | 366 | offset &= IP_OFFSET; |
| @@ -472,6 +494,7 @@ found: | |||
| 472 | } | 494 | } |
| 473 | qp->q.stamp = skb->tstamp; | 495 | qp->q.stamp = skb->tstamp; |
| 474 | qp->q.meat += skb->len; | 496 | qp->q.meat += skb->len; |
| 497 | qp->ecn |= ecn; | ||
| 475 | atomic_add(skb->truesize, &qp->q.net->mem); | 498 | atomic_add(skb->truesize, &qp->q.net->mem); |
| 476 | if (offset == 0) | 499 | if (offset == 0) |
| 477 | qp->q.last_in |= INET_FRAG_FIRST_IN; | 500 | qp->q.last_in |= INET_FRAG_FIRST_IN; |
| @@ -583,6 +606,17 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, | |||
| 583 | iph = ip_hdr(head); | 606 | iph = ip_hdr(head); |
| 584 | iph->frag_off = 0; | 607 | iph->frag_off = 0; |
| 585 | iph->tot_len = htons(len); | 608 | iph->tot_len = htons(len); |
| 609 | /* RFC3168 5.3 Fragmentation support | ||
| 610 | * If one fragment had INET_ECN_NOT_ECT, | ||
| 611 | * reassembled frame also has INET_ECN_NOT_ECT | ||
| 612 | * Elif one fragment had INET_ECN_CE | ||
| 613 | * reassembled frame also has INET_ECN_CE | ||
| 614 | */ | ||
| 615 | if (qp->ecn & IPFRAG_ECN_CLEAR) | ||
| 616 | iph->tos &= ~INET_ECN_MASK; | ||
| 617 | else if (qp->ecn & IPFRAG_ECN_SET_CE) | ||
| 618 | iph->tos |= INET_ECN_CE; | ||
| 619 | |||
| 586 | IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS); | 620 | IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS); |
| 587 | qp->q.fragments = NULL; | 621 | qp->q.fragments = NULL; |
| 588 | qp->q.fragments_tail = NULL; | 622 | qp->q.fragments_tail = NULL; |
