Upgrade to OpenVPN 2.1.0
[tomato.git] / release / src / router / openvpn / tap-win32 / instance.c
blobef994ee65fa29fc98b650077c089859009286337
1 /*
2 * TAP-Win32/TAP-Win64 -- A kernel driver to provide virtual tap
3 * device functionality on Windows.
5 * This code was inspired by the CIPE-Win32 driver by Damion K. Wilson.
7 * This source code is Copyright (C) 2002-2009 OpenVPN Technologies, Inc.,
8 * and is released under the GPL version 2 (see below).
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.
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.
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
25 #define INSTANCE_KEY(a) ((PVOID)((a)->m_Extension.m_TapDevice))
27 #define N_INSTANCE_BUCKETS 256
29 typedef struct _INSTANCE {
30 struct _INSTANCE *next;
31 TapAdapterPointer m_Adapter;
32 } INSTANCE;
34 typedef struct {
35 INSTANCE *list;
36 MUTEX lock;
37 } INSTANCE_BUCKET;
39 typedef struct {
40 INSTANCE_BUCKET buckets[N_INSTANCE_BUCKETS];
41 } INSTANCE_HASH;
43 INSTANCE_HASH *g_InstanceHash = NULL;
45 // must return a hash >= 0 and < N_INSTANCE_BUCKETS
46 int
47 InstanceHashValue (PVOID addr)
49 UCHAR *p = (UCHAR *) &addr;
51 if (sizeof (addr) == 4)
52 return p[0] ^ p[1] ^ p[2] ^ p[3];
53 else if (sizeof (addr) == 8)
54 return p[0] ^ p[1] ^ p[2] ^ p[3] ^ p[4] ^ p[5] ^ p[6] ^ p[7];
55 else
57 MYASSERT (0);
61 BOOLEAN
62 InitInstanceList (VOID)
64 MYASSERT (g_InstanceHash == NULL);
65 g_InstanceHash = MemAlloc (sizeof (INSTANCE_HASH), TRUE);
66 if (g_InstanceHash)
68 int i;
69 for (i = 0; i < N_INSTANCE_BUCKETS; ++i)
70 INIT_MUTEX (&g_InstanceHash->buckets[i].lock);
71 return TRUE;
73 else
74 return FALSE;
77 int
78 NInstances (VOID)
80 int i, n = 0;
82 if (g_InstanceHash)
84 for (i = 0; i < N_INSTANCE_BUCKETS; ++i)
86 BOOLEAN got_lock;
87 INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[i];
88 ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
90 if (got_lock)
92 INSTANCE *current;
93 for (current = ib->list; current != NULL; current = current->next)
94 ++n;
95 RELEASE_MUTEX (&ib->lock);
97 else
98 return -1;
102 return n;
106 InstanceMaxBucketSize (VOID)
108 int i, n = 0;
110 if (g_InstanceHash)
112 for (i = 0; i < N_INSTANCE_BUCKETS; ++i)
114 BOOLEAN got_lock;
115 int bucket_size = 0;
116 INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[i];
117 ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
119 if (got_lock)
121 INSTANCE *current;
122 for (current = ib->list; current != NULL; current = current->next)
123 ++bucket_size;
124 if (bucket_size > n)
125 n = bucket_size;
126 RELEASE_MUTEX (&ib->lock);
128 else
129 return -1;
133 return n;
136 VOID
137 FreeInstanceList (VOID)
139 if (g_InstanceHash)
141 MYASSERT (NInstances() == 0);
142 MemFree (g_InstanceHash, sizeof (INSTANCE_HASH));
143 g_InstanceHash = NULL;
147 BOOLEAN
148 AddAdapterToInstanceList (TapAdapterPointer p_Adapter)
150 BOOLEAN got_lock;
151 BOOLEAN ret = FALSE;
152 const int hash = InstanceHashValue(INSTANCE_KEY(p_Adapter));
153 INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[hash];
155 DEBUGP (("[TAP] AddAdapterToInstanceList hash=%d\n", hash));
157 ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
159 if (got_lock)
161 INSTANCE *i = MemAlloc (sizeof (INSTANCE), FALSE);
162 if (i)
164 MYASSERT (p_Adapter);
165 i->m_Adapter = p_Adapter;
166 i->next = ib->list;
167 ib->list = i;
168 ret = TRUE;
170 RELEASE_MUTEX (&ib->lock);
173 return ret;
176 BOOLEAN
177 RemoveAdapterFromInstanceList (TapAdapterPointer p_Adapter)
179 BOOLEAN got_lock;
180 BOOLEAN ret = FALSE;
181 INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[InstanceHashValue(INSTANCE_KEY(p_Adapter))];
183 ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
185 if (got_lock)
187 INSTANCE *current, *prev=NULL;
188 for (current = ib->list; current != NULL; current = current->next)
190 if (current->m_Adapter == p_Adapter) // found match
192 if (prev)
193 prev->next = current->next;
194 else
195 ib->list = current->next;
196 MemFree (current->m_Adapter, sizeof (TapAdapter));
197 MemFree (current, sizeof (INSTANCE));
198 ret = TRUE;
199 break;
201 prev = current;
203 RELEASE_MUTEX (&ib->lock);
206 return ret;
209 TapAdapterPointer
210 LookupAdapterInInstanceList (PDEVICE_OBJECT p_DeviceObject)
212 BOOLEAN got_lock;
213 TapAdapterPointer ret = NULL;
214 INSTANCE_BUCKET *ib = &g_InstanceHash->buckets[InstanceHashValue((PVOID)p_DeviceObject)];
216 ACQUIRE_MUTEX_ADAPTIVE (&ib->lock, got_lock);
218 if (got_lock)
220 INSTANCE *current, *prev=NULL;
221 for (current = ib->list; current != NULL; current = current->next)
223 if (p_DeviceObject == INSTANCE_KEY (current->m_Adapter)) // found match
225 // move it to head of list
226 if (prev)
228 prev->next = current->next;
229 current->next = ib->list;
230 ib->list = current;
232 ret = ib->list->m_Adapter;
233 break;
235 prev = current;
237 RELEASE_MUTEX (&ib->lock);
240 return ret;