/* * 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 Technologies, Inc., * 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