VirtualBox

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

最後變更 在這個檔案從28067是 28067,由 vboxsync 提交於 15 年 前

VBoxNetFlt.c: disabled assertion on fActive in isPromiscuous as we're not necessarily following the locking rules here and risk a race when suspending the VM.

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

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