aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/reassembly.c
diff options
context:
space:
mode:
authorAmerigo Wang <amwang@redhat.com>2012-09-18 12:50:09 -0400
committerDavid S. Miller <davem@davemloft.net>2012-09-19 17:23:28 -0400
commitb836c99fd6c9dfe52a69fa0ba36ec918f80ce02a (patch)
treecb3459103371712b73c8b7695cf05d8f936480a2 /net/ipv6/reassembly.c
parentc038a767cd697238b09f7a4ea5a504b4891774e9 (diff)
ipv6: unify conntrack reassembly expire code with standard one
Two years ago, Shan Wei tried to fix this: http://patchwork.ozlabs.org/patch/43905/ The problem is that RFC2460 requires an ICMP Time Exceeded -- Fragment Reassembly Time Exceeded message should be sent to the source of that fragment, if the defragmentation times out. " If insufficient fragments are received to complete reassembly of a packet within 60 seconds of the reception of the first-arriving fragment of that packet, reassembly of that packet must be abandoned and all the fragments that have been received for that packet must be discarded. If the first fragment (i.e., the one with a Fragment Offset of zero) has been received, an ICMP Time Exceeded -- Fragment Reassembly Time Exceeded message should be sent to the source of that fragment. " As Herbert suggested, we could actually use the standard IPv6 reassembly code which follows RFC2460. With this patch applied, I can see ICMP Time Exceeded sent from the receiver when the sender sent out 3/4 fragmented IPv6 UDP packet. Cc: Herbert Xu <herbert@gondor.apana.org.au> Cc: Michal Kubeček <mkubecek@suse.cz> Cc: David Miller <davem@davemloft.net> Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org> Cc: Patrick McHardy <kaber@trash.net> Cc: Pablo Neira Ayuso <pablo@netfilter.org> Cc: netfilter-devel@vger.kernel.org Signed-off-by: Cong Wang <amwang@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/reassembly.c')
-rw-r--r--net/ipv6/reassembly.c63
1 files changed, 19 insertions, 44 deletions
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 4ff9af628e72..0ee553354ed5 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -65,24 +65,6 @@ struct ip6frag_skb_cb
65#define FRAG6_CB(skb) ((struct ip6frag_skb_cb*)((skb)->cb)) 65#define FRAG6_CB(skb) ((struct ip6frag_skb_cb*)((skb)->cb))
66 66
67 67
68/*
69 * Equivalent of ipv4 struct ipq
70 */
71
72struct frag_queue
73{
74 struct inet_frag_queue q;
75
76 __be32 id; /* fragment id */
77 u32 user;
78 struct in6_addr saddr;
79 struct in6_addr daddr;
80
81 int iif;
82 unsigned int csum;
83 __u16 nhoffset;
84};
85
86static struct inet_frags ip6_frags; 68static struct inet_frags ip6_frags;
87 69
88int ip6_frag_nqueues(struct net *net) 70int ip6_frag_nqueues(struct net *net)
@@ -159,21 +141,6 @@ void ip6_frag_init(struct inet_frag_queue *q, void *a)
159} 141}
160EXPORT_SYMBOL(ip6_frag_init); 142EXPORT_SYMBOL(ip6_frag_init);
161 143
162/* Destruction primitives. */
163
164static __inline__ void fq_put(struct frag_queue *fq)
165{
166 inet_frag_put(&fq->q, &ip6_frags);
167}
168
169/* Kill fq entry. It is not destroyed immediately,
170 * because caller (and someone more) holds reference count.
171 */
172static __inline__ void fq_kill(struct frag_queue *fq)
173{
174 inet_frag_kill(&fq->q, &ip6_frags);
175}
176
177static void ip6_evictor(struct net *net, struct inet6_dev *idev) 144static void ip6_evictor(struct net *net, struct inet6_dev *idev)
178{ 145{
179 int evicted; 146 int evicted;
@@ -183,22 +150,18 @@ static void ip6_evictor(struct net *net, struct inet6_dev *idev)
183 IP6_ADD_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS, evicted); 150 IP6_ADD_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS, evicted);
184} 151}
185 152
186static void ip6_frag_expire(unsigned long data) 153void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq,
154 struct inet_frags *frags)
187{ 155{
188 struct frag_queue *fq;
189 struct net_device *dev = NULL; 156 struct net_device *dev = NULL;
190 struct net *net;
191
192 fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q);
193 157
194 spin_lock(&fq->q.lock); 158 spin_lock(&fq->q.lock);
195 159
196 if (fq->q.last_in & INET_FRAG_COMPLETE) 160 if (fq->q.last_in & INET_FRAG_COMPLETE)
197 goto out; 161 goto out;
198 162
199 fq_kill(fq); 163 inet_frag_kill(&fq->q, frags);
200 164
201 net = container_of(fq->q.net, struct net, ipv6.frags);
202 rcu_read_lock(); 165 rcu_read_lock();
203 dev = dev_get_by_index_rcu(net, fq->iif); 166 dev = dev_get_by_index_rcu(net, fq->iif);
204 if (!dev) 167 if (!dev)
@@ -222,7 +185,19 @@ out_rcu_unlock:
222 rcu_read_unlock(); 185 rcu_read_unlock();
223out: 186out:
224 spin_unlock(&fq->q.lock); 187 spin_unlock(&fq->q.lock);
225 fq_put(fq); 188 inet_frag_put(&fq->q, frags);
189}
190EXPORT_SYMBOL(ip6_expire_frag_queue);
191
192static void ip6_frag_expire(unsigned long data)
193{
194 struct frag_queue *fq;
195 struct net *net;
196
197 fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q);
198 net = container_of(fq->q.net, struct net, ipv6.frags);
199
200 ip6_expire_frag_queue(net, fq, &ip6_frags);
226} 201}
227 202
228static __inline__ struct frag_queue * 203static __inline__ struct frag_queue *
@@ -391,7 +366,7 @@ found:
391 return -1; 366 return -1;
392 367
393discard_fq: 368discard_fq:
394 fq_kill(fq); 369 inet_frag_kill(&fq->q, &ip6_frags);
395err: 370err:
396 IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), 371 IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
397 IPSTATS_MIB_REASMFAILS); 372 IPSTATS_MIB_REASMFAILS);
@@ -417,7 +392,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
417 unsigned int nhoff; 392 unsigned int nhoff;
418 int sum_truesize; 393 int sum_truesize;
419 394
420 fq_kill(fq); 395 inet_frag_kill(&fq->q, &ip6_frags);
421 396
422 /* Make the one we just received the head. */ 397 /* Make the one we just received the head. */
423 if (prev) { 398 if (prev) {
@@ -586,7 +561,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
586 ret = ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff); 561 ret = ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff);
587 562
588 spin_unlock(&fq->q.lock); 563 spin_unlock(&fq->q.lock);
589 fq_put(fq); 564 inet_frag_put(&fq->q, &ip6_frags);
590 return ret; 565 return ret;
591 } 566 }
592 567