LCOV - code coverage report
Current view: top level - net/ipv4 - inet_fragment.c (source / functions) Hit Total Coverage
Test: Real Lines: 26 233 11.2 %
Date: 2020-10-17 15:46:43 Functions: 0 18 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           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                 :          3 : int inet_frags_init(struct inet_frags *f)
     103                 :            : {
     104                 :          3 :         f->frags_cachep = kmem_cache_create(f->frags_cache_name, f->qsize, 0, 0,
     105                 :            :                                             NULL);
     106                 :          3 :         if (!f->frags_cachep)
     107                 :            :                 return -ENOMEM;
     108                 :            : 
     109                 :            :         refcount_set(&f->refcnt, 1);
     110                 :            :         init_completion(&f->completion);
     111                 :          3 :         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                 :          1 : static void fqdir_work_fn(struct work_struct *work)
     149                 :            : {
     150                 :          1 :         struct fqdir *fqdir = container_of(work, struct fqdir, destroy_work);
     151                 :          1 :         struct inet_frags *f = fqdir->f;
     152                 :            : 
     153                 :          1 :         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                 :          1 :         rcu_barrier();
     160                 :            : 
     161                 :          1 :         if (refcount_dec_and_test(&f->refcnt))
     162                 :          0 :                 complete(&f->completion);
     163                 :            : 
     164                 :          1 :         kfree(fqdir);
     165                 :          1 : }
     166                 :            : 
     167                 :          3 : int fqdir_init(struct fqdir **fqdirp, struct inet_frags *f, struct net *net)
     168                 :            : {
     169                 :          3 :         struct fqdir *fqdir = kzalloc(sizeof(*fqdir), GFP_KERNEL);
     170                 :            :         int res;
     171                 :            : 
     172                 :          3 :         if (!fqdir)
     173                 :            :                 return -ENOMEM;
     174                 :          3 :         fqdir->f = f;
     175                 :          3 :         fqdir->net = net;
     176                 :          3 :         res = rhashtable_init(&fqdir->rhashtable, &fqdir->f->rhash_params);
     177                 :          3 :         if (res < 0) {
     178                 :          0 :                 kfree(fqdir);
     179                 :          0 :                 return res;
     180                 :            :         }
     181                 :          3 :         refcount_inc(&f->refcnt);
     182                 :          3 :         *fqdirp = fqdir;
     183                 :          3 :         return 0;
     184                 :            : }
     185                 :            : EXPORT_SYMBOL(fqdir_init);
     186                 :            : 
     187                 :          1 : void fqdir_exit(struct fqdir *fqdir)
     188                 :            : {
     189                 :          1 :         INIT_WORK(&fqdir->destroy_work, fqdir_work_fn);
     190                 :          1 :         queue_work(system_wq, &fqdir->destroy_work);
     191                 :          1 : }
     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);
    

Generated by: LCOV version 1.14