aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_fragment.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ip_fragment.c')
-rw-r--r--net/ipv4/ip_fragment.c36
1 files changed, 35 insertions, 1 deletions
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 168440834ade..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
83static 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
78static struct inet_frags ip4_frags; 96static struct inet_frags ip4_frags;
79 97
80int ip_frag_nqueues(struct net *net) 98int ip_frag_nqueues(struct net *net)
@@ -137,11 +155,12 @@ 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;
143 qp->peer = sysctl_ipfrag_max_dist ? 162 qp->peer = sysctl_ipfrag_max_dist ?
144 inet_getpeer(arg->iph->saddr, 1) : NULL; 163 inet_getpeer_v4(arg->iph->saddr, 1) : NULL;
145} 164}
146 165
147static __inline__ void ip4_frag_free(struct inet_frag_queue *q) 166static __inline__ void ip4_frag_free(struct inet_frag_queue *q)
@@ -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;