src/openvpn/mbuf.c
6fbf66fa
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single TCP/UDP port, with support for SSL/TLS-based
  *             session authentication and key exchange,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
58716979
  *  Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net>
6fbf66fa
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
caa54ac3
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
6fbf66fa
  */
 
c110b289
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
6fbf66fa
 #include "syshead.h"
 
 #if P2MP
 
 #include "buffer.h"
 #include "error.h"
9fc0e963
 #include "integer.h"
6fbf66fa
 #include "misc.h"
 #include "mbuf.h"
 
 #include "memdbg.h"
 
 struct mbuf_set *
81d882d5
 mbuf_init(unsigned int size)
6fbf66fa
 {
81d882d5
     struct mbuf_set *ret;
     ALLOC_OBJ_CLEAR(ret, struct mbuf_set);
     ret->capacity = adjust_power_of_2(size);
     ALLOC_ARRAY(ret->array, struct mbuf_item, ret->capacity);
     return ret;
6fbf66fa
 }
 
 void
81d882d5
 mbuf_free(struct mbuf_set *ms)
6fbf66fa
 {
81d882d5
     if (ms)
6fbf66fa
     {
81d882d5
         int i;
         for (i = 0; i < (int) ms->len; ++i)
         {
             struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)];
             mbuf_free_buf(item->buffer);
         }
         free(ms->array);
         free(ms);
6fbf66fa
     }
 }
 
 struct mbuf_buffer *
81d882d5
 mbuf_alloc_buf(const struct buffer *buf)
6fbf66fa
 {
81d882d5
     struct mbuf_buffer *ret;
     ALLOC_OBJ(ret, struct mbuf_buffer);
     ret->buf = clone_buf(buf);
     ret->refcount = 1;
     ret->flags = 0;
     return ret;
6fbf66fa
 }
 
 void
81d882d5
 mbuf_free_buf(struct mbuf_buffer *mb)
6fbf66fa
 {
81d882d5
     if (mb)
6fbf66fa
     {
81d882d5
         if (--mb->refcount <= 0)
         {
             free_buf(&mb->buf);
             free(mb);
         }
6fbf66fa
     }
 }
 
 void
81d882d5
 mbuf_add_item(struct mbuf_set *ms, const struct mbuf_item *item)
6fbf66fa
 {
81d882d5
     ASSERT(ms);
     if (ms->len == ms->capacity)
6fbf66fa
     {
81d882d5
         struct mbuf_item rm;
         ASSERT(mbuf_extract_item(ms, &rm));
         mbuf_free_buf(rm.buffer);
         msg(D_MULTI_DROPPED, "MBUF: mbuf packet dropped");
6fbf66fa
     }
 
81d882d5
     ASSERT(ms->len < ms->capacity);
6fbf66fa
 
81d882d5
     ms->array[MBUF_INDEX(ms->head, ms->len, ms->capacity)] = *item;
     if (++ms->len > ms->max_queued)
     {
         ms->max_queued = ms->len;
     }
     ++item->buffer->refcount;
6fbf66fa
 }
 
 bool
81d882d5
 mbuf_extract_item(struct mbuf_set *ms, struct mbuf_item *item)
6fbf66fa
 {
81d882d5
     bool ret = false;
     if (ms)
6fbf66fa
     {
81d882d5
         while (ms->len)
         {
             *item = ms->array[ms->head];
             ms->head = MBUF_INDEX(ms->head, 1, ms->capacity);
             --ms->len;
             if (item->instance) /* ignore dereferenced instances */
             {
                 ret = true;
                 break;
             }
         }
6fbf66fa
     }
81d882d5
     return ret;
6fbf66fa
 }
 
 struct multi_instance *
81d882d5
 mbuf_peek_dowork(struct mbuf_set *ms)
6fbf66fa
 {
81d882d5
     struct multi_instance *ret = NULL;
     if (ms)
6fbf66fa
     {
81d882d5
         int i;
         for (i = 0; i < (int) ms->len; ++i)
         {
             struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)];
             if (item->instance)
             {
                 ret = item->instance;
                 break;
             }
         }
6fbf66fa
     }
81d882d5
     return ret;
6fbf66fa
 }
 
 void
81d882d5
 mbuf_dereference_instance(struct mbuf_set *ms, struct multi_instance *mi)
6fbf66fa
 {
81d882d5
     if (ms)
6fbf66fa
     {
81d882d5
         int i;
         for (i = 0; i < (int) ms->len; ++i)
         {
             struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)];
             if (item->instance == mi)
             {
                 mbuf_free_buf(item->buffer);
                 item->buffer = NULL;
                 item->instance = NULL;
                 msg(D_MBUF, "MBUF: dereferenced queued packet");
             }
         }
6fbf66fa
     }
 }
 
81d882d5
 #else  /* if P2MP */
 static void
4cd4899e
 dummy(void)
 {
81d882d5
 }
6fbf66fa
 #endif /* P2MP */