VirtualBox

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

Last change on this file since 11935 was 11935, checked in by vboxsync, 17 years ago

VBoxNetFlt for Darwin and Solaris to OSE

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

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