VirtualBox

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

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

VBoxNetFlt: review of core changes, several review comments needing follow up. untested

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