VirtualBox

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

最後變更 在這個檔案從14852是 14100,由 vboxsync 提交於 16 年 前

win/NetFlt: some VBOXNETFLT_STATIC_CONFIG-related commenting

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

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