VirtualBox

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

Last change on this file since 26943 was 25336, checked in by vboxsync, 15 years ago

HostDrivers,SrvIntNetR0,iprt/ntwrap.mac: Removed all the RT_WITH_W64_UNWIND_HACK fun.

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

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