VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetFlt/VBoxNetFlt.c@ 16524

Last change on this file since 16524 was 16193, checked in by vboxsync, 16 years ago

#3419: Added fNoPromisc parameter to vboxNetFltNewInstance for dynamic configuration.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 46.3 KB
Line 
1/* $Id: VBoxNetFlt.c 16193 2009-01-23 09:38:11Z vboxsync $ */
2/** @file
3 * VBoxNetFlt - Network Filter Driver (Host), Common Code.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/** @page pg_netflt VBoxNetFlt - Network Interface Filter
23 *
24 * This is a kernel module that attaches to a real interface on the host
25 * and filters and injects packets.
26 *
27 * In the big picture we're one of the three trunk interface on the internal
28 * network, the one named "NIC Filter Driver": @image html Networking_Overview.gif
29 *
30 *
31 * @section sec_netflt_msc Locking / Sequence Diagrams
32 *
33 * This secion contains a few sequence diagrams describing the problematic
34 * transitions of a host interface filter instance.
35 *
36 * The thing that makes it all a bit problematic is that multiple events may
37 * happen at the same time, and that we have to be very careful to avoid
38 * deadlocks caused by mixing our locks with the ones in the host kernel.
39 * The main events are receive, send, async send completion, disappearance of
40 * the host networking interface and it's reappearance. The latter two events
41 * are can be caused by driver unloading/loading or the device being physical
42 * unplugged (e.g. a USB network device).
43 *
44 * The strategy for dealing with these issues are:
45 * - Use a simple state machine.
46 * - Require the user (IntNet) to serialize all its calls to us,
47 * while at the same time not owning any lock used by any of the
48 * the callbacks we might call on receive and async send completion.
49 * - Make sure we're 100% idle before disconnecting, and have a
50 * disconnected status on both sides to fend off async calls.
51 * - Protect the host specific interface handle and the state variables
52 * using a spinlock.
53 *
54 *
55 * @subsection subsec_netflt_msc_dis_rel Disconnect from the network and release
56 *
57 * @msc
58 * VM, IntNet, NetFlt, Kernel, Wire;
59 *
60 * VM->IntNet [label="pkt0", linecolor="green", textcolor="green"];
61 * IntNet=>IntNet [label="Lock Network", linecolor="green", textcolor="green" ];
62 * IntNet=>IntNet [label="Route packet -> wire", linecolor="green", textcolor="green" ];
63 * IntNet=>IntNet [label="Unlock Network", linecolor="green", textcolor="green" ];
64 * IntNet=>NetFlt [label="pkt0 to wire", linecolor="green", textcolor="green" ];
65 * NetFlt=>Kernel [label="pkt0 to wire", linecolor="green", textcolor="green"];
66 * Kernel->Wire [label="pkt0 to wire", linecolor="green", textcolor="green"];
67 *
68 * --- [label="Suspending the trunk interface"];
69 * IntNet=>IntNet [label="Lock Network"];
70 *
71 * Wire->Kernel [label="pkt1 - racing us", linecolor="red", textcolor="red"];
72 * Kernel=>>NetFlt [label="pkt1 - racing us", linecolor="red", textcolor="red"];
73 * NetFlt=>>IntNet [label="pkt1 recv - blocks", linecolor="red", textcolor="red"];
74 *
75 * IntNet=>IntNet [label="Mark Trunk Suspended"];
76 * IntNet=>IntNet [label="Unlock Network"];
77 *
78 * IntNet=>NetFlt [label="pfnSetActive(false)"];
79 * NetFlt=>NetFlt [label="Mark inactive (atomic)"];
80 * IntNet<<NetFlt;
81 * IntNet=>NetFlt [label="pfnWaitForIdle(forever)"];
82 *
83 * IntNet=>>NetFlt [label="pkt1 to host", linecolor="red", textcolor="red"];
84 * NetFlt=>>Kernel [label="pkt1 to host", linecolor="red", textcolor="red"];
85 *
86 * Kernel<-Wire [label="pkt0 on wire", linecolor="green", textcolor="green"];
87 * NetFlt<<Kernel [label="pkt0 on wire", linecolor="green", textcolor="green"];
88 * IntNet<<=NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
89 * IntNet<<=IntNet [label="Lock Net, free SG, Unlock Net", linecolor="green", textcolor="green"];
90 * IntNet>>NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
91 * NetFlt<-NetFlt [label="idle", linecolor="green", textcolor="green"];
92 *
93 * IntNet<<NetFlt [label="idle (pfnWaitForIdle)"];
94 *
95 * Wire->Kernel [label="pkt2", linecolor="red", textcolor="red"];
96 * Kernel=>>NetFlt [label="pkt2", linecolor="red", textcolor="red"];
97 * NetFlt=>>Kernel [label="pkt2 to host", linecolor="red", textcolor="red"];
98 *
99 * VM->IntNet [label="pkt3", linecolor="green", textcolor="green"];
100 * IntNet=>IntNet [label="Lock Network", linecolor="green", textcolor="green" ];
101 * IntNet=>IntNet [label="Route packet -> drop", linecolor="green", textcolor="green" ];
102 * IntNet=>IntNet [label="Unlock Network", linecolor="green", textcolor="green" ];
103 *
104 * --- [label="The trunk interface is idle now, disconnect it"];
105 * IntNet=>IntNet [label="Lock Network"];
106 * IntNet=>IntNet [label="Unlink Trunk"];
107 * IntNet=>IntNet [label="Unlock Network"];
108 * IntNet=>NetFlt [label="pfnDisconnectAndRelease"];
109 * NetFlt=>Kernel [label="iflt_detach"];
110 * NetFlt<<=Kernel [label="iff_detached"];
111 * NetFlt>>Kernel [label="iff_detached"];
112 * NetFlt<<Kernel [label="iflt_detach"];
113 * NetFlt=>NetFlt [label="Release"];
114 * IntNet<<NetFlt [label="pfnDisconnectAndRelease"];
115 *
116 * @endmsc
117 *
118 *
119 *
120 * @subsection subsec_netflt_msc_hif_rm Host Interface Removal
121 *
122 * The ifnet_t (pIf) is a tricky customer as any reference to it can potentially
123 * race the filter detaching. The simple way of solving it on Darwin is to guard
124 * all access to the pIf member with a spinlock. The other host systems will
125 * probably have similar race conditions, so the spinlock is a generic thing.
126 *
127 * @msc
128 * VM, IntNet, NetFlt, Kernel;
129 *
130 * VM->IntNet [label="pkt0", linecolor="green", textcolor="green"];
131 * IntNet=>IntNet [label="Lock Network", linecolor="green", textcolor="green" ];
132 * IntNet=>IntNet [label="Route packet -> wire", linecolor="green", textcolor="green" ];
133 * IntNet=>IntNet [label="Unlock Network", linecolor="green", textcolor="green" ];
134 * IntNet=>NetFlt [label="pkt0 to wire", linecolor="green", textcolor="green" ];
135 * NetFlt=>Kernel [label="ifnet_reference w/ spinlock", linecolor="green", textcolor="green" ];
136 * NetFlt<<Kernel [label="ifnet_reference", linecolor="green", textcolor="green" ];
137 * NetFlt=>Kernel [label="pkt0 to wire (blocks)", linecolor="green", textcolor="green" ];
138 *
139 * --- [label="The host interface is being disconnected"];
140 * Kernel->NetFlt [label="iff_detached"];
141 * NetFlt=>Kernel [label="ifnet_release w/ spinlock"];
142 * NetFlt<<Kernel [label="ifnet_release"];
143 * NetFlt=>NetFlt [label="fDisconnectedFromHost=true"];
144 * NetFlt>>Kernel [label="iff_detached"];
145 *
146 * NetFlt<<Kernel [label="dropped", linecolor="green", textcolor="green"];
147 * NetFlt=>NetFlt [label="Acquire spinlock", linecolor="green", textcolor="green"];
148 * NetFlt=>Kernel [label="ifnet_release", linecolor="green", textcolor="green"];
149 * NetFlt<<Kernel [label="ifnet_release", linecolor="green", textcolor="green"];
150 * NetFlt=>NetFlt [label="pIf=NULL", linecolor="green", textcolor="green"];
151 * NetFlt=>NetFlt [label="Release spinlock", linecolor="green", textcolor="green"];
152 * IntNet<=NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
153 * IntNet>>NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
154 * IntNet<<NetFlt [label="pkt0 to wire", linecolor="green", textcolor="green"];
155 *
156 * @endmsc
157 *
158 *
159 *
160 * @subsection subsec_netflt_msc_hif_rm Host Interface Rediscovery
161 *
162 * The rediscovery is performed when we receive a send request and a certain
163 * period have elapsed since the last attempt, i.e. we're polling it. We
164 * synchronize the rediscovery with disconnection from the internal network
165 * by means of the pfnWaitForIdle call, so no special handling is required.
166 *
167 * @msc
168 * VM2, VM1, IntNet, NetFlt, Kernel, Wire;
169 *
170 * --- [label="Rediscovery conditions are not met"];
171 * VM1->IntNet [label="pkt0"];
172 * IntNet=>IntNet [label="Lock Network"];
173 * IntNet=>IntNet [label="Route packet -> wire"];
174 * IntNet=>IntNet [label="Unlock Network"];
175 * IntNet=>NetFlt [label="pkt0 to wire"];
176 * NetFlt=>NetFlt [label="Read pIf(==NULL) w/ spinlock"];
177 * IntNet<<NetFlt [label="pkt0 to wire (dropped)"];
178 *
179 * --- [label="Rediscovery conditions"];
180 * VM1->IntNet [label="pkt1"];
181 * IntNet=>IntNet [label="Lock Network"];
182 * IntNet=>IntNet [label="Route packet -> wire"];
183 * IntNet=>IntNet [label="Unlock Network"];
184 * IntNet=>NetFlt [label="pkt1 to wire"];
185 * NetFlt=>NetFlt [label="Read pIf(==NULL) w/ spinlock"];
186 * NetFlt=>NetFlt [label="fRediscoveryPending=true w/ spinlock"];
187 * NetFlt=>Kernel [label="ifnet_find_by_name"];
188 * NetFlt<<Kernel [label="ifnet_find_by_name (success)"];
189 *
190 * VM2->IntNet [label="pkt2", linecolor="red", textcolor="red"];
191 * IntNet=>IntNet [label="Lock Network", linecolor="red", textcolor="red"];
192 * IntNet=>IntNet [label="Route packet -> wire", linecolor="red", textcolor="red"];
193 * IntNet=>IntNet [label="Unlock Network", linecolor="red", textcolor="red"];
194 * IntNet=>NetFlt [label="pkt2 to wire", linecolor="red", textcolor="red"];
195 * NetFlt=>NetFlt [label="!pIf || fRediscoveryPending (w/ spinlock)", linecolor="red", textcolor="red"];
196 * IntNet<<NetFlt [label="pkt2 to wire (dropped)", linecolor="red", textcolor="red"];
197
198 * NetFlt=>Kernel [label="iflt_attach"];
199 * NetFlt<<Kernel [label="iflt_attach (success)"];
200 * NetFlt=>NetFlt [label="Acquire spinlock"];
201 * NetFlt=>NetFlt [label="Set pIf and update flags"];
202 * NetFlt=>NetFlt [label="Release spinlock"];
203 *
204 * NetFlt=>Kernel [label="pkt1 to wire"];
205 * Kernel->Wire [label="pkt1 to wire"];
206 * NetFlt<<Kernel [label="pkt1 to wire"];
207 * IntNet<<NetFlt [label="pkt1 to wire"];
208 *
209 *
210 * @endmsc
211 *
212 */
213
214/*******************************************************************************
215* Header Files *
216*******************************************************************************/
217#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
218#include "VBoxNetFltInternal.h"
219
220#include <VBox/sup.h>
221#include <VBox/log.h>
222#include <VBox/err.h>
223#include <iprt/assert.h>
224#include <iprt/mem.h>
225#include <iprt/string.h>
226#include <iprt/spinlock.h>
227#include <iprt/semaphore.h>
228#include <iprt/time.h>
229#include <iprt/uuid.h>
230
231/*******************************************************************************
232* Defined Constants And Macros *
233*******************************************************************************/
234#define IFPORT_2_VBOXNETFLTINS(pIfPort) \
235 ( (PVBOXNETFLTINS)((uint8_t *)pIfPort - RT_OFFSETOF(VBOXNETFLTINS, MyPort)) )
236
237
238/**
239 * Finds a instance by its name, the caller does the locking.
240 *
241 *
242 * @returns Pointer to the instance by the given name. NULL if not found.
243 * @param pGlobals The globals.
244 * @param pszName The name of the instance.
245 */
246static PVBOXNETFLTINS vboxNetFltFindInstanceLocked(PVBOXNETFLTGLOBALS pGlobals, const char *pszName)
247{
248 PVBOXNETFLTINS pCur;
249 for (pCur = pGlobals->pInstanceHead; pCur; pCur = pCur->pNext)
250 if (!strcmp(pszName, pCur->szName))
251 return pCur;
252 return NULL;
253}
254
255
256/**
257 * Finds a instance by its name, will request the mutex.
258 *
259 * @returns Pointer to the instance by the given name. NULL if not found.
260 * @param pGlobals The globals.
261 * @param pszName The name of the instance.
262 */
263DECLHIDDEN(PVBOXNETFLTINS) vboxNetFltFindInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName)
264{
265 PVBOXNETFLTINS pRet;
266 int rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
267 AssertRCReturn(rc, NULL);
268
269 pRet = vboxNetFltFindInstanceLocked(pGlobals, pszName);
270
271 rc = RTSemFastMutexRelease(pGlobals->hFastMtx);
272 AssertRC(rc);
273 return pRet;
274}
275
276
277/**
278 * Unlinks an instance from the chain.
279 *
280 * @param pGlobals The globals.
281 * @param pToUnlink The instance to unlink.
282 */
283static void vboxNetFltUnlinkLocked(PVBOXNETFLTGLOBALS pGlobals, PVBOXNETFLTINS pToUnlink)
284{
285 if (pGlobals->pInstanceHead == pToUnlink)
286 pGlobals->pInstanceHead = pToUnlink->pNext;
287 else
288 {
289 PVBOXNETFLTINS pCur;
290 for (pCur = pGlobals->pInstanceHead; pCur; pCur = pCur->pNext)
291 if (pCur->pNext == pToUnlink)
292 {
293 pCur->pNext = pToUnlink->pNext;
294 break;
295 }
296 Assert(pCur);
297 }
298 pToUnlink->pNext = NULL;
299}
300
301
302AssertCompileMemberSize(VBOXNETFLTINS, enmState, sizeof(uint32_t));
303
304/**
305 * Sets the enmState member atomically.
306 *
307 * Used for all updates.
308 *
309 * @param pThis The instance.
310 * @param enmNewState The new value.
311 */
312DECLINLINE(void) vboxNetFltSetState(PVBOXNETFLTINS pThis, VBOXNETFTLINSSTATE enmNewState)
313{
314 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, enmNewState);
315}
316
317
318/**
319 * Gets the enmState member atomically.
320 *
321 * Used for all reads.
322 *
323 * @returns The enmState value.
324 * @param pThis The instance.
325 */
326DECLINLINE(VBOXNETFTLINSSTATE) vboxNetFltGetState(PVBOXNETFLTINS pThis)
327{
328 return (VBOXNETFTLINSSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState);
329}
330
331
332/**
333 * Performs interface rediscovery if it was disconnected from the host.
334 *
335 * @returns true if successfully rediscovered and connected, false if not.
336 * @param pThis The instance.
337 */
338static bool vboxNetFltMaybeRediscovered(PVBOXNETFLTINS pThis)
339{
340 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
341 uint64_t Now = RTTimeNanoTS();
342 bool fRediscovered;
343 bool fDoIt;
344
345 /*
346 * Rediscovered already? Time to try again?
347 */
348 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
349
350 fRediscovered = !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
351 fDoIt = !fRediscovered
352 && !ASMAtomicUoReadBool(&pThis->fRediscoveryPending)
353 && Now - ASMAtomicUoReadU64(&pThis->NanoTSLastRediscovery) > UINT64_C(5000000000); /* 5 sec */
354 if (fDoIt)
355 ASMAtomicWriteBool(&pThis->fRediscoveryPending, true);
356
357 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
358
359 /*
360 * Call the OS specific code to do the job.
361 * Update the state when the call returns, that is everything except for
362 * the fDisconnectedFromHost flag which the OS specific code shall set.
363 */
364 if (fDoIt)
365 {
366 fRediscovered = vboxNetFltOsMaybeRediscovered(pThis);
367
368 Assert(!fRediscovered || !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost));
369
370 ASMAtomicUoWriteU64(&pThis->NanoTSLastRediscovery, RTTimeNanoTS());
371 ASMAtomicWriteBool(&pThis->fRediscoveryPending, false);
372
373 if (fRediscovered)
374 vboxNetFltPortOsSetActive(pThis, pThis->fActive);
375 }
376
377 return fRediscovered;
378}
379
380#ifdef RT_WITH_W64_UNWIND_HACK
381# if defined(RT_OS_WINDOWS) && defined(RT_ARCH_AMD64)
382# define NETFLT_DECL_CALLBACK(type) DECLASM(DECLHIDDEN(type))
383# define NETFLT_CALLBACK(_n) netfltNtWrap##_n
384
385NETFLT_DECL_CALLBACK(int) NETFLT_CALLBACK(vboxNetFltPortXmit)(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst);
386NETFLT_DECL_CALLBACK(bool) NETFLT_CALLBACK(vboxNetFltPortIsPromiscuous)(PINTNETTRUNKIFPORT pIfPort);
387NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortGetMacAddress)(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac);
388NETFLT_DECL_CALLBACK(bool) NETFLT_CALLBACK(vboxNetFltPortIsHostMac)(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac);
389NETFLT_DECL_CALLBACK(int) NETFLT_CALLBACK(vboxNetFltPortWaitForIdle)(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies);
390NETFLT_DECL_CALLBACK(bool) NETFLT_CALLBACK(vboxNetFltPortSetActive)(PINTNETTRUNKIFPORT pIfPort, bool fActive);
391NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortDisconnectAndRelease)(PINTNETTRUNKIFPORT pIfPort);
392NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortRetain)(PINTNETTRUNKIFPORT pIfPort);
393NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortRelease)(PINTNETTRUNKIFPORT pIfPort);
394
395# else
396# error "UNSUPPORTED (RT_WITH_W64_UNWIND_HACK)"
397# endif
398#else
399# define NETFLT_DECL_CALLBACK(type) static DECLCALLBACK(type)
400# define NETFLT_CALLBACK(_n) _n
401#endif
402
403/**
404 * @copydoc INTNETTRUNKIFPORT::pfnXmit
405 */
406NETFLT_DECL_CALLBACK(int) vboxNetFltPortXmit(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst)
407{
408 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
409 int rc = VINF_SUCCESS;
410
411 /*
412 * Input validation.
413 */
414 AssertPtr(pThis);
415 AssertPtr(pSG);
416 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
417 AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, VERR_INVALID_STATE);
418 Assert(pThis->fActive);
419
420 /*
421 * Do a busy retain and then make sure we're connected to the interface
422 * before invoking the OS specific code.
423 */
424 vboxNetFltRetain(pThis, true /* fBusy */);
425 if ( !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost)
426 || vboxNetFltMaybeRediscovered(pThis))
427 rc = vboxNetFltPortOsXmit(pThis, pSG, fDst);
428 vboxNetFltRelease(pThis, true /* fBusy */);
429
430 return rc;
431}
432
433
434/**
435 * @copydoc INTNETTRUNKIFPORT::pfnIsPromiscuous
436 */
437NETFLT_DECL_CALLBACK(bool) vboxNetFltPortIsPromiscuous(PINTNETTRUNKIFPORT pIfPort)
438{
439 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
440
441 /*
442 * Input validation.
443 */
444 AssertPtr(pThis);
445 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
446 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
447 Assert(pThis->fActive);
448
449 /*
450 * Ask the OS specific code.
451 */
452 return vboxNetFltPortOsIsPromiscuous(pThis);
453}
454
455
456/**
457 * @copydoc INTNETTRUNKIFPORT::pfnGetMacAddress
458 */
459NETFLT_DECL_CALLBACK(void) vboxNetFltPortGetMacAddress(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac)
460{
461 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
462
463 /*
464 * Input validation.
465 */
466 AssertPtr(pThis);
467 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
468 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
469 Assert(pThis->fActive);
470
471 /*
472 * Forward the question to the OS specific code.
473 */
474 vboxNetFltPortOsGetMacAddress(pThis, pMac);
475}
476
477
478/**
479 * @copydoc INTNETTRUNKIFPORT::pfnIsHostMac
480 */
481NETFLT_DECL_CALLBACK(bool) vboxNetFltPortIsHostMac(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac)
482{
483 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
484
485 /*
486 * Input validation.
487 */
488 AssertPtr(pThis);
489 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
490 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
491 Assert(pThis->fActive);
492
493 /*
494 * Ask the OS specific code.
495 */
496 return vboxNetFltPortOsIsHostMac(pThis, pMac);
497}
498
499
500/**
501 * @copydoc INTNETTRUNKIFPORT::pfnWaitForIdle
502 */
503NETFLT_DECL_CALLBACK(int) vboxNetFltPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)
504{
505 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
506 int rc;
507
508 /*
509 * Input validation.
510 */
511 AssertPtr(pThis);
512 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
513 AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, VERR_INVALID_STATE);
514 AssertReturn(!pThis->fActive, VERR_INVALID_STATE);
515
516 /*
517 * Go to sleep on the semaphore after checking the busy count.
518 */
519 vboxNetFltRetain(pThis, false /* fBusy */);
520
521 rc = VINF_SUCCESS;
522 while (pThis->cBusy && RT_SUCCESS(rc))
523 rc = RTSemEventWait(pThis->hEventIdle, cMillies); /** @todo make interruptible? */
524
525 vboxNetFltRelease(pThis, false /* fBusy */);
526
527 return rc;
528}
529
530
531/**
532 * @copydoc INTNETTRUNKIFPORT::pfnSetActive
533 */
534NETFLT_DECL_CALLBACK(bool) vboxNetFltPortSetActive(PINTNETTRUNKIFPORT pIfPort, bool fActive)
535{
536 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
537
538 /*
539 * Input validation.
540 */
541 AssertPtr(pThis);
542 AssertPtr(pThis->pGlobals);
543 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
544 AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, false);
545
546 /*
547 * We're assuming that the caller is serializing the calls, so we don't
548 * have to be extremely careful here. Just update first and then call
549 * the OS specific code, the update must be serialized for various reasons.
550 */
551 if (ASMAtomicReadBool(&pThis->fActive) != fActive)
552 {
553 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
554 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
555 ASMAtomicWriteBool(&pThis->fActive, fActive);
556 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
557
558 vboxNetFltPortOsSetActive(pThis, fActive);
559 }
560 else
561 fActive = !fActive;
562 return !fActive;
563}
564
565
566/**
567 * @copydoc INTNETTRUNKIFPORT::pfnDisconnectAndRelease
568 */
569NETFLT_DECL_CALLBACK(void) vboxNetFltPortDisconnectAndRelease(PINTNETTRUNKIFPORT pIfPort)
570{
571 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
572 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
573
574 /*
575 * Serious paranoia.
576 */
577 AssertPtr(pThis);
578 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
579 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
580 AssertPtr(pThis->pGlobals);
581 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
582 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
583 Assert(pThis->szName[0]);
584
585 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
586 Assert(!pThis->fActive);
587 Assert(!pThis->fRediscoveryPending);
588 Assert(!pThis->cBusy);
589
590 /*
591 * Disconnect and release it.
592 */
593 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
594 vboxNetFltSetState(pThis, kVBoxNetFltInsState_Disconnecting);
595 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
596
597 vboxNetFltOsDisconnectIt(pThis);
598 pThis->pSwitchPort = NULL;
599
600#ifdef VBOXNETFLT_STATIC_CONFIG
601 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
602 vboxNetFltSetState(pThis, kVBoxNetFltInsState_Unconnected);
603 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
604#endif
605
606 vboxNetFltRelease(pThis, false /* fBusy */);
607}
608
609
610/**
611 * Destroy a device that has been disconnected from the switch.
612 *
613 * @return true iff the instance is destroyed, false otherwise
614 * @param pThis The instance to be destroyed. This is
615 * no longer valid when this function returns.
616 */
617static bool vboxNetFltCheckDestroyInstance(PVBOXNETFLTINS pThis)
618{
619 PVBOXNETFLTGLOBALS pGlobals = pThis->pGlobals;
620 int rc;
621 uint32_t cRefs = ASMAtomicUoReadU32((uint32_t volatile *)&pThis->cRefs);
622 LogFlow(("vboxNetFltCheckDestroyInstance: pThis=%p (%s)\n", pThis, pThis->szName));
623
624 /*
625 * Validate the state.
626 */
627#ifdef VBOXNETFLT_STATIC_CONFIG
628 Assert( vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Disconnecting
629 || vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Unconnected);
630#else
631 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Disconnecting);
632#endif
633 Assert(!pThis->fActive);
634 Assert(!pThis->fRediscoveryPending);
635 Assert(!pThis->cRefs);
636 Assert(!pThis->cBusy);
637 Assert(!pThis->pSwitchPort);
638
639 /*
640 * Make sure the state is 'disconnecting' and let the OS specific code
641 * do its part of the cleanup outside the mutex.
642 */
643 rc = RTSemFastMutexRequest(pGlobals->hFastMtx); AssertRC(rc);
644 if(cRefs != 0)
645 {
646 Assert(cRefs < UINT32_MAX / 2);
647 RTSemFastMutexRelease(pGlobals->hFastMtx);
648 return false;
649 }
650 vboxNetFltSetState(pThis, kVBoxNetFltInsState_Destroying);
651 RTSemFastMutexRelease(pGlobals->hFastMtx);
652
653 vboxNetFltOsDeleteInstance(pThis);
654
655 /*
656 * Unlink the instance and free up its resources.
657 */
658 rc = RTSemFastMutexRequest(pGlobals->hFastMtx); AssertRC(rc);
659 vboxNetFltSetState(pThis, kVBoxNetFltInsState_Destroyed);
660 vboxNetFltUnlinkLocked(pGlobals, pThis);
661 RTSemFastMutexRelease(pGlobals->hFastMtx);
662
663 RTSemEventDestroy(pThis->hEventIdle);
664 pThis->hEventIdle = NIL_RTSEMEVENT;
665 RTSpinlockDestroy(pThis->hSpinlock);
666 pThis->hSpinlock = NIL_RTSPINLOCK;
667 RTMemFree(pThis);
668 return true;
669}
670
671
672/**
673 * Releases a reference to the specified instance.
674 *
675 * This method will destroy the instance when the count reaches 0.
676 * It will also take care of decrementing the counter and idle wakeup.
677 *
678 * @param pThis The instance.
679 * @param fBusy Whether the busy counter should be decremented too.
680 */
681DECLHIDDEN(void) vboxNetFltRelease(PVBOXNETFLTINS pThis, bool fBusy)
682{
683 uint32_t cRefs;
684
685 /*
686 * Paranoid Android.
687 */
688 AssertPtr(pThis);
689 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
690 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
691 Assert( vboxNetFltGetState(pThis) > kVBoxNetFltInsState_Invalid
692 && vboxNetFltGetState(pThis) < kVBoxNetFltInsState_Destroyed);
693 AssertPtr(pThis->pGlobals);
694 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
695 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
696 Assert(pThis->szName[0]);
697
698 /*
699 * Work the busy counter.
700 */
701 if (fBusy)
702 {
703 cRefs = ASMAtomicDecU32(&pThis->cBusy);
704 if (!cRefs)
705 {
706 int rc = RTSemEventSignal(pThis->hEventIdle);
707 AssertRC(rc);
708 }
709 else
710 Assert(cRefs < UINT32_MAX / 2);
711 }
712
713 /*
714 * The object reference counting.
715 */
716 cRefs = ASMAtomicDecU32(&pThis->cRefs);
717 if (!cRefs)
718 vboxNetFltCheckDestroyInstance(pThis);
719 else
720 Assert(cRefs < UINT32_MAX / 2);
721}
722
723
724/**
725 * @copydoc INTNETTRUNKIFPORT::pfnRetain
726 */
727NETFLT_DECL_CALLBACK(void) vboxNetFltPortRelease(PINTNETTRUNKIFPORT pIfPort)
728{
729 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
730 vboxNetFltRelease(pThis, false /* fBusy */);
731}
732
733
734/**
735 * Retains a reference to the specified instance and a busy reference too.
736 *
737 * @param pThis The instance.
738 * @param fBusy Whether the busy counter should be incremented as well.
739 */
740DECLHIDDEN(void) vboxNetFltRetain(PVBOXNETFLTINS pThis, bool fBusy)
741{
742 uint32_t cRefs;
743
744 /*
745 * Paranoid Android.
746 */
747 AssertPtr(pThis);
748 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
749 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
750 Assert( vboxNetFltGetState(pThis) > kVBoxNetFltInsState_Invalid
751 && vboxNetFltGetState(pThis) < kVBoxNetFltInsState_Destroyed);
752 AssertPtr(pThis->pGlobals);
753 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
754 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
755 Assert(pThis->szName[0]);
756
757 /*
758 * Retain the object.
759 */
760 cRefs = ASMAtomicIncU32(&pThis->cRefs);
761 Assert(cRefs > 1 && cRefs < UINT32_MAX / 2);
762
763 /*
764 * Work the busy counter.
765 */
766 if (fBusy)
767 {
768 cRefs = ASMAtomicIncU32(&pThis->cBusy);
769 Assert(cRefs > 0 && cRefs < UINT32_MAX / 2);
770 }
771
772 NOREF(cRefs);
773}
774
775
776/**
777 * @copydoc INTNETTRUNKIFPORT::pfnRetain
778 */
779NETFLT_DECL_CALLBACK(void) vboxNetFltPortRetain(PINTNETTRUNKIFPORT pIfPort)
780{
781 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
782 vboxNetFltRetain(pThis, false /* fBusy */);
783}
784
785
786/**
787 * Connects the instance to the specified switch port.
788 *
789 * Called while owning the lock. We're ASSUMING that the internal
790 * networking code is already owning an recursive mutex, so, there
791 * will be no deadlocks when vboxNetFltOsConnectIt calls back into
792 * it for setting preferences.
793 *
794 * @returns VBox status code.
795 * @param pThis The instance.
796 * @param pSwitchPort The port on the internal network 'switch'.
797 * @param ppIfPort Where to return our port interface.
798 */
799static int vboxNetFltConnectIt(PVBOXNETFLTINS pThis, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
800{
801 int rc;
802
803 /*
804 * Validate state.
805 */
806 Assert(!pThis->fActive);
807 Assert(!pThis->fRediscoveryPending);
808 Assert(!pThis->cBusy);
809#ifdef VBOXNETFLT_STATIC_CONFIG
810 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Unconnected);
811#else
812 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Initializing);
813#endif
814
815 /*
816 * Do the job.
817 * Note that we're calling the os stuff while owning the semaphore here.
818 */
819 pThis->pSwitchPort = pSwitchPort;
820 rc = vboxNetFltOsConnectIt(pThis);
821 if (RT_SUCCESS(rc))
822 {
823 vboxNetFltSetState(pThis, kVBoxNetFltInsState_Connected);
824#ifdef VBOXNETFLT_STATIC_CONFIG
825 *ppIfPort = &pThis->MyPort;
826#endif
827 }
828 else
829 pThis->pSwitchPort = NULL;
830
831 Assert(!pThis->fActive);
832 return rc;
833}
834
835
836/**
837 * Creates a new instance.
838 *
839 * The new instance will be in the suspended state in a dynamic config and in
840 * the inactive in a static one.
841 *
842 * Called without owning the lock, but will request is several times.
843 *
844 * @returns VBox status code.
845 * @param pGlobals The globals.
846 * @param pszName The instance name.
847 * @param pSwitchPort The port on the switch that we're connected with (dynamic only).
848 * @param ppIfPort Where to store the pointer to our port interface (dynamic only).
849 * @param fNoPromisc Do not attempt going into promiscuous mode.
850 */
851static int vboxNetFltNewInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort, bool fNoPromisc
852#ifdef VBOXNETFLT_STATIC_CONFIG
853 , void * pContext
854#endif
855 )
856{
857 /*
858 * Allocate and initialize a new instance before requesting the mutex.
859 */
860 int rc;
861 size_t const cchName = strlen(pszName);
862 PVBOXNETFLTINS pNew = (PVBOXNETFLTINS)RTMemAllocZ(RT_OFFSETOF(VBOXNETFLTINS, szName[cchName + 1]));
863 if (!pNew)
864 return VERR_INTNET_FLT_IF_FAILED;
865 pNew->pNext = NULL;
866 pNew->MyPort.u32Version = INTNETTRUNKIFPORT_VERSION;
867 pNew->MyPort.pfnRetain = NETFLT_CALLBACK(vboxNetFltPortRetain);
868 pNew->MyPort.pfnRelease = NETFLT_CALLBACK(vboxNetFltPortRelease);
869 pNew->MyPort.pfnDisconnectAndRelease= NETFLT_CALLBACK(vboxNetFltPortDisconnectAndRelease);
870 pNew->MyPort.pfnSetActive = NETFLT_CALLBACK(vboxNetFltPortSetActive);
871 pNew->MyPort.pfnWaitForIdle = NETFLT_CALLBACK(vboxNetFltPortWaitForIdle);
872 pNew->MyPort.pfnGetMacAddress = NETFLT_CALLBACK(vboxNetFltPortGetMacAddress);
873 pNew->MyPort.pfnIsHostMac = NETFLT_CALLBACK(vboxNetFltPortIsHostMac);
874 pNew->MyPort.pfnIsPromiscuous = NETFLT_CALLBACK(vboxNetFltPortIsPromiscuous);
875 pNew->MyPort.pfnXmit = NETFLT_CALLBACK(vboxNetFltPortXmit);
876 pNew->MyPort.u32VersionEnd = INTNETTRUNKIFPORT_VERSION;
877 pNew->pSwitchPort = NULL;
878 pNew->pGlobals = pGlobals;
879 pNew->hSpinlock = NIL_RTSPINLOCK;
880 pNew->enmState = kVBoxNetFltInsState_Initializing;
881 pNew->fActive = false;
882 pNew->fDisconnectedFromHost = false;
883 pNew->fRediscoveryPending = false;
884 pNew->fDisablePromiscuous = fNoPromisc;
885 pNew->NanoTSLastRediscovery = INT64_MAX;
886 pNew->cRefs = 1;
887 pNew->cBusy = 0;
888 pNew->hEventIdle = NIL_RTSEMEVENT;
889 memcpy(pNew->szName, pszName, cchName + 1);
890
891 rc = RTSpinlockCreate(&pNew->hSpinlock);
892 if (RT_SUCCESS(rc))
893 {
894 rc = RTSemEventCreate(&pNew->hEventIdle);
895 if (RT_SUCCESS(rc))
896 {
897 rc = vboxNetFltOsPreInitInstance(pNew);
898 if (RT_SUCCESS(rc))
899 {
900 /*
901 * Insert the instance into the chain, checking for
902 * duplicates first of course (race).
903 */
904 rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
905 if (RT_SUCCESS(rc))
906 {
907 if (!vboxNetFltFindInstanceLocked(pGlobals, pszName))
908 {
909 pNew->pNext = pGlobals->pInstanceHead;
910 pGlobals->pInstanceHead = pNew;
911 RTSemFastMutexRelease(pGlobals->hFastMtx);
912
913 /*
914 * Call the OS specific initialization code.
915 */
916 rc = vboxNetFltOsInitInstance(pNew
917#ifdef VBOXNETFLT_STATIC_CONFIG
918 , pContext
919#endif
920 );
921 RTSemFastMutexRequest(pGlobals->hFastMtx);
922 if (RT_SUCCESS(rc))
923 {
924#ifdef VBOXNETFLT_STATIC_CONFIG
925 pNew->enmState = kVBoxNetFltInsState_Unconnected;
926 Assert(!pSwitchPort);
927 *ppIfPort = &pNew->MyPort;
928 RTSemFastMutexRelease(pGlobals->hFastMtx);
929 return rc;
930
931#else
932 /*
933 * Connect it as well, the OS specific bits has to be done outside
934 * the lock as they may call back to into intnet.
935 */
936 rc = vboxNetFltConnectIt(pNew, pSwitchPort, ppIfPort);
937 if (RT_SUCCESS(rc))
938 {
939 RTSemFastMutexRelease(pGlobals->hFastMtx);
940 *ppIfPort = &pNew->MyPort;
941 return rc;
942 }
943
944 /* Bail out (failed). */
945 vboxNetFltOsDeleteInstance(pNew);
946#endif
947 }
948 vboxNetFltUnlinkLocked(pGlobals, pNew);
949 }
950 else
951 rc = VERR_INTNET_FLT_IF_BUSY;
952 RTSemFastMutexRelease(pGlobals->hFastMtx);
953 }
954 }
955 RTSemEventDestroy(pNew->hEventIdle);
956 }
957 RTSpinlockDestroy(pNew->hSpinlock);
958 }
959
960 RTMemFree(pNew);
961 return rc;
962}
963
964#ifdef VBOXNETFLT_STATIC_CONFIG
965
966/**
967 * searches for the NetFlt instance by its name and creates the new one if not found
968 *
969 * @return VINF_SUCCESS if new instance was created, VINF_ALREADY_INITIALIZED if an instanmce already exists,
970 * VERR_xxx in case of a failure
971 */
972DECLHIDDEN(int) vboxNetFltSearchCreateInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName, PVBOXNETFLTINS *ppInstance, void * pContext)
973{
974 PINTNETTRUNKIFPORT pIfPort;
975 int rc;
976
977 rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
978 AssertRCReturn(rc, rc);
979
980 *ppInstance = vboxNetFltFindInstanceLocked(pGlobals, pszName);
981 if(*ppInstance)
982 {
983 VBOXNETFTLINSSTATE enmState = vboxNetFltGetState(*ppInstance);
984 if(enmState != kVBoxNetFltInsState_Destroying && enmState != kVBoxNetFltInsState_Destroyed)
985 {
986 vboxNetFltRetain(*ppInstance, false);
987 RTSemFastMutexRelease(pGlobals->hFastMtx);
988 return VINF_ALREADY_INITIALIZED;
989 }
990
991 /*wait for the instance to be removed from the list */
992
993 *ppInstance = NULL;
994
995 do
996 {
997 RTSemFastMutexRelease(pGlobals->hFastMtx);
998
999 RTSemEventWait(pGlobals->hTimerEvent, 2);
1000
1001 rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
1002 AssertRCReturn(rc, rc);
1003 } while(vboxNetFltFindInstanceLocked(pGlobals, pszName));
1004 }
1005
1006 RTSemFastMutexRelease(pGlobals->hFastMtx);
1007
1008 rc = vboxNetFltNewInstance(pGlobals, pszName, NULL, &pIfPort, false, pContext);
1009 if(RT_SUCCESS(rc))
1010 *ppInstance = IFPORT_2_VBOXNETFLTINS(pIfPort);
1011 else
1012 *ppInstance = NULL;
1013
1014 return rc;
1015}
1016
1017#endif
1018
1019/**
1020 * @copydoc INTNETTRUNKFACTORY::pfnCreateAndConnect
1021 */
1022static DECLCALLBACK(int) vboxNetFltFactoryCreateAndConnect(PINTNETTRUNKFACTORY pIfFactory, const char *pszName,
1023 PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort, bool fNoPromisc)
1024{
1025 PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, TrunkFactory));
1026 PVBOXNETFLTINS pCur;
1027 int rc;
1028
1029 LogFlow(("vboxNetFltFactoryCreateAndConnect: pszName=%p:{%s}\n", pszName, pszName));
1030 Assert(pGlobals->cFactoryRefs > 0);
1031
1032 /*
1033 * Static: Find instance, check if busy, connect if not.
1034 * Dynamic: Check for duplicate / busy interface instance.
1035 */
1036 rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
1037 AssertRCReturn(rc, rc);
1038
1039 pCur = vboxNetFltFindInstanceLocked(pGlobals, pszName);
1040 if (pCur)
1041 {
1042#ifdef VBOXNETFLT_STATIC_CONFIG
1043 switch (vboxNetFltGetState(pCur))
1044 {
1045 case kVBoxNetFltInsState_Unconnected:
1046 /* instance can be destroyed when it is neither used by the IntNet nor by the ndis filter driver mechanism
1047 * (i.e. the driver is not bound to the specified adapter)*/
1048 /* Prevent setting promiscuous mode for WiFi adapters. */
1049 pCur->fDisablePromiscuous = fNoPromisc;
1050 LogAleksey(("fNoPromisc=%d\n", pCur->fDisablePromiscuous));
1051 vboxNetFltRetain(pCur, false /* fBusy */); /** @todo who releases this on failure? */
1052 rc = vboxNetFltConnectIt(pCur, pSwitchPort, ppIfPort);
1053 break;
1054 case kVBoxNetFltInsState_Connected:
1055 AssertFailed();
1056 rc = VERR_INTNET_FLT_IF_BUSY;
1057 break;
1058 case kVBoxNetFltInsState_Disconnecting:
1059 AssertFailed();
1060 rc = VERR_INTNET_FLT_IF_BUSY;
1061 break;
1062 default:
1063 /** @todo what? */
1064 rc = VERR_INTNET_FLT_IF_BUSY;
1065 break;
1066 }
1067#else
1068 rc = VERR_INTNET_FLT_IF_BUSY;
1069#endif
1070 RTSemFastMutexRelease(pGlobals->hFastMtx);
1071 LogFlow(("vboxNetFltFactoryCreateAndConnect: returns %Rrc\n", rc));
1072 return rc;
1073 }
1074
1075 RTSemFastMutexRelease(pGlobals->hFastMtx);
1076
1077#ifdef VBOXNETFLT_STATIC_CONFIG
1078 rc = VERR_INTNET_FLT_IF_NOT_FOUND;
1079#else
1080 /*
1081 * Dynamically create a new instance.
1082 */
1083 rc = vboxNetFltNewInstance(pGlobals, pszName, pSwitchPort, ppIfPort, fNoPromisc);
1084#endif
1085 LogFlow(("vboxNetFltFactoryCreateAndConnect: returns %Rrc\n", rc));
1086 return rc;
1087}
1088
1089
1090/**
1091 * @copydoc INTNETTRUNKFACTORY::pfnRelease
1092 */
1093static DECLCALLBACK(void) vboxNetFltFactoryRelease(PINTNETTRUNKFACTORY pIfFactory)
1094{
1095 PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, TrunkFactory));
1096
1097 int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
1098 Assert(cRefs >= 0); NOREF(cRefs);
1099 LogFlow(("vboxNetFltFactoryRelease: cRefs=%d (new)\n", cRefs));
1100}
1101
1102
1103/**
1104 * Implements the SUPDRV component factor interface query method.
1105 *
1106 * @returns Pointer to an interface. NULL if not supported.
1107 *
1108 * @param pSupDrvFactory Pointer to the componet factory registration structure.
1109 * @param pSession The session - unused.
1110 * @param pszInterfaceUuid The factory interface id.
1111 */
1112static DECLCALLBACK(void *) vboxNetFltQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
1113{
1114 PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, SupDrvFactory));
1115
1116 /*
1117 * Convert the UUID strings and compare them.
1118 */
1119 RTUUID UuidReq;
1120 int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
1121 if (RT_SUCCESS(rc))
1122 {
1123 if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_UUID_STR))
1124 {
1125 ASMAtomicIncS32(&pGlobals->cFactoryRefs);
1126 return &pGlobals->TrunkFactory;
1127 }
1128#ifdef LOG_ENABLED
1129 /* log legacy queries */
1130 /* else if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_V1_UUID_STR))
1131 Log(("VBoxNetFlt: V1 factory query\n"));
1132 */
1133 else
1134 Log(("VBoxNetFlt: unknown factory interface query (%s)\n", pszInterfaceUuid));
1135#endif
1136 }
1137 else
1138 Log(("VBoxNetFlt: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
1139
1140 return NULL;
1141}
1142
1143
1144/**
1145 * Checks whether the VBoxNetFlt wossname can be unloaded.
1146 *
1147 * This will return false if someone is currently using the module.
1148 *
1149 * @returns true if it's relatively safe to unload it, otherwise false.
1150 * @param pGlobals Pointer to the globals.
1151 */
1152DECLHIDDEN(bool) vboxNetFltCanUnload(PVBOXNETFLTGLOBALS pGlobals)
1153{
1154 int rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
1155 bool fRc = !pGlobals->pInstanceHead
1156 && pGlobals->cFactoryRefs <= 0;
1157 RTSemFastMutexRelease(pGlobals->hFastMtx);
1158 AssertRC(rc);
1159 return fRc;
1160}
1161
1162/**
1163 * tries to deinitialize Idc
1164 * we separate the globals settings "base" which is actually
1165 * "general" globals settings except for Idc, and idc.
1166 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
1167 * thus it's not possible to make idc initialization from the driver startup routine for it,
1168 * though the "base is still needed for the driver to functions".
1169 * @param pGlobals
1170 * @return VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
1171 */
1172DECLHIDDEN(int) vboxNetFltTryDeleteIdc(PVBOXNETFLTGLOBALS pGlobals)
1173{
1174 int rc;
1175
1176 Assert(pGlobals->hFastMtx != NIL_RTSEMFASTMUTEX);
1177
1178 /*
1179 * Check before trying to deregister the factory.
1180 */
1181 if (!vboxNetFltCanUnload(pGlobals))
1182 return VERR_WRONG_ORDER;
1183
1184 /*
1185 * Disconnect from SUPDRV and check that nobody raced us,
1186 * reconnect if that should happen.
1187 */
1188 rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
1189 AssertRC(rc);
1190 if (!vboxNetFltCanUnload(pGlobals))
1191 {
1192 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
1193 AssertRC(rc);
1194 return VERR_WRONG_ORDER;
1195 }
1196
1197 SUPR0IdcClose(&pGlobals->SupDrvIDC);
1198
1199 return rc;
1200}
1201
1202/**
1203 * performs "base" globals deinitialization
1204 * we separate the globals settings "base" which is actually
1205 * "general" globals settings except for Idc, and idc.
1206 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
1207 * thus it's not possible to make idc initialization from the driver startup routine for it,
1208 * though the "base is still needed for the driver to functions".
1209 * @param pGlobals
1210 * @return none
1211 */
1212DECLHIDDEN(void) vboxNetFltDeleteGlobalsBase(PVBOXNETFLTGLOBALS pGlobals)
1213{
1214 /*
1215 * Release resources.
1216 */
1217 RTSemFastMutexDestroy(pGlobals->hFastMtx);
1218 pGlobals->hFastMtx = NIL_RTSEMFASTMUTEX;
1219
1220#ifdef VBOXNETFLT_STATIC_CONFIG
1221 RTSemEventDestroy(pGlobals->hTimerEvent);
1222 pGlobals->hTimerEvent = NIL_RTSEMEVENT;
1223#endif
1224
1225}
1226
1227/**
1228 * Called by the native part when the OS wants the driver to unload.
1229 *
1230 * @returns VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
1231 *
1232 * @param pGlobals Pointer to the globals.
1233 */
1234DECLHIDDEN(int) vboxNetFltTryDeleteGlobals(PVBOXNETFLTGLOBALS pGlobals)
1235{
1236 int rc = vboxNetFltTryDeleteIdc(pGlobals);
1237 if(RT_SUCCESS(rc))
1238 {
1239 vboxNetFltDeleteGlobalsBase(pGlobals);
1240 }
1241 return rc;
1242}
1243
1244/**
1245 * performs the "base" globals initialization
1246 * we separate the globals initialization to globals "base" initialization which is actually
1247 * "general" globals initialization except for Idc not being initialized, and idc initialization.
1248 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
1249 * thus it's not possible to make idc initialization from the driver startup routine for it.
1250 *
1251 * @returns VBox status code.
1252 * @param pGlobals Pointer to the globals. */
1253DECLHIDDEN(int) vboxNetFltInitGlobalsBase(PVBOXNETFLTGLOBALS pGlobals)
1254{
1255 /*
1256 * Initialize the common portions of the structure.
1257 */
1258 int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx);
1259 if (RT_SUCCESS(rc))
1260 {
1261#ifdef VBOXNETFLT_STATIC_CONFIG
1262 rc = RTSemEventCreate(&pGlobals->hTimerEvent);
1263 if (RT_SUCCESS(rc))
1264 {
1265#endif
1266 pGlobals->pInstanceHead = NULL;
1267
1268 pGlobals->TrunkFactory.pfnRelease = vboxNetFltFactoryRelease;
1269 pGlobals->TrunkFactory.pfnCreateAndConnect = vboxNetFltFactoryCreateAndConnect;
1270
1271 strcpy(pGlobals->SupDrvFactory.szName, "VBoxNetFlt");
1272 pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxNetFltQueryFactoryInterface;
1273
1274 return rc;
1275#ifdef VBOXNETFLT_STATIC_CONFIG
1276 }
1277 RTSemFastMutexDestroy(pGlobals->hFastMtx);
1278#endif
1279 }
1280
1281 return rc;
1282}
1283
1284/**
1285 * performs the Idc initialization
1286 * we separate the globals initialization to globals "base" initialization which is actually
1287 * "general" globals initialization except for Idc not being initialized, and idc initialization.
1288 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
1289 * thus it's not possible to make idc initialization from the driver startup routine for it.
1290 *
1291 * @returns VBox status code.
1292 * @param pGlobals Pointer to the globals. */
1293DECLHIDDEN(int) vboxNetFltInitIdc(PVBOXNETFLTGLOBALS pGlobals)
1294{
1295 int rc;
1296 /*
1297 * Establish a connection to SUPDRV and register our component factory.
1298 */
1299 rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
1300 if (RT_SUCCESS(rc))
1301 {
1302 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
1303 if (RT_SUCCESS(rc))
1304 {
1305 Log(("VBoxNetFlt: pSession=%p\n", SUPR0IdcGetSession(&pGlobals->SupDrvIDC)));
1306 return rc;
1307 }
1308
1309 /* bail out. */
1310 LogRel(("VBoxNetFlt: Failed to register component factory, rc=%Rrc\n", rc));
1311 SUPR0IdcClose(&pGlobals->SupDrvIDC);
1312 }
1313
1314 return rc;
1315}
1316
1317/**
1318 * Called by the native driver/kext module initialization routine.
1319 *
1320 * It will initialize the common parts of the globals, assuming the caller
1321 * has already taken care of the OS specific bits.
1322 *
1323 * @returns VBox status code.
1324 * @param pGlobals Pointer to the globals.
1325 */
1326DECLHIDDEN(int) vboxNetFltInitGlobals(PVBOXNETFLTGLOBALS pGlobals)
1327{
1328 /*
1329 * Initialize the common portions of the structure.
1330 */
1331 int rc = vboxNetFltInitGlobalsBase(pGlobals);
1332 if (RT_SUCCESS(rc))
1333 {
1334 rc = vboxNetFltInitIdc(pGlobals);
1335 if (RT_SUCCESS(rc))
1336 {
1337 return rc;
1338 }
1339
1340 /* bail out. */
1341 vboxNetFltDeleteGlobalsBase(pGlobals);
1342 }
1343
1344 return rc;
1345}
1346
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette