/*
* TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap
* device functionality on Windows.
*
* This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
*
* This source code is Copyright (C) 2002-2008 OpenVPN Solutions LLC,
* and is released under the GPL version 2 (see below), however due
* to the extra costs of supporting Windows Vista, OpenVPN Solutions
* LLC reserves the right to change the terms of the TAP-Win32/TAP-Win64
* license for versions 9.1 and higher prior to the official release of
* OpenVPN 2.1.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program (see the file COPYING included with this
* distribution); if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//------------------
// Memory Management
//------------------
PVOID
MemAlloc (ULONG p_Size, BOOLEAN zero)
{
PVOID l_Return = NULL;
if (p_Size)
{
__try
{
if (NdisAllocateMemoryWithTag (&l_Return, p_Size, 'APAT')
== NDIS_STATUS_SUCCESS)
{
if (zero)
NdisZeroMemory (l_Return, p_Size);
}
else
l_Return = NULL;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
l_Return = NULL;
}
}
return l_Return;
}
VOID
MemFree (PVOID p_Addr, ULONG p_Size)
{
if (p_Addr && p_Size)
{
__try
{
#if DBG
NdisZeroMemory (p_Addr, p_Size);
#endif
NdisFreeMemory (p_Addr, p_Size, 0);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
}
}
/*
* Circular queue management routines.
*/
#define QUEUE_BYTE_ALLOCATION(size) \
(sizeof (Queue) + (size * sizeof (PVOID)))
#define QUEUE_ADD_INDEX(var, inc) \
{ \
var += inc; \
if (var >= q->capacity) \
var -= q->capacity; \
MYASSERT (var < q->capacity); \
}
#define QUEUE_SANITY_CHECK() \
MYASSERT (q != NULL && q->base < q->capacity && q->size <= q->capacity)
#define QueueCount(q) (q->size)
#define UPDATE_MAX_SIZE() \
{ \
if (q->size > q->max_size) \
q->max_size = q->size; \
}
Queue *
QueueInit (ULONG capacity)
{
Queue *q;
MYASSERT (capacity > 0);
q = (Queue *) MemAlloc (QUEUE_BYTE_ALLOCATION (capacity), TRUE);
if (!q)
return NULL;
q->base = q->size = 0;
q->capacity = capacity;
q->max_size = 0;
return q;
}
VOID
QueueFree (Queue *q)
{
if (q)
{
QUEUE_SANITY_CHECK ();
MemFree (q, QUEUE_BYTE_ALLOCATION (q->capacity));
}
}
PVOID
QueuePush (Queue *q, PVOID item)
{
ULONG dest;
QUEUE_SANITY_CHECK ();
if (q->size == q->capacity)
return NULL;
dest = q->base;
QUEUE_ADD_INDEX (dest, q->size);
q->data[dest] = item;
++q->size;
UPDATE_MAX_SIZE();
return item;
}
PVOID
QueuePop (Queue *q)
{
ULONG oldbase;
QUEUE_SANITY_CHECK ();
if (!q->size)
return NULL;
oldbase = q->base;
QUEUE_ADD_INDEX (q->base, 1);
--q->size;
UPDATE_MAX_SIZE();
return q->data[oldbase];
}
PVOID
QueueExtract (Queue *q, PVOID item)
{
ULONG src, dest, count, n;
QUEUE_SANITY_CHECK ();
n = 0;
src = dest = q->base;
count = q->size;
while (count--)
{
if (item == q->data[src])
{
++n;
--q->size;
}
else
{
q->data[dest] = q->data[src];
QUEUE_ADD_INDEX (dest, 1);
}
QUEUE_ADD_INDEX (src, 1);
}
if (n)
return item;
else
return NULL;
}
#undef QUEUE_BYTE_ALLOCATION
#undef QUEUE_ADD_INDEX
#undef QUEUE_SANITY_CHECK
#undef UPDATE_MAX_SIZE