VirtualBox

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

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

Solaris/VBoxNetFlt: Teardown time race fixes.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id
檔案大小: 39.3 KB
 
1/* $Id: VBoxNetFlt.c 13769 2008-11-03 19:13:51Z 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#ifdef VBOXNETFLT_STATIC_CONFIG
223# error "The static setup needs a full check up wrt assumptions and incomplete code."
224#endif
225
226
227/*******************************************************************************
228* Defined Constants And Macros *
229*******************************************************************************/
230#define IFPORT_2_VBOXNETFLTINS(pIfPort) \
231 ( (PVBOXNETFLTINS)((uint8_t *)pIfPort - RT_OFFSETOF(VBOXNETFLTINS, MyPort)) )
232
233
234/**
235 * Finds a instance by its name, the caller does the locking.
236 *
237 *
238 * @returns Pointer to the instance by the given name. NULL if not found.
239 * @param pGlobals The globals.
240 * @param pszName The name of the instance.
241 */
242static PVBOXNETFLTINS vboxNetFltFindInstanceLocked(PVBOXNETFLTGLOBALS pGlobals, const char *pszName)
243{
244 PVBOXNETFLTINS pCur;
245 for (pCur = pGlobals->pInstanceHead; pCur; pCur = pCur->pNext)
246 if (!strcmp(pszName, pCur->szName))
247 return pCur;
248 return NULL;
249}
250
251
252/**
253 * Finds a instance by its name, will request the mutex.
254 *
255 * @returns Pointer to the instance by the given name. NULL if not found.
256 * @param pGlobals The globals.
257 * @param pszName The name of the instance.
258 */
259DECLHIDDEN(PVBOXNETFLTINS) vboxNetFltFindInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName)
260{
261 PVBOXNETFLTINS pRet;
262 int rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
263 AssertRCReturn(rc, NULL);
264
265 pRet = vboxNetFltFindInstanceLocked(pGlobals, pszName);
266
267 rc = RTSemFastMutexRelease(pGlobals->hFastMtx);
268 AssertRC(rc);
269 return pRet;
270}
271
272
273/**
274 * Unlinks an instance from the chain.
275 *
276 * @param pGlobals The globals.
277 * @param pToUnlink The instance to unlink.
278 */
279static void vboxNetFltUnlinkLocked(PVBOXNETFLTGLOBALS pGlobals, PVBOXNETFLTINS pToUnlink)
280{
281 if (pGlobals->pInstanceHead == pToUnlink)
282 pGlobals->pInstanceHead = pToUnlink->pNext;
283 else
284 {
285 PVBOXNETFLTINS pCur;
286 for (pCur = pGlobals->pInstanceHead; pCur; pCur = pCur->pNext)
287 if (pCur->pNext == pToUnlink)
288 {
289 pCur->pNext = pToUnlink->pNext;
290 break;
291 }
292 Assert(pCur);
293 }
294 pToUnlink->pNext = NULL;
295}
296
297
298AssertCompileMemberSize(VBOXNETFLTINS, enmState, sizeof(uint32_t));
299
300/**
301 * Sets the enmState member atomically.
302 *
303 * Used for all updates.
304 *
305 * @param pThis The instance.
306 * @param enmNewState The new value.
307 */
308DECLINLINE(void) vboxNetFltSetState(PVBOXNETFLTINS pThis, VBOXNETFTLINSSTATE enmNewState)
309{
310 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, enmNewState);
311}
312
313
314/**
315 * Gets the enmState member atomically.
316 *
317 * Used for all reads.
318 *
319 * @returns The enmState value.
320 * @param pThis The instance.
321 */
322DECLINLINE(VBOXNETFTLINSSTATE) vboxNetFltGetState(PVBOXNETFLTINS pThis)
323{
324 return (VBOXNETFTLINSSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState);
325}
326
327
328/**
329 * Performs interface rediscovery if it was disconnected from the host.
330 *
331 * @returns true if successfully rediscovered and connected, false if not.
332 * @param pThis The instance.
333 */
334static bool vboxNetFltMaybeRediscovered(PVBOXNETFLTINS pThis)
335{
336 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
337 uint64_t Now = RTTimeNanoTS();
338 bool fRediscovered;
339 bool fDoIt;
340
341 /*
342 * Rediscovered already? Time to try again?
343 */
344 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
345
346 fRediscovered = !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
347 fDoIt = !fRediscovered
348 && !ASMAtomicUoReadBool(&pThis->fRediscoveryPending)
349 && Now - ASMAtomicUoReadU64(&pThis->NanoTSLastRediscovery) > UINT64_C(5000000000); /* 5 sec */
350 if (fDoIt)
351 ASMAtomicWriteBool(&pThis->fRediscoveryPending, true);
352
353 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
354
355 /*
356 * Call the OS specific code to do the job.
357 * Update the state when the call returns, that is everything except for
358 * the fDisconnectedFromHost flag which the OS specific code shall set.
359 */
360 if (fDoIt)
361 {
362 fRediscovered = vboxNetFltOsMaybeRediscovered(pThis);
363
364 Assert(!fRediscovered || !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost));
365
366 ASMAtomicUoWriteU64(&pThis->NanoTSLastRediscovery, RTTimeNanoTS());
367 ASMAtomicWriteBool(&pThis->fRediscoveryPending, false);
368
369 if (fRediscovered)
370 vboxNetFltPortOsSetActive(pThis, pThis->fActive);
371 }
372
373 return fRediscovered;
374}
375
376#ifdef RT_WITH_W64_UNWIND_HACK
377# if defined(RT_OS_WINDOWS) && defined(RT_ARCH_AMD64)
378# define NETFLT_DECL_CALLBACK(type) DECLASM(DECLHIDDEN(type))
379# define NETFLT_CALLBACK(_n) netfltNtWrap##_n
380
381NETFLT_DECL_CALLBACK(int) NETFLT_CALLBACK(vboxNetFltPortXmit)(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst);
382NETFLT_DECL_CALLBACK(bool) NETFLT_CALLBACK(vboxNetFltPortIsPromiscuous)(PINTNETTRUNKIFPORT pIfPort);
383NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortGetMacAddress)(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac);
384NETFLT_DECL_CALLBACK(bool) NETFLT_CALLBACK(vboxNetFltPortIsHostMac)(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac);
385NETFLT_DECL_CALLBACK(int) NETFLT_CALLBACK(vboxNetFltPortWaitForIdle)(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies);
386NETFLT_DECL_CALLBACK(bool) NETFLT_CALLBACK(vboxNetFltPortSetActive)(PINTNETTRUNKIFPORT pIfPort, bool fActive);
387NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortDisconnectAndRelease)(PINTNETTRUNKIFPORT pIfPort);
388NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortRetain)(PINTNETTRUNKIFPORT pIfPort);
389NETFLT_DECL_CALLBACK(void) NETFLT_CALLBACK(vboxNetFltPortRelease)(PINTNETTRUNKIFPORT pIfPort);
390
391# else
392# error "UNSUPPORTED (RT_WITH_W64_UNWIND_HACK)"
393# endif
394#else
395# define NETFLT_DECL_CALLBACK(type) static DECLCALLBACK(type)
396# define NETFLT_CALLBACK(_n) _n
397#endif
398
399/**
400 * @copydoc INTNETTRUNKIFPORT::pfnXmit
401 */
402NETFLT_DECL_CALLBACK(int) vboxNetFltPortXmit(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst)
403{
404 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
405 int rc;
406
407 /*
408 * Input validation.
409 */
410 AssertPtr(pThis);
411 AssertPtr(pSG);
412 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
413 AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, VERR_INVALID_STATE);
414 Assert(pThis->fActive);
415
416 /*
417 * Do a busy retain and then make sure we're connected to the interface
418 * before invoking the OS specific code.
419 */
420 vboxNetFltRetain(pThis, true /* fBusy */);
421 if ( !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost)
422 || vboxNetFltMaybeRediscovered(pThis))
423 rc = vboxNetFltPortOsXmit(pThis, pSG, fDst);
424 vboxNetFltRelease(pThis, true /* fBusy */);
425
426 return rc;
427}
428
429
430/**
431 * @copydoc INTNETTRUNKIFPORT::pfnIsPromiscuous
432 */
433NETFLT_DECL_CALLBACK(bool) vboxNetFltPortIsPromiscuous(PINTNETTRUNKIFPORT pIfPort)
434{
435 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
436
437 /*
438 * Input validation.
439 */
440 AssertPtr(pThis);
441 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
442 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
443 Assert(pThis->fActive);
444
445 /*
446 * Ask the OS specific code.
447 */
448 return vboxNetFltPortOsIsPromiscuous(pThis);
449}
450
451
452/**
453 * @copydoc INTNETTRUNKIFPORT::pfnGetMacAddress
454 */
455NETFLT_DECL_CALLBACK(void) vboxNetFltPortGetMacAddress(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac)
456{
457 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
458
459 /*
460 * Input validation.
461 */
462 AssertPtr(pThis);
463 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
464 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
465 Assert(pThis->fActive);
466
467 /*
468 * Forward the question to the OS specific code.
469 */
470 vboxNetFltPortOsGetMacAddress(pThis, pMac);
471}
472
473
474/**
475 * @copydoc INTNETTRUNKIFPORT::pfnIsHostMac
476 */
477NETFLT_DECL_CALLBACK(bool) vboxNetFltPortIsHostMac(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac)
478{
479 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
480
481 /*
482 * Input validation.
483 */
484 AssertPtr(pThis);
485 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
486 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
487 Assert(pThis->fActive);
488
489 /*
490 * Ask the OS specific code.
491 */
492 return vboxNetFltPortOsIsHostMac(pThis, pMac);
493}
494
495
496/**
497 * @copydoc INTNETTRUNKIFPORT::pfnWaitForIdle
498 */
499NETFLT_DECL_CALLBACK(int) vboxNetFltPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)
500{
501 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
502 int rc;
503
504 /*
505 * Input validation.
506 */
507 AssertPtr(pThis);
508 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
509 AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, VERR_INVALID_STATE);
510 AssertReturn(!pThis->fActive, VERR_INVALID_STATE);
511
512 /*
513 * Go to sleep on the semaphore after checking the busy count.
514 */
515 vboxNetFltRetain(pThis, false /* fBusy */);
516
517 rc = VINF_SUCCESS;
518 while (pThis->cBusy && RT_SUCCESS(rc))
519 rc = RTSemEventWait(pThis->hEventIdle, cMillies); /** @todo make interruptible? */
520
521 vboxNetFltRelease(pThis, false /* fBusy */);
522
523 return rc;
524}
525
526
527/**
528 * @copydoc INTNETTRUNKIFPORT::pfnSetActive
529 */
530NETFLT_DECL_CALLBACK(bool) vboxNetFltPortSetActive(PINTNETTRUNKIFPORT pIfPort, bool fActive)
531{
532 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
533
534 /*
535 * Input validation.
536 */
537 AssertPtr(pThis);
538 AssertPtr(pThis->pGlobals);
539 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
540 AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, false);
541
542 /*
543 * We're assuming that the caller is serializing the calls, so we don't
544 * have to be extremely careful here. Just update first and then call
545 * the OS specific code, the update must be serialized for various reasons.
546 */
547 if (ASMAtomicReadBool(&pThis->fActive) != fActive)
548 {
549 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
550 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
551 ASMAtomicWriteBool(&pThis->fActive, fActive);
552 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
553
554 vboxNetFltPortOsSetActive(pThis, fActive);
555 }
556 else
557 fActive = !fActive;
558 return !fActive;
559}
560
561
562/**
563 * @copydoc INTNETTRUNKIFPORT::pfnDisconnectAndRelease
564 */
565NETFLT_DECL_CALLBACK(void) vboxNetFltPortDisconnectAndRelease(PINTNETTRUNKIFPORT pIfPort)
566{
567 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
568 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
569
570 /*
571 * Serious paranoia.
572 */
573 AssertPtr(pThis);
574 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
575 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
576 AssertPtr(pThis->pGlobals);
577 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
578 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
579 Assert(pThis->szName[0]);
580
581 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
582 Assert(!pThis->fActive);
583 Assert(!pThis->fRediscoveryPending);
584 Assert(!pThis->cBusy);
585
586 /*
587 * Disconnect and release it.
588 */
589 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
590 vboxNetFltSetState(pThis, kVBoxNetFltInsState_Disconnecting);
591 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
592
593 vboxNetFltOsDisconnectIt(pThis);
594 pThis->pSwitchPort = NULL;
595
596 vboxNetFltRelease(pThis, false /* fBusy */);
597}
598
599
600/**
601 * Destroy a device that has been disconnected from the switch.
602 *
603 * @param pThis The instance to be destroyed. This is
604 * no longer valid when this function returns.
605 */
606static void vboxNetFltDestroyInstance(PVBOXNETFLTINS pThis)
607{
608 PVBOXNETFLTGLOBALS pGlobals = pThis->pGlobals;
609 int rc;
610 LogFlow(("vboxNetFltDestroyInstance: pThis=%p (%s)\n", pThis, pThis->szName));
611
612 /*
613 * Validate the state.
614 */
615#ifdef VBOXNETFLT_STATIC_CONFIG
616 Assert( vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Disconnecting
617 || vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Unconnected);
618#else
619 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Disconnecting);
620#endif
621 Assert(!pThis->fActive);
622 Assert(!pThis->fRediscoveryPending);
623 Assert(!pThis->cRefs);
624 Assert(!pThis->cBusy);
625 Assert(!pThis->pSwitchPort);
626
627 /*
628 * Make sure the state is 'disconnecting' and let the OS specific code
629 * do its part of the cleanup outside the mutex.
630 */
631 rc = RTSemFastMutexRequest(pGlobals->hFastMtx); AssertRC(rc);
632 vboxNetFltSetState(pThis, kVBoxNetFltInsState_Disconnecting);
633 RTSemFastMutexRelease(pGlobals->hFastMtx);
634
635 vboxNetFltOsDeleteInstance(pThis);
636
637 /*
638 * Unlink the instance and free up its resources.
639 */
640 rc = RTSemFastMutexRequest(pGlobals->hFastMtx); AssertRC(rc);
641 vboxNetFltSetState(pThis, kVBoxNetFltInsState_Destroyed);
642 vboxNetFltUnlinkLocked(pGlobals, pThis);
643 RTSemFastMutexRelease(pGlobals->hFastMtx);
644
645 RTSemEventDestroy(pThis->hEventIdle);
646 pThis->hEventIdle = NIL_RTSEMEVENT;
647 RTSpinlockDestroy(pThis->hSpinlock);
648 pThis->hSpinlock = NIL_RTSPINLOCK;
649 RTMemFree(pThis);
650}
651
652
653/**
654 * Releases a reference to the specified instance.
655 *
656 * This method will destroy the instance when the count reaches 0.
657 * It will also take care of decrementing the counter and idle wakeup.
658 *
659 * @param pThis The instance.
660 * @param fBusy Whether the busy counter should be decremented too.
661 */
662DECLHIDDEN(void) vboxNetFltRelease(PVBOXNETFLTINS pThis, bool fBusy)
663{
664 uint32_t cRefs;
665
666 /*
667 * Paranoid Android.
668 */
669 AssertPtr(pThis);
670 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
671 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
672 Assert( vboxNetFltGetState(pThis) > kVBoxNetFltInsState_Invalid
673 && vboxNetFltGetState(pThis) < kVBoxNetFltInsState_Destroyed);
674 AssertPtr(pThis->pGlobals);
675 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
676 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
677 Assert(pThis->szName[0]);
678
679 /*
680 * Work the busy counter.
681 */
682 if (fBusy)
683 {
684 cRefs = ASMAtomicDecU32(&pThis->cBusy);
685 if (!cRefs)
686 {
687 int rc = RTSemEventSignal(pThis->hEventIdle);
688 AssertRC(rc);
689 }
690 else
691 Assert(cRefs < UINT32_MAX / 2);
692 }
693
694 /*
695 * The object reference counting.
696 */
697 cRefs = ASMAtomicDecU32(&pThis->cRefs);
698 if (!cRefs)
699 vboxNetFltDestroyInstance(pThis);
700 else
701 Assert(cRefs < UINT32_MAX / 2);
702}
703
704
705/**
706 * @copydoc INTNETTRUNKIFPORT::pfnRetain
707 */
708NETFLT_DECL_CALLBACK(void) vboxNetFltPortRelease(PINTNETTRUNKIFPORT pIfPort)
709{
710 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
711 vboxNetFltRelease(pThis, false /* fBusy */);
712}
713
714
715/**
716 * Retains a reference to the specified instance and a busy reference too.
717 *
718 * @param pThis The instance.
719 * @param fBusy Whether the busy counter should be incremented as well.
720 */
721DECLHIDDEN(void) vboxNetFltRetain(PVBOXNETFLTINS pThis, bool fBusy)
722{
723 uint32_t cRefs;
724
725 /*
726 * Paranoid Android.
727 */
728 AssertPtr(pThis);
729 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
730 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
731 Assert( vboxNetFltGetState(pThis) > kVBoxNetFltInsState_Invalid
732 && vboxNetFltGetState(pThis) < kVBoxNetFltInsState_Destroyed);
733 AssertPtr(pThis->pGlobals);
734 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
735 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
736 Assert(pThis->szName[0]);
737
738 /*
739 * Retain the object.
740 */
741 cRefs = ASMAtomicIncU32(&pThis->cRefs);
742 Assert(cRefs > 1 && cRefs < UINT32_MAX / 2);
743
744 /*
745 * Work the busy counter.
746 */
747 if (fBusy)
748 {
749 cRefs = ASMAtomicIncU32(&pThis->cBusy);
750 Assert(cRefs > 1 && cRefs < UINT32_MAX / 2);
751 }
752
753 NOREF(cRefs);
754}
755
756
757/**
758 * @copydoc INTNETTRUNKIFPORT::pfnRetain
759 */
760NETFLT_DECL_CALLBACK(void) vboxNetFltPortRetain(PINTNETTRUNKIFPORT pIfPort)
761{
762 PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
763 vboxNetFltRetain(pThis, false /* fBusy */);
764}
765
766
767/**
768 * Connects the instance to the specified switch port.
769 *
770 * Called while owning the lock. We're ASSUMING that the internal
771 * networking code is already owning an recursive mutex, so, there
772 * will be no deadlocks when vboxNetFltOsConnectIt calls back into
773 * it for setting preferences.
774 *
775 * @returns VBox status code.
776 * @param pThis The instance.
777 * @param pSwitchPort The port on the internal network 'switch'.
778 * @param ppIfPort Where to return our port interface.
779 */
780static int vboxNetFltConnectIt(PVBOXNETFLTINS pThis, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
781{
782 int rc;
783
784 /*
785 * Validate state.
786 */
787 Assert(!pThis->fActive);
788 Assert(!pThis->fRediscoveryPending);
789 Assert(!pThis->cBusy);
790#ifdef VBOXNETFLT_STATIC_CONFIG
791 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Unconnected);
792#else
793 Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Initializing);
794#endif
795
796 /*
797 * Do the job.
798 * Note that we're calling the os stuff while owning the semaphore here.
799 */
800 pThis->pSwitchPort = pSwitchPort;
801 rc = vboxNetFltOsConnectIt(pThis);
802 if (RT_SUCCESS(rc))
803 vboxNetFltSetState(pThis, kVBoxNetFltInsState_Connected);
804 else
805 pThis->pSwitchPort = NULL;
806
807 Assert(!pThis->fActive);
808 return rc;
809}
810
811
812/**
813 * Creates a new instance.
814 *
815 * The new instance will be in the suspended state in a dynamic config and in
816 * the inactive in a static one.
817 *
818 * Called without owning the lock, but will request is several times.
819 *
820 * @returns VBox status code.
821 * @param pGlobals The globals.
822 * @param pszName The instance name.
823 * @param pSwitchPort The port on the switch that we're connected with (dynamic only).
824 * @param ppIfPort Where to store the pointer to our port interface (dynamic only).
825 */
826static int vboxNetFltNewInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
827{
828 /*
829 * Allocate and initialize a new instance before requesting the mutex.
830 */
831 int rc;
832 size_t const cchName = strlen(pszName);
833 PVBOXNETFLTINS pNew = (PVBOXNETFLTINS)RTMemAllocZ(RT_OFFSETOF(VBOXNETFLTINS, szName[cchName + 1]));
834 if (!pNew)
835 return VERR_INTNET_FLT_IF_FAILED;
836 pNew->pNext = NULL;
837 pNew->MyPort.u32Version = INTNETTRUNKIFPORT_VERSION;
838 pNew->MyPort.pfnRetain = NETFLT_CALLBACK(vboxNetFltPortRetain);
839 pNew->MyPort.pfnRelease = NETFLT_CALLBACK(vboxNetFltPortRelease);
840 pNew->MyPort.pfnDisconnectAndRelease= NETFLT_CALLBACK(vboxNetFltPortDisconnectAndRelease);
841 pNew->MyPort.pfnSetActive = NETFLT_CALLBACK(vboxNetFltPortSetActive);
842 pNew->MyPort.pfnWaitForIdle = NETFLT_CALLBACK(vboxNetFltPortWaitForIdle);
843 pNew->MyPort.pfnGetMacAddress = NETFLT_CALLBACK(vboxNetFltPortGetMacAddress);
844 pNew->MyPort.pfnIsHostMac = NETFLT_CALLBACK(vboxNetFltPortIsHostMac);
845 pNew->MyPort.pfnIsPromiscuous = NETFLT_CALLBACK(vboxNetFltPortIsPromiscuous);
846 pNew->MyPort.pfnXmit = NETFLT_CALLBACK(vboxNetFltPortXmit);
847 pNew->MyPort.u32VersionEnd = INTNETTRUNKIFPORT_VERSION;
848 pNew->pSwitchPort = NULL;
849 pNew->pGlobals = pGlobals;
850 pNew->hSpinlock = NIL_RTSPINLOCK;
851 pNew->enmState = kVBoxNetFltInsState_Initializing;
852 pNew->fActive = false;
853 pNew->fDisconnectedFromHost = false;
854 pNew->fRediscoveryPending = false;
855 pNew->NanoTSLastRediscovery = INT64_MAX;
856 pNew->cRefs = 1;
857 pNew->cBusy = 0;
858 pNew->hEventIdle = NIL_RTSEMEVENT;
859 memcpy(pNew->szName, pszName, cchName + 1);
860
861 rc = RTSpinlockCreate(&pNew->hSpinlock);
862 if (RT_SUCCESS(rc))
863 {
864 rc = RTSemEventCreate(&pNew->hEventIdle);
865 if (RT_SUCCESS(rc))
866 {
867 rc = vboxNetFltOsPreInitInstance(pNew);
868 if (RT_SUCCESS(rc))
869 {
870 /*
871 * Insert the instance into the chain, checking for
872 * duplicates first of course (race).
873 */
874 rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
875 if (RT_SUCCESS(rc))
876 {
877 if (!vboxNetFltFindInstanceLocked(pGlobals, pszName))
878 {
879 pNew->pNext = pGlobals->pInstanceHead;
880 pGlobals->pInstanceHead = pNew;
881 RTSemFastMutexRelease(pGlobals->hFastMtx);
882
883 /*
884 * Call the OS specific initialization code.
885 */
886 rc = vboxNetFltOsInitInstance(pNew);
887 RTSemFastMutexRequest(pGlobals->hFastMtx);
888 if (RT_SUCCESS(rc))
889 {
890#ifdef VBOXNETFLT_STATIC_CONFIG
891 pNew->enmState = kVBoxNetFltInsState_Inactive;
892 Assert(!pSwitchPort); Assert(!ppIfPort);
893 RTSemFastMutexRelease(pGlobals->hFastMtx);
894 return rc;
895
896#else
897 /*
898 * Connect it as well, the OS specific bits has to be done outside
899 * the lock as they may call back to into intnet.
900 */
901 rc = vboxNetFltConnectIt(pNew, pSwitchPort, ppIfPort);
902 if (RT_SUCCESS(rc))
903 {
904 RTSemFastMutexRelease(pGlobals->hFastMtx);
905 *ppIfPort = &pNew->MyPort;
906 return rc;
907 }
908
909 /* Bail out (failed). */
910 vboxNetFltOsDeleteInstance(pNew);
911#endif
912 }
913 vboxNetFltUnlinkLocked(pGlobals, pNew);
914 }
915 else
916 rc = VERR_INTNET_FLT_IF_BUSY;
917 RTSemFastMutexRelease(pGlobals->hFastMtx);
918 }
919 }
920 RTSemEventDestroy(pNew->hEventIdle);
921 }
922 RTSpinlockDestroy(pNew->hSpinlock);
923 }
924
925 RTMemFree(pNew);
926 return rc;
927}
928
929
930/**
931 * @copydoc INTNETTRUNKFACTORY::pfnCreateAndConnect
932 */
933static DECLCALLBACK(int) vboxNetFltFactoryCreateAndConnect(PINTNETTRUNKFACTORY pIfFactory, const char *pszName,
934 PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
935{
936 PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, TrunkFactory));
937 PVBOXNETFLTINS pCur;
938 int rc;
939
940 LogFlow(("vboxNetFltFactoryCreateAndConnect: pszName=%p:{%s}\n", pszName, pszName));
941 Assert(pGlobals->cFactoryRefs > 0);
942
943 /*
944 * Static: Find instance, check if busy, connect if not.
945 * Dynamic: Check for duplicate / busy interface instance.
946 */
947 rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
948 AssertRCReturn(rc, rc);
949
950 pCur = vboxNetFltFindInstanceLocked(pGlobals, pszName);
951 if (pCur)
952 {
953 rc = VERR_INTNET_FLT_IF_BUSY;
954#ifdef VBOXNETFLT_STATIC_CONFIG
955 if (vboxNetFltGetState(pCur) == kVBoxNetFltInsState_Unconnected)
956 rc = vboxNetFltConnectIt(pCur, pSwitchPort, ppIfPort);
957#endif
958 RTSemFastMutexRelease(pGlobals->hFastMtx);
959 LogFlow(("vboxNetFltFactoryCreateAndConnect: returns %Rrc\n", rc));
960 return rc;
961 }
962
963 RTSemFastMutexRelease(pGlobals->hFastMtx);
964
965#ifdef VBOXNETFLT_STATIC_CONFIG
966 rc = VERR_INTNET_FLT_IF_NOT_FOUND;
967#else
968 /*
969 * Dynamically create a new instance.
970 */
971 rc = vboxNetFltNewInstance(pGlobals, pszName, pSwitchPort, ppIfPort);
972#endif
973 LogFlow(("vboxNetFltFactoryCreateAndConnect: returns %Rrc\n", rc));
974 return rc;
975}
976
977
978/**
979 * @copydoc INTNETTRUNKFACTORY::pfnRelease
980 */
981static DECLCALLBACK(void) vboxNetFltFactoryRelease(PINTNETTRUNKFACTORY pIfFactory)
982{
983 PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, TrunkFactory));
984
985 int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
986 Assert(cRefs >= 0); NOREF(cRefs);
987 LogFlow(("vboxNetFltFactoryRelease: cRefs=%d (new)\n", cRefs));
988}
989
990
991/**
992 * Implements the SUPDRV component factor interface query method.
993 *
994 * @returns Pointer to an interface. NULL if not supported.
995 *
996 * @param pSupDrvFactory Pointer to the componet factory registration structure.
997 * @param pSession The session - unused.
998 * @param pszInterfaceUuid The factory interface id.
999 */
1000static DECLCALLBACK(void *) vboxNetFltQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
1001{
1002 PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, SupDrvFactory));
1003
1004 /*
1005 * Convert the UUID strings and compare them.
1006 */
1007 RTUUID UuidReq;
1008 int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
1009 if (RT_SUCCESS(rc))
1010 {
1011 if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_UUID_STR))
1012 {
1013 ASMAtomicIncS32(&pGlobals->cFactoryRefs);
1014 return &pGlobals->TrunkFactory;
1015 }
1016#ifdef LOG_ENABLED
1017 /* log legacy queries */
1018 /* else if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_V1_UUID_STR))
1019 Log(("VBoxNetFlt: V1 factory query\n"));
1020 */
1021 else
1022 Log(("VBoxNetFlt: unknown factory interface query (%s)\n", pszInterfaceUuid));
1023#endif
1024 }
1025 else
1026 Log(("VBoxNetFlt: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
1027
1028 return NULL;
1029}
1030
1031
1032/**
1033 * Checks whether the VBoxNetFlt wossname can be unloaded.
1034 *
1035 * This will return false if someone is currently using the module.
1036 *
1037 * @returns true if it's relatively safe to unload it, otherwise false.
1038 * @param pGlobals Pointer to the globals.
1039 */
1040DECLHIDDEN(bool) vboxNetFltCanUnload(PVBOXNETFLTGLOBALS pGlobals)
1041{
1042 int rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
1043 bool fRc = !pGlobals->pInstanceHead
1044 && pGlobals->cFactoryRefs <= 0;
1045 RTSemFastMutexRelease(pGlobals->hFastMtx);
1046 AssertRC(rc);
1047 return fRc;
1048}
1049
1050
1051/**
1052 * Called by the native part when the OS wants the driver to unload.
1053 *
1054 * @returns VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
1055 *
1056 * @param pGlobals Pointer to the globals.
1057 */
1058DECLHIDDEN(int) vboxNetFltTryDeleteGlobals(PVBOXNETFLTGLOBALS pGlobals)
1059{
1060 int rc;
1061 Assert(pGlobals->hFastMtx != NIL_RTSEMFASTMUTEX);
1062
1063 /*
1064 * Check before trying to deregister the factory.
1065 */
1066 if (!vboxNetFltCanUnload(pGlobals))
1067 return VERR_WRONG_ORDER;
1068
1069 /*
1070 * Disconnect from SUPDRV and check that nobody raced us,
1071 * reconnect if that should happen.
1072 */
1073 rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
1074 AssertRC(rc);
1075 if (!vboxNetFltCanUnload(pGlobals))
1076 {
1077 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
1078 AssertRC(rc);
1079 return VERR_WRONG_ORDER;
1080 }
1081
1082 SUPR0IdcClose(&pGlobals->SupDrvIDC);
1083
1084 /*
1085 * Release resources.
1086 */
1087 RTSemFastMutexDestroy(pGlobals->hFastMtx);
1088 pGlobals->hFastMtx = NIL_RTSEMFASTMUTEX;
1089
1090 return VINF_SUCCESS;
1091}
1092
1093
1094/**
1095 * Called by the native driver/kext module initialization routine.
1096 *
1097 * It will initialize the common parts of the globals, assuming the caller
1098 * has already taken care of the OS specific bits.
1099 *
1100 * @returns VBox status code.
1101 * @param pGlobals Pointer to the globals.
1102 */
1103DECLHIDDEN(int) vboxNetFltInitGlobals(PVBOXNETFLTGLOBALS pGlobals)
1104{
1105 /*
1106 * Initialize the common portions of the structure.
1107 */
1108 int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx);
1109 if (RT_SUCCESS(rc))
1110 {
1111 pGlobals->pInstanceHead = NULL;
1112
1113 pGlobals->TrunkFactory.pfnRelease = vboxNetFltFactoryRelease;
1114 pGlobals->TrunkFactory.pfnCreateAndConnect = vboxNetFltFactoryCreateAndConnect;
1115
1116 strcpy(pGlobals->SupDrvFactory.szName, "VBoxNetFlt");
1117 pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxNetFltQueryFactoryInterface;
1118
1119 /*
1120 * Establish a connection to SUPDRV and register our component factory.
1121 */
1122 rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
1123 if (RT_SUCCESS(rc))
1124 {
1125 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
1126 if (RT_SUCCESS(rc))
1127 {
1128 Log(("VBoxNetFlt: pSession=%p\n", SUPR0IdcGetSession(&pGlobals->SupDrvIDC)));
1129 return rc;
1130 }
1131
1132 /* bail out. */
1133 LogRel(("VBoxNetFlt: Failed to register component factory, rc=%Rrc\n", rc));
1134 SUPR0IdcClose(&pGlobals->SupDrvIDC);
1135 }
1136 RTSemFastMutexDestroy(pGlobals->hFastMtx);
1137 pGlobals->hFastMtx = NIL_RTSEMFASTMUTEX;
1138 }
1139
1140 return rc;
1141}
1142
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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