1/*
2 *  OpenVPN -- An application to securely tunnel IP networks
3 *             over a single TCP/UDP port, with support for SSL/TLS-based
4 *             session authentication and key exchange,
5 *             packet encryption, packet authentication, and
6 *             packet compression.
7 *
8 *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
9 *
10 *  This program is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 2
12 *  as published by the Free Software Foundation.
13 *
14 *  This program is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this program (see the file COPYING included with this
21 *  distribution); if not, write to the Free Software Foundation, Inc.,
22 *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#elif defined(_MSC_VER)
28#include "config-msvc.h"
29#endif
30
31#include "syshead.h"
32
33#if P2MP
34
35#include "buffer.h"
36#include "error.h"
37#include "misc.h"
38#include "mbuf.h"
39
40#include "memdbg.h"
41
42struct mbuf_set *
43mbuf_init (unsigned int size)
44{
45  struct mbuf_set *ret;
46  ALLOC_OBJ_CLEAR (ret, struct mbuf_set);
47  ret->capacity = adjust_power_of_2 (size);
48  ALLOC_ARRAY (ret->array, struct mbuf_item, ret->capacity);
49  return ret;
50}
51
52void
53mbuf_free (struct mbuf_set *ms)
54{
55  if (ms)
56    {
57      int i;
58      for (i = 0; i < (int) ms->len; ++i)
59	{
60	  struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)];
61	  mbuf_free_buf (item->buffer);
62	}
63      free (ms->array);
64      free (ms);
65    }
66}
67
68struct mbuf_buffer *
69mbuf_alloc_buf (const struct buffer *buf)
70{
71  struct mbuf_buffer *ret;
72  ALLOC_OBJ (ret, struct mbuf_buffer);
73  ret->buf = clone_buf (buf);
74  ret->refcount = 1;
75  ret->flags = 0;
76  return ret;
77}
78
79void
80mbuf_free_buf (struct mbuf_buffer *mb)
81{
82  if (mb)
83    {
84      if (--mb->refcount <= 0)
85	{
86	  free_buf (&mb->buf);
87	  free (mb);
88	}
89    }
90}
91
92void
93mbuf_add_item (struct mbuf_set *ms, const struct mbuf_item *item)
94{
95  ASSERT (ms);
96  if (ms->len == ms->capacity)
97    {
98      struct mbuf_item rm;
99      ASSERT (mbuf_extract_item (ms, &rm));
100      mbuf_free_buf (rm.buffer);
101      msg (D_MULTI_DROPPED, "MBUF: mbuf packet dropped");
102    }
103
104  ASSERT (ms->len < ms->capacity);
105
106  ms->array[MBUF_INDEX(ms->head, ms->len, ms->capacity)] = *item;
107  if (++ms->len > ms->max_queued)
108    ms->max_queued = ms->len;
109  ++item->buffer->refcount;
110}
111
112bool
113mbuf_extract_item (struct mbuf_set *ms, struct mbuf_item *item)
114{
115  bool ret = false;
116  if (ms)
117    {
118      while (ms->len)
119	{
120	  *item = ms->array[ms->head];
121	  ms->head = MBUF_INDEX(ms->head, 1, ms->capacity);
122	  --ms->len;
123	  if (item->instance) /* ignore dereferenced instances */
124	    {
125	      ret = true;
126	      break;
127	    }
128	}
129    }
130  return ret;
131}
132
133struct multi_instance *
134mbuf_peek_dowork (struct mbuf_set *ms)
135{
136  struct multi_instance *ret = NULL;
137  if (ms)
138    {
139      int i;
140      for (i = 0; i < (int) ms->len; ++i)
141	{
142	  struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)];
143	  if (item->instance)
144	    {
145	      ret = item->instance;
146	      break;
147	    }
148	}
149    }
150  return ret;
151}
152
153void
154mbuf_dereference_instance (struct mbuf_set *ms, struct multi_instance *mi)
155{
156  if (ms)
157    {
158      int i;
159      for (i = 0; i < (int) ms->len; ++i)
160	{
161	  struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)];
162	  if (item->instance == mi)
163	    {
164	      mbuf_free_buf (item->buffer);
165	      item->buffer = NULL;
166	      item->instance = NULL;
167	      msg (D_MBUF, "MBUF: dereferenced queued packet");
168	    }
169	}
170    }
171}
172
173#else
174static void dummy(void) {}
175#endif /* P2MP */
176