VirtualBox

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

Last change on this file since 17543 was 17198, checked in by vboxsync, 16 years ago

vboxNetAdpFactoryCreateAndConnect: inverted assertion.

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