VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdp.c@ 16976

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

#2957: VBoxNetAdp: generic and darwin parts. Not operational yet.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 28.1 KB
 
1/* $Id: VBoxNetAdp.c 16960 2009-02-19 22:13:33Z vboxsync $ */
2/** @file
3 * VBoxNetAdp - Virtual Network Adapter Driver (Host), Common Code.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.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#define LOG_GROUP LOG_GROUP_NET_TAP_DRV
23#include "VBoxNetAdpInternal.h"
24
25#include <VBox/sup.h>
26#include <VBox/log.h>
27#include <VBox/err.h>
28#include <VBox/version.h>
29#include <iprt/assert.h>
30#include <iprt/string.h>
31#include <iprt/spinlock.h>
32#include <iprt/uuid.h>
33
34#include <net/ethernet.h>
35#include <net/if_ether.h>
36#include <net/if_types.h>
37#include <sys/socket.h>
38#include <net/if.h>
39#include <net/if_dl.h>
40#include <sys/errno.h>
41#include <sys/param.h>
42
43/*******************************************************************************
44* Defined Constants And Macros *
45*******************************************************************************/
46#define IFPORT_2_VBOXNETADP(pIfPort) \
47 ( (PVBOXNETADP)((uint8_t *)pIfPort - RT_OFFSETOF(VBOXNETADP, MyPort)) )
48
49
50DECLHIDDEN(void) vboxNetAdpComposeMACAddress(PVBOXNETADP pThis, PRTMAC pMac)
51{
52 /* Note that terminating 0 is included. */
53 memcpy(pMac->au8, "\0vbox", sizeof(pMac->au8));
54 pMac->au8[sizeof(pMac->au8) - 1] += pThis->uUnit;
55}
56
57
58/**
59 * Sets the enmState member atomically.
60 *
61 * Used for all updates.
62 *
63 * @param pThis The instance.
64 * @param enmNewState The new value.
65 */
66DECLINLINE(void) vboxNetAdpSetState(PVBOXNETADP pThis, VBOXNETADPSTATE enmNewState)
67{
68 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, enmNewState);
69}
70
71
72/**
73 * Gets the enmState member atomically.
74 *
75 * Used for all reads.
76 *
77 * @returns The enmState value.
78 * @param pThis The instance.
79 */
80DECLINLINE(VBOXNETADPSTATE) vboxNetAdpGetState(PVBOXNETADP pThis)
81{
82 return (VBOXNETADPSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState);
83}
84
85
86DECLINLINE(bool) vboxNetAdpIsAvailable(PVBOXNETADP pAdp)
87{
88 return pAdp->enmState == kVBoxNetAdpState_Available;
89}
90
91DECLINLINE(bool) vboxNetAdpIsConnected(PVBOXNETADP pAdp)
92{
93 return pAdp->enmState >= kVBoxNetAdpState_Connected;
94}
95
96DECLINLINE(bool) vboxNetAdpIsVoid(PVBOXNETADP pAdp)
97{
98 return pAdp->enmState == kVBoxNetAdpState_Invalid;
99}
100
101DECLINLINE(bool) vboxNetAdpIsValid(PVBOXNETADP pAdp)
102{
103 return pAdp->enmState != kVBoxNetAdpState_Invalid
104 && pAdp->enmState != kVBoxNetAdpState_Transitional;
105}
106
107DECLINLINE(bool) vboxNetAdpIsBusy(PVBOXNETADP pAdp)
108{
109 return pAdp->enmState == kVBoxNetAdpState_Connected;
110}
111
112
113static PVBOXNETADP vboxNetAdpFind(PVBOXNETADPGLOBALS pGlobals, const char *pszName)
114{
115 unsigned i;
116
117 for (i = 0; i < RT_ELEMENTS(pGlobals->aAdapters); i++)
118 {
119 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
120 PVBOXNETADP pThis = &pGlobals->aAdapters[i];
121 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
122 if (vboxNetAdpIsValid(pThis)
123 && !strcmp(pThis->szName, pszName))
124 {
125 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
126 return pThis;
127 }
128 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
129 }
130 return NULL;
131}
132
133/**
134 * Releases a reference to the specified instance.
135 *
136 * @param pThis The instance.
137 * @param fBusy Whether the busy counter should be decremented too.
138 */
139DECLHIDDEN(void) vboxNetAdpRelease(PVBOXNETADP pThis)
140{
141 uint32_t cRefs;
142
143 /*
144 * Paranoid Android.
145 */
146 AssertPtr(pThis);
147 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
148 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
149 Assert(vboxNetAdpGetState(pThis) > kVBoxNetAdpState_Invalid);
150 AssertPtr(pThis->pGlobals);
151 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
152 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
153 Assert(pThis->szName[0]);
154
155 /*
156 * The object reference counting.
157 */
158 cRefs = ASMAtomicDecU32(&pThis->cRefs);
159/* if (!cRefs) */
160/* vboxNetAdpCheckDestroyInstance(pThis); */
161/* else */
162 Assert(cRefs < UINT32_MAX / 2);
163}
164
165/**
166 * Decrements the busy counter and does idle wakeup.
167 *
168 * @param pThis The instance.
169 */
170DECLHIDDEN(void) vboxNetAdpIdle(PVBOXNETADP pThis)
171{
172 uint32_t cBusy;
173
174 /*
175 * Paranoid Android.
176 */
177 AssertPtr(pThis);
178 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
179 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
180 Assert(pThis->enmState == kVBoxNetAdpState_Connected);
181 AssertPtr(pThis->pGlobals);
182 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
183
184 cBusy = ASMAtomicDecU32(&pThis->cBusy);
185 if (!cBusy)
186 {
187 int rc = RTSemEventSignal(pThis->hEventIdle);
188 AssertRC(rc);
189 }
190 else
191 Assert(cBusy < UINT32_MAX / 2);
192}
193
194/**
195 * Retains a reference to the specified instance.
196 *
197 * @param pThis The instance.
198 */
199DECLHIDDEN(void) vboxNetAdpRetain(PVBOXNETADP pThis)
200{
201 uint32_t cRefs;
202
203 /*
204 * Paranoid Android.
205 */
206 AssertPtr(pThis);
207 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
208 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
209 Assert(vboxNetAdpGetState(pThis) > kVBoxNetAdpState_Invalid);
210 AssertPtr(pThis->pGlobals);
211 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
212 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
213 Assert(pThis->szName[0]);
214
215 /*
216 * Retain the object.
217 */
218 cRefs = ASMAtomicIncU32(&pThis->cRefs);
219 Assert(cRefs > 1 && cRefs < UINT32_MAX / 2);
220
221 NOREF(cRefs);
222}
223
224/**
225 * Increments busy counter.
226 *
227 * @param pThis The instance.
228 */
229DECLHIDDEN(void) vboxNetAdpBusy(PVBOXNETADP pThis)
230{
231 uint32_t cBusy;
232
233 /*
234 * Are we vigilant enough?
235 */
236 AssertPtr(pThis);
237 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
238 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
239 Assert(pThis->enmState == kVBoxNetAdpState_Connected);
240 AssertPtr(pThis->pGlobals);
241 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
242 cBusy = ASMAtomicIncU32(&pThis->cBusy);
243 Assert(cBusy > 0 && cBusy < UINT32_MAX / 2);
244
245 NOREF(cBusy);
246}
247
248/**
249 * Checks if receive is possible and increases busy and ref counters if so.
250 *
251 * @param pThis The instance.
252 */
253DECLHIDDEN(bool) vboxNetAdpPrepareToReceive(PVBOXNETADP pThis)
254{
255 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
256 bool fCanReceive = false;
257 /*
258 * Input validation.
259 */
260 AssertPtr(pThis);
261 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
262 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
263 if (pThis->enmState == kVBoxNetAdpState_Active)
264 {
265 fCanReceive = true;
266 vboxNetAdpRetain(pThis);
267 vboxNetAdpBusy(pThis);
268 }
269 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
270
271 return fCanReceive;
272}
273
274/**
275 * Forwards scatter/gather list to internal network and decreases busy and ref counters.
276 *
277 * @param pThis The instance.
278 */
279DECLHIDDEN(void) vboxNetAdpReceive(PVBOXNETADP pThis, PINTNETSG pSG)
280{
281 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
282 /*
283 * Input validation.
284 */
285 AssertPtr(pThis);
286 AssertPtr(pSG);
287 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
288 pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, pSG, INTNETTRUNKDIR_HOST);
289 vboxNetAdpIdle(pThis);
290 vboxNetAdpRelease(pThis);
291}
292
293/**
294 * Decreases busy and ref counters.
295 *
296 * @param pThis The instance.
297 */
298DECLHIDDEN(void) vboxNetAdpCancelReceive(PVBOXNETADP pThis)
299{
300 vboxNetAdpIdle(pThis);
301 vboxNetAdpRelease(pThis);
302}
303
304#ifdef RT_WITH_W64_UNWIND_HACK
305# if defined(RT_OS_WINDOWS) && defined(RT_ARCH_AMD64)
306# define NETADP_DECL_CALLBACK(type) DECLASM(DECLHIDDEN(type))
307# define NETADP_CALLBACK(_n) netfltNtWrap##_n
308
309NETADP_DECL_CALLBACK(int) NETADP_CALLBACK(vboxNetAdpPortXmit)(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst);
310NETADP_DECL_CALLBACK(bool) NETADP_CALLBACK(vboxNetAdpPortIsPromiscuous)(PINTNETTRUNKIFPORT pIfPort);
311NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortGetMacAddress)(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac);
312NETADP_DECL_CALLBACK(bool) NETADP_CALLBACK(vboxNetAdpPortIsHostMac)(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac);
313NETADP_DECL_CALLBACK(int) NETADP_CALLBACK(vboxNetAdpPortWaitForIdle)(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies);
314NETADP_DECL_CALLBACK(bool) NETADP_CALLBACK(vboxNetAdpPortSetActive)(PINTNETTRUNKIFPORT pIfPort, bool fActive);
315NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortDisconnectAndRelease)(PINTNETTRUNKIFPORT pIfPort);
316NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortRetain)(PINTNETTRUNKIFPORT pIfPort);
317NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortRelease)(PINTNETTRUNKIFPORT pIfPort);
318
319# else
320# error "UNSUPPORTED (RT_WITH_W64_UNWIND_HACK)"
321# endif
322#else
323# define NETADP_DECL_CALLBACK(type) static DECLCALLBACK(type)
324# define NETADP_CALLBACK(_n) _n
325#endif
326
327/**
328 * @copydoc INTNETTRUNKIFPORT::pfnXmit
329 */
330NETADP_DECL_CALLBACK(int) vboxNetAdpPortXmit(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst)
331{
332 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
333 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
334 int rc = VINF_SUCCESS;
335
336 /*
337 * Input validation.
338 */
339 AssertPtr(pThis);
340 AssertPtr(pSG);
341 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
342
343 /*
344 * Do a retain/busy, invoke the OS specific code.
345 */
346 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
347 if (pThis->enmState != kVBoxNetAdpState_Active)
348 {
349 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
350 Log(("vboxNetAdpReceive: Dropping incoming packet for inactive interface %s.\n",
351 pThis->szName));
352 return VERR_INVALID_STATE;
353 }
354 vboxNetAdpRetain(pThis);
355 vboxNetAdpBusy(pThis);
356 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
357 rc = vboxNetAdpPortOsXmit(pThis, pSG, fDst);
358 vboxNetAdpIdle(pThis);
359 vboxNetAdpRelease(pThis);
360
361 return rc;
362}
363
364
365/**
366 * @copydoc INTNETTRUNKIFPORT::pfnIsPromiscuous
367 */
368NETADP_DECL_CALLBACK(bool) vboxNetAdpPortIsPromiscuous(PINTNETTRUNKIFPORT pIfPort)
369{
370 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
371
372 /*
373 * Input validation.
374 */
375 AssertPtr(pThis);
376 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
377 Assert(vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Connected);
378
379 /*
380 * Ask the OS specific code.
381 */
382 return vboxNetAdpPortOsIsPromiscuous(pThis);
383}
384
385
386/**
387 * @copydoc INTNETTRUNKIFPORT::pfnGetMacAddress
388 */
389NETADP_DECL_CALLBACK(void) vboxNetAdpPortGetMacAddress(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac)
390{
391 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
392
393 /*
394 * Input validation.
395 */
396 AssertPtr(pThis);
397 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
398 Assert(vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Connected);
399
400 /*
401 * Forward the question to the OS specific code.
402 */
403 vboxNetAdpPortOsGetMacAddress(pThis, pMac);
404}
405
406
407/**
408 * @copydoc INTNETTRUNKIFPORT::pfnIsHostMac
409 */
410NETADP_DECL_CALLBACK(bool) vboxNetAdpPortIsHostMac(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac)
411{
412 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
413
414 /*
415 * Input validation.
416 */
417 AssertPtr(pThis);
418 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
419 Assert(vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Connected);
420
421 /*
422 * Ask the OS specific code.
423 */
424 return vboxNetAdpPortOsIsHostMac(pThis, pMac);
425}
426
427
428/**
429 * @copydoc INTNETTRUNKIFPORT::pfnWaitForIdle
430 */
431NETADP_DECL_CALLBACK(int) vboxNetAdpPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)
432{
433 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
434 int rc;
435
436 /*
437 * Input validation.
438 */
439 AssertPtr(pThis);
440 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
441 AssertReturn(vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Connected, VERR_INVALID_STATE);
442
443 /*
444 * Go to sleep on the semaphore after checking the busy count.
445 */
446 vboxNetAdpRetain(pThis);
447
448 rc = VINF_SUCCESS;
449 while (pThis->cBusy && RT_SUCCESS(rc))
450 rc = RTSemEventWait(pThis->hEventIdle, cMillies); /** @todo make interruptible? */
451
452 vboxNetAdpRelease(pThis);
453
454 return rc;
455}
456
457
458/**
459 * @copydoc INTNETTRUNKIFPORT::pfnSetActive
460 */
461NETADP_DECL_CALLBACK(bool) vboxNetAdpPortSetActive(PINTNETTRUNKIFPORT pIfPort, bool fActive)
462{
463 bool fPreviouslyActive;
464 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
465 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
466
467 /*
468 * Input validation.
469 */
470 AssertPtr(pThis);
471 AssertPtr(pThis->pGlobals);
472 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
473
474 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
475 switch (vboxNetAdpGetState(pThis))
476 {
477 case kVBoxNetAdpState_Connected:
478 fPreviouslyActive = false;
479 pThis->enmState = kVBoxNetAdpState_Active;
480 break;
481 case kVBoxNetAdpState_Active:
482 fPreviouslyActive = true;
483 pThis->enmState = kVBoxNetAdpState_Connected;
484 break;
485 default:
486 fPreviouslyActive = false;
487 break;
488 }
489 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
490 return fPreviouslyActive;
491}
492
493
494/**
495 * @copydoc INTNETTRUNKIFPORT::pfnDisconnectAndRelease
496 */
497NETADP_DECL_CALLBACK(void) vboxNetAdpPortDisconnectAndRelease(PINTNETTRUNKIFPORT pIfPort)
498{
499 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
500 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
501
502 /*
503 * Serious paranoia.
504 */
505 AssertPtr(pThis);
506 Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
507 Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
508 AssertPtr(pThis->pGlobals);
509 Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
510 Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
511
512 Assert(pThis->enmState == kVBoxNetAdpState_Connected);
513 Assert(!pThis->cBusy);
514
515 /*
516 * Disconnect and release it.
517 */
518 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
519 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Transitional);
520 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
521
522 vboxNetAdpOsDisconnectIt(pThis);
523 pThis->pSwitchPort = NULL;
524
525 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
526 vboxNetAdpSetState(pThis, kVBoxNetAdpState_Available);
527 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
528
529 vboxNetAdpRelease(pThis);
530}
531
532
533/**
534 * @copydoc INTNETTRUNKIFPORT::pfnRelease
535 */
536NETADP_DECL_CALLBACK(void) vboxNetAdpPortRelease(PINTNETTRUNKIFPORT pIfPort)
537{
538 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
539 vboxNetAdpRelease(pThis);
540}
541
542
543/**
544 * @copydoc INTNETTRUNKIFPORT::pfnRetain
545 */
546NETADP_DECL_CALLBACK(void) vboxNetAdpPortRetain(PINTNETTRUNKIFPORT pIfPort)
547{
548 PVBOXNETADP pThis = IFPORT_2_VBOXNETADP(pIfPort);
549 vboxNetAdpRetain(pThis);
550}
551
552
553/**
554 * Connects the instance to the specified switch port.
555 *
556 * Called while owning the lock. We're ASSUMING that the internal
557 * networking code is already owning an recursive mutex, so, there
558 * will be no deadlocks when vboxNetAdpOsConnectIt calls back into
559 * it for setting preferences.
560 *
561 * @returns VBox status code.
562 * @param pThis The instance.
563 * @param pSwitchPort The port on the internal network 'switch'.
564 * @param ppIfPort Where to return our port interface.
565 */
566static int vboxNetAdpConnectIt(PVBOXNETADP pThis, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
567{
568 int rc;
569
570 /*
571 * Validate state.
572 */
573 //Assert(!pThis->fActive);
574 Assert(!pThis->cBusy);
575 Assert(vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Transitional);
576
577 /*
578 * Do the job.
579 * Note that we're calling the os stuff while owning the semaphore here.
580 */
581 pThis->pSwitchPort = pSwitchPort;
582 rc = vboxNetAdpOsConnectIt(pThis);
583 if (RT_SUCCESS(rc))
584 {
585 *ppIfPort = &pThis->MyPort;
586 }
587 else
588 pThis->pSwitchPort = NULL;
589
590 //Assert(!pThis->fActive);
591 return rc;
592}
593
594/**
595 * @copydoc INTNETTRUNKFACTORY::pfnCreateAndConnect
596 */
597static DECLCALLBACK(int) vboxNetAdpFactoryCreateAndConnect(PINTNETTRUNKFACTORY pIfFactory, const char *pszName,
598 PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort, bool fNoPromisc)
599{
600 PVBOXNETADP pThis;
601 int rc;
602 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
603
604 LogFlow(("vboxNetAdpFactoryCreateAndConnect: pszName=%p:{%s}\n", pszName, pszName));
605 Assert(pGlobals->cFactoryRefs > 0);
606
607 /*
608 * Find instance, check if busy, connect if not.
609 */
610 pThis = vboxNetAdpFind(pGlobals, pszName);
611 if (pThis)
612 {
613 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
614 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
615 if (pThis->enmState == kVBoxNetAdpState_Available)
616 {
617 pThis->enmState = kVBoxNetAdpState_Transitional;
618 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
619 rc = vboxNetAdpConnectIt(pThis, pSwitchPort, ppIfPort);
620 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
621 if (RT_SUCCESS(rc))
622 pThis->enmState = kVBoxNetAdpState_Connected;
623 else
624 pThis->enmState = kVBoxNetAdpState_Available;
625 }
626 else
627 rc = VERR_INTNET_FLT_IF_BUSY;
628 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
629 }
630 else
631 rc = VERR_INTNET_FLT_IF_NOT_FOUND;
632
633 return rc;
634}
635
636/**
637 * @copydoc INTNETTRUNKFACTORY::pfnRelease
638 */
639static DECLCALLBACK(void) vboxNetAdpFactoryRelease(PINTNETTRUNKFACTORY pIfFactory)
640{
641 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
642
643 int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
644 Assert(cRefs >= 0); NOREF(cRefs);
645 LogFlow(("vboxNetAdpFactoryRelease: cRefs=%d (new)\n", cRefs));
646}
647
648
649/**
650 * Implements the SUPDRV component factor interface query method.
651 *
652 * @returns Pointer to an interface. NULL if not supported.
653 *
654 * @param pSupDrvFactory Pointer to the component factory registration structure.
655 * @param pSession The session - unused.
656 * @param pszInterfaceUuid The factory interface id.
657 */
658static DECLCALLBACK(void *) vboxNetAdpQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
659{
660 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, SupDrvFactory));
661
662 /*
663 * Convert the UUID strings and compare them.
664 */
665 RTUUID UuidReq;
666 int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
667 if (RT_SUCCESS(rc))
668 {
669 if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_UUID_STR))
670 {
671 ASMAtomicIncS32(&pGlobals->cFactoryRefs);
672 return &pGlobals->TrunkFactory;
673 }
674#ifdef LOG_ENABLED
675 else
676 Log(("VBoxNetAdp: unknown factory interface query (%s)\n", pszInterfaceUuid));
677#endif
678 }
679 else
680 Log(("VBoxNetAdp: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
681
682 return NULL;
683}
684
685
686/**
687 * Checks whether the VBoxNetAdp wossname can be unloaded.
688 *
689 * This will return false if someone is currently using the module.
690 *
691 * @returns true if it's relatively safe to unload it, otherwise false.
692 * @param pGlobals Pointer to the globals.
693 */
694DECLHIDDEN(bool) vboxNetAdpCanUnload(PVBOXNETADPGLOBALS pGlobals)
695{
696 int rc;
697 unsigned i;
698 bool fRc = true; /* Assume it can be unloaded. */
699
700 for (i = 0; i < RT_ELEMENTS(pGlobals->aAdapters); i++)
701 {
702 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
703 PVBOXNETADP pThis = &pGlobals->aAdapters[i];
704 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
705 if (vboxNetAdpIsConnected(&pGlobals->aAdapters[i]))
706 {
707 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
708 fRc = false;
709 break; /* We already know the answer. */
710 }
711 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
712 }
713 return fRc && ASMAtomicUoReadS32((int32_t volatile *)&pGlobals->cFactoryRefs) <= 0;
714}
715
716/**
717 * tries to deinitialize Idc
718 * we separate the globals settings "base" which is actually
719 * "general" globals settings except for Idc, and idc.
720 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
721 * thus it's not possible to make idc initialization from the driver startup routine for it,
722 * though the "base is still needed for the driver to functions".
723 * @param pGlobals
724 * @return VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
725 */
726DECLHIDDEN(int) vboxNetAdpTryDeleteIdc(PVBOXNETADPGLOBALS pGlobals)
727{
728 int rc;
729
730 Assert(pGlobals->hFastMtx != NIL_RTSEMFASTMUTEX);
731
732 /*
733 * Check before trying to deregister the factory.
734 */
735 if (!vboxNetAdpCanUnload(pGlobals))
736 return VERR_WRONG_ORDER;
737
738 /*
739 * Disconnect from SUPDRV and check that nobody raced us,
740 * reconnect if that should happen.
741 */
742 rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
743 AssertRC(rc);
744 if (!vboxNetAdpCanUnload(pGlobals))
745 {
746 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
747 AssertRC(rc);
748 return VERR_WRONG_ORDER;
749 }
750
751 SUPR0IdcClose(&pGlobals->SupDrvIDC);
752
753 return rc;
754}
755
756/**
757 * performs "base" globals deinitialization
758 * we separate the globals settings "base" which is actually
759 * "general" globals settings except for Idc, and idc.
760 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
761 * thus it's not possible to make idc initialization from the driver startup routine for it,
762 * though the "base is still needed for the driver to functions".
763 * @param pGlobals
764 * @return none
765 */
766DECLHIDDEN(void) vboxNetAdpDeleteGlobalsBase(PVBOXNETADPGLOBALS pGlobals)
767{
768 /*
769 * Release resources.
770 */
771 RTSemFastMutexDestroy(pGlobals->hFastMtx);
772 pGlobals->hFastMtx = NIL_RTSEMFASTMUTEX;
773
774#ifdef VBOXNETADP_STATIC_CONFIG
775 RTSemEventDestroy(pGlobals->hTimerEvent);
776 pGlobals->hTimerEvent = NIL_RTSEMEVENT;
777#endif
778
779}
780
781/**
782 * Called by the native part when the OS wants the driver to unload.
783 *
784 * @returns VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
785 *
786 * @param pGlobals Pointer to the globals.
787 */
788DECLHIDDEN(int) vboxNetAdpTryDeleteGlobals(PVBOXNETADPGLOBALS pGlobals)
789{
790 int rc = vboxNetAdpTryDeleteIdc(pGlobals);
791 if(RT_SUCCESS(rc))
792 {
793 vboxNetAdpDeleteGlobalsBase(pGlobals);
794 }
795 return rc;
796}
797
798/**
799 * performs the "base" globals initialization
800 * we separate the globals initialization to globals "base" initialization which is actually
801 * "general" globals initialization except for Idc not being initialized, and idc initialization.
802 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
803 * thus it's not possible to make idc initialization from the driver startup routine for it.
804 *
805 * @returns VBox status code.
806 * @param pGlobals Pointer to the globals. */
807DECLHIDDEN(int) vboxNetAdpInitGlobalsBase(PVBOXNETADPGLOBALS pGlobals)
808{
809 /*
810 * Initialize the common portions of the structure.
811 */
812 int i;
813 int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx);
814 if (RT_SUCCESS(rc))
815 {
816 memset(pGlobals->aAdapters, 0, sizeof(pGlobals->aAdapters));
817 for (i = 0; i < (int)RT_ELEMENTS(pGlobals->aAdapters); i++)
818 {
819 rc = RTSpinlockCreate(&pGlobals->aAdapters[i].hSpinlock);
820 if (RT_FAILURE(rc))
821 {
822 /* Clean up. */
823 while (--i >= 0)
824 RTSpinlockDestroy(pGlobals->aAdapters[i].hSpinlock);
825 Log(("vboxNetAdpInitGlobalsBase: Failed to create fast mutex (rc=%Rrc).\n", rc));
826 RTSemFastMutexDestroy(pGlobals->hFastMtx);
827 return rc;
828 }
829 }
830 pGlobals->TrunkFactory.pfnRelease = vboxNetAdpFactoryRelease;
831 pGlobals->TrunkFactory.pfnCreateAndConnect = vboxNetAdpFactoryCreateAndConnect;
832
833 strcpy(pGlobals->SupDrvFactory.szName, "VBoxNetTap");
834 pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxNetAdpQueryFactoryInterface;
835 }
836
837 return rc;
838}
839
840/**
841 * performs the Idc initialization
842 * we separate the globals initialization to globals "base" initialization which is actually
843 * "general" globals initialization except for Idc not being initialized, and idc initialization.
844 * This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
845 * thus it's not possible to make idc initialization from the driver startup routine for it.
846 *
847 * @returns VBox status code.
848 * @param pGlobals Pointer to the globals. */
849DECLHIDDEN(int) vboxNetAdpInitIdc(PVBOXNETADPGLOBALS pGlobals)
850{
851 int rc;
852 /*
853 * Establish a connection to SUPDRV and register our component factory.
854 */
855 rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
856 if (RT_SUCCESS(rc))
857 {
858 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
859 if (RT_SUCCESS(rc))
860 {
861 Log(("VBoxNetAdp: pSession=%p\n", SUPR0IdcGetSession(&pGlobals->SupDrvIDC)));
862 return rc;
863 }
864
865 /* bail out. */
866 LogRel(("VBoxNetAdp: Failed to register component factory, rc=%Rrc\n", rc));
867 SUPR0IdcClose(&pGlobals->SupDrvIDC);
868 }
869
870 return rc;
871}
872
873/**
874 * Called by the native driver/kext module initialization routine.
875 *
876 * It will initialize the common parts of the globals, assuming the caller
877 * has already taken care of the OS specific bits.
878 *
879 * @returns VBox status code.
880 * @param pGlobals Pointer to the globals.
881 */
882DECLHIDDEN(int) vboxNetAdpInitGlobals(PVBOXNETADPGLOBALS pGlobals)
883{
884 /*
885 * Initialize the common portions of the structure.
886 */
887 int rc = vboxNetAdpInitGlobalsBase(pGlobals);
888 if (RT_SUCCESS(rc))
889 {
890 rc = vboxNetAdpInitIdc(pGlobals);
891 if (RT_SUCCESS(rc))
892 {
893 return rc;
894 }
895
896 /* bail out. */
897 vboxNetAdpDeleteGlobalsBase(pGlobals);
898 }
899
900 return rc;
901}
902
903//////
904
905int vboxNetAdpCreate (PINTNETTRUNKFACTORY pIfFactory, PVBOXNETADP *ppNew)
906{
907 int rc;
908 unsigned i;
909 PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
910
911 for (i = 0; i < RT_ELEMENTS(pGlobals->aAdapters); i++)
912 {
913 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
914 PVBOXNETADP pThis = &pGlobals->aAdapters[i];
915
916 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
917 if (vboxNetAdpIsVoid(pThis))
918 {
919 RTMAC Mac;
920
921 pThis->enmState = kVBoxNetAdpState_Transitional;
922 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
923 /* Found an empty slot -- use it. */
924 pThis->uUnit = i;
925 vboxNetAdpComposeMACAddress(pThis, &Mac);
926 rc = vboxNetAdpOsCreate(pThis, &Mac);
927 *ppNew = pThis;
928 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
929 pThis->enmState = kVBoxNetAdpState_Available;
930 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
931 return rc;
932 }
933 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
934 }
935
936 /* All slots in adapter array are busy. */
937 return VERR_OUT_OF_RESOURCES;
938}
939
940int vboxNetAdpDestroy (PVBOXNETADP pThis)
941{
942 int rc;
943 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
944
945 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
946 if (pThis->enmState != kVBoxNetAdpState_Available || pThis->cBusy)
947 {
948 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
949 return VERR_INTNET_FLT_IF_BUSY;
950 }
951 pThis->enmState = kVBoxNetAdpState_Transitional;
952 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
953
954 vboxNetAdpOsDestroy(pThis);
955
956 RTSpinlockAcquire(pThis->hSpinlock, &Tmp);
957 pThis->enmState = kVBoxNetAdpState_Invalid;
958 RTSpinlockRelease(pThis->hSpinlock, &Tmp);
959
960 return rc;
961}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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