Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * inet fragments management
4 : : *
5 : : * Authors: Pavel Emelyanov <xemul@openvz.org>
6 : : * Started as consolidation of ipv4/ip_fragment.c,
7 : : * ipv6/reassembly. and ipv6 nf conntrack reassembly
8 : : */
9 : :
10 : : #include <linux/list.h>
11 : : #include <linux/spinlock.h>
12 : : #include <linux/module.h>
13 : : #include <linux/timer.h>
14 : : #include <linux/mm.h>
15 : : #include <linux/random.h>
16 : : #include <linux/skbuff.h>
17 : : #include <linux/rtnetlink.h>
18 : : #include <linux/slab.h>
19 : : #include <linux/rhashtable.h>
20 : :
21 : : #include <net/sock.h>
22 : : #include <net/inet_frag.h>
23 : : #include <net/inet_ecn.h>
24 : : #include <net/ip.h>
25 : : #include <net/ipv6.h>
26 : :
27 : : /* Use skb->cb to track consecutive/adjacent fragments coming at
28 : : * the end of the queue. Nodes in the rb-tree queue will
29 : : * contain "runs" of one or more adjacent fragments.
30 : : *
31 : : * Invariants:
32 : : * - next_frag is NULL at the tail of a "run";
33 : : * - the head of a "run" has the sum of all fragment lengths in frag_run_len.
34 : : */
35 : : struct ipfrag_skb_cb {
36 : : union {
37 : : struct inet_skb_parm h4;
38 : : struct inet6_skb_parm h6;
39 : : };
40 : : struct sk_buff *next_frag;
41 : : int frag_run_len;
42 : : };
43 : :
44 : : #define FRAG_CB(skb) ((struct ipfrag_skb_cb *)((skb)->cb))
45 : :
46 : : static void fragcb_clear(struct sk_buff *skb)
47 : : {
48 : 0 : RB_CLEAR_NODE(&skb->rbnode);
49 : 0 : FRAG_CB(skb)->next_frag = NULL;
50 : 0 : FRAG_CB(skb)->frag_run_len = skb->len;
51 : : }
52 : :
53 : : /* Append skb to the last "run". */
54 : : static void fragrun_append_to_last(struct inet_frag_queue *q,
55 : : struct sk_buff *skb)
56 : : {
57 : : fragcb_clear(skb);
58 : :
59 : 0 : FRAG_CB(q->last_run_head)->frag_run_len += skb->len;
60 : 0 : FRAG_CB(q->fragments_tail)->next_frag = skb;
61 : 0 : q->fragments_tail = skb;
62 : : }
63 : :
64 : : /* Create a new "run" with the skb. */
65 : 0 : static void fragrun_create(struct inet_frag_queue *q, struct sk_buff *skb)
66 : : {
67 : : BUILD_BUG_ON(sizeof(struct ipfrag_skb_cb) > sizeof(skb->cb));
68 : : fragcb_clear(skb);
69 : :
70 [ # # ]: 0 : if (q->last_run_head)
71 : 0 : rb_link_node(&skb->rbnode, &q->last_run_head->rbnode,
72 : : &q->last_run_head->rbnode.rb_right);
73 : : else
74 : : rb_link_node(&skb->rbnode, NULL, &q->rb_fragments.rb_node);
75 : 0 : rb_insert_color(&skb->rbnode, &q->rb_fragments);
76 : :
77 : 0 : q->fragments_tail = skb;
78 : 0 : q->last_run_head = skb;
79 : 0 : }
80 : :
81 : : /* Given the OR values of all fragments, apply RFC 3168 5.3 requirements
82 : : * Value : 0xff if frame should be dropped.
83 : : * 0 or INET_ECN_CE value, to be ORed in to final iph->tos field
84 : : */
85 : : const u8 ip_frag_ecn_table[16] = {
86 : : /* at least one fragment had CE, and others ECT_0 or ECT_1 */
87 : : [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0] = INET_ECN_CE,
88 : : [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_1] = INET_ECN_CE,
89 : : [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = INET_ECN_CE,
90 : :
91 : : /* invalid combinations : drop frame */
92 : : [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE] = 0xff,
93 : : [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_0] = 0xff,
94 : : [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_1] = 0xff,
95 : : [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = 0xff,
96 : : [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0] = 0xff,
97 : : [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_1] = 0xff,
98 : : [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = 0xff,
99 : : };
100 : : EXPORT_SYMBOL(ip_frag_ecn_table);
101 : :
102 : 621 : int inet_frags_init(struct inet_frags *f)
103 : : {
104 : 621 : f->frags_cachep = kmem_cache_create(f->frags_cache_name, f->qsize, 0, 0,
105 : : NULL);
106 [ + - ]: 621 : if (!f->frags_cachep)
107 : : return -ENOMEM;
108 : :
109 : : refcount_set(&f->refcnt, 1);
110 : : init_completion(&f->completion);
111 : 621 : return 0;
112 : : }
113 : : EXPORT_SYMBOL(inet_frags_init);
114 : :
115 : 0 : void inet_frags_fini(struct inet_frags *f)
116 : : {
117 [ # # ]: 0 : if (refcount_dec_and_test(&f->refcnt))
118 : 0 : complete(&f->completion);
119 : :
120 : 0 : wait_for_completion(&f->completion);
121 : :
122 : 0 : kmem_cache_destroy(f->frags_cachep);
123 : 0 : f->frags_cachep = NULL;
124 : 0 : }
125 : : EXPORT_SYMBOL(inet_frags_fini);
126 : :
127 : : /* called from rhashtable_free_and_destroy() at netns_frags dismantle */
128 : 0 : static void inet_frags_free_cb(void *ptr, void *arg)
129 : : {
130 : : struct inet_frag_queue *fq = ptr;
131 : : int count;
132 : :
133 : 0 : count = del_timer_sync(&fq->timer) ? 1 : 0;
134 : :
135 : : spin_lock_bh(&fq->lock);
136 [ # # ]: 0 : if (!(fq->flags & INET_FRAG_COMPLETE)) {
137 : 0 : fq->flags |= INET_FRAG_COMPLETE;
138 : 0 : count++;
139 [ # # ]: 0 : } else if (fq->flags & INET_FRAG_HASH_DEAD) {
140 : 0 : count++;
141 : : }
142 : : spin_unlock_bh(&fq->lock);
143 : :
144 [ # # ]: 0 : if (refcount_sub_and_test(count, &fq->refcnt))
145 : 0 : inet_frag_destroy(fq);
146 : 0 : }
147 : :
148 : 0 : static void fqdir_work_fn(struct work_struct *work)
149 : : {
150 : 0 : struct fqdir *fqdir = container_of(work, struct fqdir, destroy_work);
151 : 0 : struct inet_frags *f = fqdir->f;
152 : :
153 : 0 : rhashtable_free_and_destroy(&fqdir->rhashtable, inet_frags_free_cb, NULL);
154 : :
155 : : /* We need to make sure all ongoing call_rcu(..., inet_frag_destroy_rcu)
156 : : * have completed, since they need to dereference fqdir.
157 : : * Would it not be nice to have kfree_rcu_barrier() ? :)
158 : : */
159 : 0 : rcu_barrier();
160 : :
161 [ # # ]: 0 : if (refcount_dec_and_test(&f->refcnt))
162 : 0 : complete(&f->completion);
163 : :
164 : 0 : kfree(fqdir);
165 : 0 : }
166 : :
167 : 621 : int fqdir_init(struct fqdir **fqdirp, struct inet_frags *f, struct net *net)
168 : : {
169 : 621 : struct fqdir *fqdir = kzalloc(sizeof(*fqdir), GFP_KERNEL);
170 : : int res;
171 : :
172 [ + - ]: 621 : if (!fqdir)
173 : : return -ENOMEM;
174 : 621 : fqdir->f = f;
175 : 621 : fqdir->net = net;
176 : 621 : res = rhashtable_init(&fqdir->rhashtable, &fqdir->f->rhash_params);
177 [ - + ]: 621 : if (res < 0) {
178 : 0 : kfree(fqdir);
179 : 0 : return res;
180 : : }
181 : 621 : refcount_inc(&f->refcnt);
182 : 621 : *fqdirp = fqdir;
183 : 621 : return 0;
184 : : }
185 : : EXPORT_SYMBOL(fqdir_init);
186 : :
187 : 0 : void fqdir_exit(struct fqdir *fqdir)
188 : : {
189 : 0 : INIT_WORK(&fqdir->destroy_work, fqdir_work_fn);
190 : 0 : queue_work(system_wq, &fqdir->destroy_work);
191 : 0 : }
192 : : EXPORT_SYMBOL(fqdir_exit);
193 : :
194 : 0 : void inet_frag_kill(struct inet_frag_queue *fq)
195 : : {
196 [ # # ]: 0 : if (del_timer(&fq->timer))
197 : 0 : refcount_dec(&fq->refcnt);
198 : :
199 [ # # ]: 0 : if (!(fq->flags & INET_FRAG_COMPLETE)) {
200 : 0 : struct fqdir *fqdir = fq->fqdir;
201 : :
202 : 0 : fq->flags |= INET_FRAG_COMPLETE;
203 : : rcu_read_lock();
204 : : /* The RCU read lock provides a memory barrier
205 : : * guaranteeing that if fqdir->dead is false then
206 : : * the hash table destruction will not start until
207 : : * after we unlock. Paired with inet_frags_exit_net().
208 : : */
209 [ # # ]: 0 : if (!fqdir->dead) {
210 : 0 : rhashtable_remove_fast(&fqdir->rhashtable, &fq->node,
211 : 0 : fqdir->f->rhash_params);
212 : 0 : refcount_dec(&fq->refcnt);
213 : : } else {
214 : 0 : fq->flags |= INET_FRAG_HASH_DEAD;
215 : : }
216 : : rcu_read_unlock();
217 : : }
218 : 0 : }
219 : : EXPORT_SYMBOL(inet_frag_kill);
220 : :
221 : 0 : static void inet_frag_destroy_rcu(struct rcu_head *head)
222 : : {
223 : 0 : struct inet_frag_queue *q = container_of(head, struct inet_frag_queue,
224 : : rcu);
225 : 0 : struct inet_frags *f = q->fqdir->f;
226 : :
227 [ # # ]: 0 : if (f->destructor)
228 : 0 : f->destructor(q);
229 : 0 : kmem_cache_free(f->frags_cachep, q);
230 : 0 : }
231 : :
232 : 0 : unsigned int inet_frag_rbtree_purge(struct rb_root *root)
233 : : {
234 : 0 : struct rb_node *p = rb_first(root);
235 : : unsigned int sum = 0;
236 : :
237 [ # # ]: 0 : while (p) {
238 : : struct sk_buff *skb = rb_entry(p, struct sk_buff, rbnode);
239 : :
240 : 0 : p = rb_next(p);
241 : 0 : rb_erase(&skb->rbnode, root);
242 [ # # ]: 0 : while (skb) {
243 : 0 : struct sk_buff *next = FRAG_CB(skb)->next_frag;
244 : :
245 : 0 : sum += skb->truesize;
246 : 0 : kfree_skb(skb);
247 : : skb = next;
248 : : }
249 : : }
250 : 0 : return sum;
251 : : }
252 : : EXPORT_SYMBOL(inet_frag_rbtree_purge);
253 : :
254 : 0 : void inet_frag_destroy(struct inet_frag_queue *q)
255 : : {
256 : : struct fqdir *fqdir;
257 : : unsigned int sum, sum_truesize = 0;
258 : : struct inet_frags *f;
259 : :
260 [ # # ]: 0 : WARN_ON(!(q->flags & INET_FRAG_COMPLETE));
261 [ # # ]: 0 : WARN_ON(del_timer(&q->timer) != 0);
262 : :
263 : : /* Release all fragment data. */
264 : 0 : fqdir = q->fqdir;
265 : 0 : f = fqdir->f;
266 : 0 : sum_truesize = inet_frag_rbtree_purge(&q->rb_fragments);
267 : 0 : sum = sum_truesize + f->qsize;
268 : :
269 : 0 : call_rcu(&q->rcu, inet_frag_destroy_rcu);
270 : :
271 : 0 : sub_frag_mem_limit(fqdir, sum);
272 : 0 : }
273 : : EXPORT_SYMBOL(inet_frag_destroy);
274 : :
275 : 0 : static struct inet_frag_queue *inet_frag_alloc(struct fqdir *fqdir,
276 : : struct inet_frags *f,
277 : : void *arg)
278 : : {
279 : : struct inet_frag_queue *q;
280 : :
281 : 0 : q = kmem_cache_zalloc(f->frags_cachep, GFP_ATOMIC);
282 [ # # ]: 0 : if (!q)
283 : : return NULL;
284 : :
285 : 0 : q->fqdir = fqdir;
286 : 0 : f->constructor(q, arg);
287 : 0 : add_frag_mem_limit(fqdir, f->qsize);
288 : :
289 : 0 : timer_setup(&q->timer, f->frag_expire, 0);
290 : 0 : spin_lock_init(&q->lock);
291 : : refcount_set(&q->refcnt, 3);
292 : :
293 : 0 : return q;
294 : : }
295 : :
296 : 0 : static struct inet_frag_queue *inet_frag_create(struct fqdir *fqdir,
297 : : void *arg,
298 : : struct inet_frag_queue **prev)
299 : : {
300 : 0 : struct inet_frags *f = fqdir->f;
301 : : struct inet_frag_queue *q;
302 : :
303 : 0 : q = inet_frag_alloc(fqdir, f, arg);
304 [ # # ]: 0 : if (!q) {
305 : 0 : *prev = ERR_PTR(-ENOMEM);
306 : 0 : return NULL;
307 : : }
308 : 0 : mod_timer(&q->timer, jiffies + fqdir->timeout);
309 : :
310 : 0 : *prev = rhashtable_lookup_get_insert_key(&fqdir->rhashtable, &q->key,
311 : : &q->node, f->rhash_params);
312 [ # # ]: 0 : if (*prev) {
313 : 0 : q->flags |= INET_FRAG_COMPLETE;
314 : 0 : inet_frag_kill(q);
315 : 0 : inet_frag_destroy(q);
316 : 0 : return NULL;
317 : : }
318 : : return q;
319 : : }
320 : :
321 : : /* TODO : call from rcu_read_lock() and no longer use refcount_inc_not_zero() */
322 : 0 : struct inet_frag_queue *inet_frag_find(struct fqdir *fqdir, void *key)
323 : : {
324 : : struct inet_frag_queue *fq = NULL, *prev;
325 : :
326 [ # # # # ]: 0 : if (!fqdir->high_thresh || frag_mem_limit(fqdir) > fqdir->high_thresh)
327 : : return NULL;
328 : :
329 : : rcu_read_lock();
330 : :
331 : 0 : prev = rhashtable_lookup(&fqdir->rhashtable, key, fqdir->f->rhash_params);
332 [ # # ]: 0 : if (!prev)
333 : 0 : fq = inet_frag_create(fqdir, key, &prev);
334 [ # # ]: 0 : if (!IS_ERR_OR_NULL(prev)) {
335 : : fq = prev;
336 [ # # ]: 0 : if (!refcount_inc_not_zero(&fq->refcnt))
337 : : fq = NULL;
338 : : }
339 : : rcu_read_unlock();
340 : 0 : return fq;
341 : : }
342 : : EXPORT_SYMBOL(inet_frag_find);
343 : :
344 : 0 : int inet_frag_queue_insert(struct inet_frag_queue *q, struct sk_buff *skb,
345 : : int offset, int end)
346 : : {
347 : 0 : struct sk_buff *last = q->fragments_tail;
348 : :
349 : : /* RFC5722, Section 4, amended by Errata ID : 3089
350 : : * When reassembling an IPv6 datagram, if
351 : : * one or more its constituent fragments is determined to be an
352 : : * overlapping fragment, the entire datagram (and any constituent
353 : : * fragments) MUST be silently discarded.
354 : : *
355 : : * Duplicates, however, should be ignored (i.e. skb dropped, but the
356 : : * queue/fragments kept for later reassembly).
357 : : */
358 [ # # ]: 0 : if (!last)
359 : 0 : fragrun_create(q, skb); /* First fragment. */
360 [ # # ]: 0 : else if (last->ip_defrag_offset + last->len < end) {
361 : : /* This is the common case: skb goes to the end. */
362 : : /* Detect and discard overlaps. */
363 [ # # ]: 0 : if (offset < last->ip_defrag_offset + last->len)
364 : : return IPFRAG_OVERLAP;
365 [ # # ]: 0 : if (offset == last->ip_defrag_offset + last->len)
366 : : fragrun_append_to_last(q, skb);
367 : : else
368 : 0 : fragrun_create(q, skb);
369 : : } else {
370 : : /* Binary search. Note that skb can become the first fragment,
371 : : * but not the last (covered above).
372 : : */
373 : : struct rb_node **rbn, *parent;
374 : :
375 : 0 : rbn = &q->rb_fragments.rb_node;
376 : : do {
377 : : struct sk_buff *curr;
378 : : int curr_run_end;
379 : :
380 : 0 : parent = *rbn;
381 [ # # ]: 0 : curr = rb_to_skb(parent);
382 : 0 : curr_run_end = curr->ip_defrag_offset +
383 : 0 : FRAG_CB(curr)->frag_run_len;
384 [ # # ]: 0 : if (end <= curr->ip_defrag_offset)
385 : 0 : rbn = &parent->rb_left;
386 [ # # ]: 0 : else if (offset >= curr_run_end)
387 : 0 : rbn = &parent->rb_right;
388 [ # # # # ]: 0 : else if (offset >= curr->ip_defrag_offset &&
389 : : end <= curr_run_end)
390 : : return IPFRAG_DUP;
391 : : else
392 : 0 : return IPFRAG_OVERLAP;
393 [ # # ]: 0 : } while (*rbn);
394 : : /* Here we have parent properly set, and rbn pointing to
395 : : * one of its NULL left/right children. Insert skb.
396 : : */
397 : : fragcb_clear(skb);
398 : : rb_link_node(&skb->rbnode, parent, rbn);
399 : 0 : rb_insert_color(&skb->rbnode, &q->rb_fragments);
400 : : }
401 : :
402 : 0 : skb->ip_defrag_offset = offset;
403 : :
404 : 0 : return IPFRAG_OK;
405 : : }
406 : : EXPORT_SYMBOL(inet_frag_queue_insert);
407 : :
408 : 0 : void *inet_frag_reasm_prepare(struct inet_frag_queue *q, struct sk_buff *skb,
409 : : struct sk_buff *parent)
410 : : {
411 [ # # ]: 0 : struct sk_buff *fp, *head = skb_rb_first(&q->rb_fragments);
412 : : struct sk_buff **nextp;
413 : : int delta;
414 : :
415 [ # # ]: 0 : if (head != skb) {
416 : 0 : fp = skb_clone(skb, GFP_ATOMIC);
417 [ # # ]: 0 : if (!fp)
418 : : return NULL;
419 : 0 : FRAG_CB(fp)->next_frag = FRAG_CB(skb)->next_frag;
420 [ # # ]: 0 : if (RB_EMPTY_NODE(&skb->rbnode))
421 : 0 : FRAG_CB(parent)->next_frag = fp;
422 : : else
423 : 0 : rb_replace_node(&skb->rbnode, &fp->rbnode,
424 : : &q->rb_fragments);
425 [ # # ]: 0 : if (q->fragments_tail == skb)
426 : 0 : q->fragments_tail = fp;
427 : 0 : skb_morph(skb, head);
428 : 0 : FRAG_CB(skb)->next_frag = FRAG_CB(head)->next_frag;
429 : 0 : rb_replace_node(&head->rbnode, &skb->rbnode,
430 : : &q->rb_fragments);
431 : 0 : consume_skb(head);
432 : : head = skb;
433 : : }
434 [ # # ]: 0 : WARN_ON(head->ip_defrag_offset != 0);
435 : :
436 : 0 : delta = -head->truesize;
437 : :
438 : : /* Head of list must not be cloned. */
439 [ # # ]: 0 : if (skb_unclone(head, GFP_ATOMIC))
440 : : return NULL;
441 : :
442 : 0 : delta += head->truesize;
443 [ # # ]: 0 : if (delta)
444 : 0 : add_frag_mem_limit(q->fqdir, delta);
445 : :
446 : : /* If the first fragment is fragmented itself, we split
447 : : * it to two chunks: the first with data and paged part
448 : : * and the second, holding only fragments.
449 : : */
450 [ # # ]: 0 : if (skb_has_frag_list(head)) {
451 : : struct sk_buff *clone;
452 : : int i, plen = 0;
453 : :
454 : : clone = alloc_skb(0, GFP_ATOMIC);
455 [ # # ]: 0 : if (!clone)
456 : : return NULL;
457 : 0 : skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
458 : : skb_frag_list_init(head);
459 [ # # ]: 0 : for (i = 0; i < skb_shinfo(head)->nr_frags; i++)
460 : 0 : plen += skb_frag_size(&skb_shinfo(head)->frags[i]);
461 : 0 : clone->data_len = head->data_len - plen;
462 : 0 : clone->len = clone->data_len;
463 : 0 : head->truesize += clone->truesize;
464 : 0 : clone->csum = 0;
465 : 0 : clone->ip_summed = head->ip_summed;
466 : 0 : add_frag_mem_limit(q->fqdir, clone->truesize);
467 : 0 : skb_shinfo(head)->frag_list = clone;
468 : 0 : nextp = &clone->next;
469 : : } else {
470 : 0 : nextp = &skb_shinfo(head)->frag_list;
471 : : }
472 : :
473 : 0 : return nextp;
474 : : }
475 : : EXPORT_SYMBOL(inet_frag_reasm_prepare);
476 : :
477 : 0 : void inet_frag_reasm_finish(struct inet_frag_queue *q, struct sk_buff *head,
478 : : void *reasm_data, bool try_coalesce)
479 : : {
480 : : struct sk_buff **nextp = (struct sk_buff **)reasm_data;
481 : : struct rb_node *rbn;
482 : : struct sk_buff *fp;
483 : : int sum_truesize;
484 : :
485 : 0 : skb_push(head, head->data - skb_network_header(head));
486 : :
487 : : /* Traverse the tree in order, to build frag_list. */
488 : 0 : fp = FRAG_CB(head)->next_frag;
489 : 0 : rbn = rb_next(&head->rbnode);
490 : 0 : rb_erase(&head->rbnode, &q->rb_fragments);
491 : :
492 : 0 : sum_truesize = head->truesize;
493 [ # # ]: 0 : while (rbn || fp) {
494 : : /* fp points to the next sk_buff in the current run;
495 : : * rbn points to the next run.
496 : : */
497 : : /* Go through the current run. */
498 [ # # ]: 0 : while (fp) {
499 : 0 : struct sk_buff *next_frag = FRAG_CB(fp)->next_frag;
500 : : bool stolen;
501 : : int delta;
502 : :
503 : 0 : sum_truesize += fp->truesize;
504 [ # # ]: 0 : if (head->ip_summed != fp->ip_summed)
505 : 0 : head->ip_summed = CHECKSUM_NONE;
506 [ # # ]: 0 : else if (head->ip_summed == CHECKSUM_COMPLETE)
507 : 0 : head->csum = csum_add(head->csum, fp->csum);
508 : :
509 [ # # # # ]: 0 : if (try_coalesce && skb_try_coalesce(head, fp, &stolen,
510 : : &delta)) {
511 : 0 : kfree_skb_partial(fp, stolen);
512 : : } else {
513 : 0 : fp->prev = NULL;
514 : 0 : memset(&fp->rbnode, 0, sizeof(fp->rbnode));
515 : 0 : fp->sk = NULL;
516 : :
517 : 0 : head->data_len += fp->len;
518 : 0 : head->len += fp->len;
519 : 0 : head->truesize += fp->truesize;
520 : :
521 : 0 : *nextp = fp;
522 : 0 : nextp = &fp->next;
523 : : }
524 : :
525 : : fp = next_frag;
526 : : }
527 : : /* Move to the next run. */
528 [ # # ]: 0 : if (rbn) {
529 : 0 : struct rb_node *rbnext = rb_next(rbn);
530 : :
531 [ # # ]: 0 : fp = rb_to_skb(rbn);
532 : 0 : rb_erase(rbn, &q->rb_fragments);
533 : : rbn = rbnext;
534 : : }
535 : : }
536 : 0 : sub_frag_mem_limit(q->fqdir, sum_truesize);
537 : :
538 : 0 : *nextp = NULL;
539 : : skb_mark_not_on_list(head);
540 : 0 : head->prev = NULL;
541 : 0 : head->tstamp = q->stamp;
542 : 0 : }
543 : : EXPORT_SYMBOL(inet_frag_reasm_finish);
544 : :
545 : 0 : struct sk_buff *inet_frag_pull_head(struct inet_frag_queue *q)
546 : : {
547 : : struct sk_buff *head, *skb;
548 : :
549 [ # # ]: 0 : head = skb_rb_first(&q->rb_fragments);
550 [ # # ]: 0 : if (!head)
551 : : return NULL;
552 : 0 : skb = FRAG_CB(head)->next_frag;
553 [ # # ]: 0 : if (skb)
554 : 0 : rb_replace_node(&head->rbnode, &skb->rbnode,
555 : : &q->rb_fragments);
556 : : else
557 : 0 : rb_erase(&head->rbnode, &q->rb_fragments);
558 : 0 : memset(&head->rbnode, 0, sizeof(head->rbnode));
559 : 0 : barrier();
560 : :
561 [ # # ]: 0 : if (head == q->fragments_tail)
562 : 0 : q->fragments_tail = NULL;
563 : :
564 : 0 : sub_frag_mem_limit(q->fqdir, head->truesize);
565 : :
566 : 0 : return head;
567 : : }
568 : : EXPORT_SYMBOL(inet_frag_pull_head);
|