VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvIntNet.cpp@ 33567

Last change on this file since 33567 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.7 KB
Line 
1/* $Id: DrvIntNet.cpp 33540 2010-10-28 09:27:05Z vboxsync $ */
2/** @file
3 * DrvIntNet - Internal network transport driver.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
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
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DRV_INTNET
22#include <VBox/pdmdrv.h>
23#include <VBox/pdmnetinline.h>
24#include <VBox/pdmnetifs.h>
25#include <VBox/cfgm.h>
26#include <VBox/intnet.h>
27#include <VBox/intnetinline.h>
28#include <VBox/vmm.h>
29#include <VBox/sup.h>
30#include <VBox/err.h>
31
32#include <VBox/param.h>
33#include <VBox/log.h>
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/ctype.h>
37#include <iprt/memcache.h>
38#include <iprt/net.h>
39#include <iprt/semaphore.h>
40#include <iprt/string.h>
41#include <iprt/time.h>
42#include <iprt/thread.h>
43#include <iprt/uuid.h>
44
45#include "../Builtins.h"
46
47
48/*******************************************************************************
49* Defined Constants And Macros *
50*******************************************************************************/
51/** Enables the ring-0 part. */
52#define VBOX_WITH_DRVINTNET_IN_R0
53
54
55/*******************************************************************************
56* Structures and Typedefs *
57*******************************************************************************/
58/**
59 * The state of the asynchronous thread.
60 */
61typedef enum RECVSTATE
62{
63 /** The thread is suspended. */
64 RECVSTATE_SUSPENDED = 1,
65 /** The thread is running. */
66 RECVSTATE_RUNNING,
67 /** The thread must (/has) terminate. */
68 RECVSTATE_TERMINATE,
69 /** The usual 32-bit type blowup. */
70 RECVSTATE_32BIT_HACK = 0x7fffffff
71} RECVSTATE;
72
73/**
74 * Internal networking driver instance data.
75 *
76 * @implements PDMINETWORKUP
77 */
78typedef struct DRVINTNET
79{
80 /** The network interface. */
81 PDMINETWORKUP INetworkUpR3;
82 /** The network interface. */
83 R3PTRTYPE(PPDMINETWORKDOWN) pIAboveNet;
84 /** The network config interface.
85 * Can (in theory at least) be NULL. */
86 R3PTRTYPE(PPDMINETWORKCONFIG) pIAboveConfigR3;
87 /** Pointer to the driver instance (ring-3). */
88 PPDMDRVINSR3 pDrvInsR3;
89 /** Pointer to the communication buffer (ring-3). */
90 R3PTRTYPE(PINTNETBUF) pBufR3;
91 /** Ring-3 base interface for the ring-0 context. */
92 PDMIBASER0 IBaseR0;
93 /** Ring-3 base interface for the raw-mode context. */
94 PDMIBASERC IBaseRC;
95 RTR3PTR R3PtrAlignment;
96
97 /** The network interface for the ring-0 context. */
98 PDMINETWORKUPR0 INetworkUpR0;
99 /** Pointer to the driver instance (ring-0). */
100 PPDMDRVINSR0 pDrvInsR0;
101 /** Pointer to the communication buffer (ring-0). */
102 R0PTRTYPE(PINTNETBUF) pBufR0;
103
104 /** The network interface for the raw-mode context. */
105 PDMINETWORKUPRC INetworkUpRC;
106 /** Pointer to the driver instance. */
107 PPDMDRVINSRC pDrvInsRC;
108 RTRCPTR RCPtrAlignment;
109
110 /** The transmit lock. */
111 PDMCRITSECT XmitLock;
112 /** Interface handle. */
113 INTNETIFHANDLE hIf;
114 /** The receive thread state. */
115 RECVSTATE volatile enmRecvState;
116 /** The receive thread. */
117 RTTHREAD hRecvThread;
118 /** The event semaphore that the receive thread waits on. */
119 RTSEMEVENT hRecvEvt;
120 /** The transmit thread. */
121 PPDMTHREAD pXmitThread;
122 /** The event semaphore that the transmit thread waits on. */
123 SUPSEMEVENT hXmitEvt;
124 /** The support driver session handle. */
125 PSUPDRVSESSION pSupDrvSession;
126 /** Scatter/gather descriptor cache. */
127 RTMEMCACHE hSgCache;
128 /** Set if the link is down.
129 * When the link is down all incoming packets will be dropped. */
130 bool volatile fLinkDown;
131 /** Set when the xmit thread has been signalled. (atomic) */
132 bool volatile fXmitSignalled;
133 /** Set if the transmit thread the one busy transmitting. */
134 bool volatile fXmitOnXmitThread;
135 /** The xmit thread should process the ring ASAP. */
136 bool fXmitProcessRing;
137 /** Set if data transmission should start immediately and deactivate
138 * as late as possible. */
139 bool fActivateEarlyDeactivateLate;
140 /** Padding. */
141 bool afReserved[HC_ARCH_BITS == 64 ? 3 : 3];
142 /** Scratch space for holding the ring-0 scatter / gather descriptor.
143 * The PDMSCATTERGATHER::fFlags member is used to indicate whether it is in
144 * use or not. Always accessed while owning the XmitLock. */
145 union
146 {
147 PDMSCATTERGATHER Sg;
148 uint8_t padding[8 * sizeof(RTUINTPTR)];
149 } u;
150 /** The network name. */
151 char szNetwork[INTNET_MAX_NETWORK_NAME];
152
153 /** Number of GSO packets sent. */
154 STAMCOUNTER StatSentGso;
155 /** Number of GSO packets received. */
156 STAMCOUNTER StatReceivedGso;
157 /** Number of packets send from ring-0. */
158 STAMCOUNTER StatSentR0;
159 /** The number of times we've had to wake up the xmit thread to continue the
160 * ring-0 job. */
161 STAMCOUNTER StatXmitWakeupR0;
162 /** The number of times we've had to wake up the xmit thread to continue the
163 * ring-3 job. */
164 STAMCOUNTER StatXmitWakeupR3;
165 /** The times the xmit thread has been told to process the ring. */
166 STAMCOUNTER StatXmitProcessRing;
167#ifdef VBOX_WITH_STATISTICS
168 /** Profiling packet transmit runs. */
169 STAMPROFILE StatTransmit;
170 /** Profiling packet receive runs. */
171 STAMPROFILEADV StatReceive;
172#endif /* VBOX_WITH_STATISTICS */
173#ifdef LOG_ENABLED
174 /** The nano ts of the last transfer. */
175 uint64_t u64LastTransferTS;
176 /** The nano ts of the last receive. */
177 uint64_t u64LastReceiveTS;
178#endif
179} DRVINTNET;
180AssertCompileMemberAlignment(DRVINTNET, XmitLock, 8);
181AssertCompileMemberAlignment(DRVINTNET, StatSentGso, 8);
182/** Pointer to instance data of the internal networking driver. */
183typedef DRVINTNET *PDRVINTNET;
184
185
186#ifdef IN_RING3
187
188
189/**
190 * Updates the MAC address on the kernel side.
191 *
192 * @returns VBox status code.
193 * @param pThis The driver instance.
194 */
195static int drvR3IntNetUpdateMacAddress(PDRVINTNET pThis)
196{
197 if (!pThis->pIAboveConfigR3)
198 return VINF_SUCCESS;
199
200 INTNETIFSETMACADDRESSREQ SetMacAddressReq;
201 SetMacAddressReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
202 SetMacAddressReq.Hdr.cbReq = sizeof(SetMacAddressReq);
203 SetMacAddressReq.pSession = NIL_RTR0PTR;
204 SetMacAddressReq.hIf = pThis->hIf;
205 int rc = pThis->pIAboveConfigR3->pfnGetMac(pThis->pIAboveConfigR3, &SetMacAddressReq.Mac);
206 if (RT_SUCCESS(rc))
207 rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS,
208 &SetMacAddressReq, sizeof(SetMacAddressReq));
209
210 Log(("drvR3IntNetUpdateMacAddress: %.*Rhxs rc=%Rrc\n", sizeof(SetMacAddressReq.Mac), &SetMacAddressReq.Mac, rc));
211 return rc;
212}
213
214
215/**
216 * Sets the kernel interface active or inactive.
217 *
218 * Worker for poweron, poweroff, suspend and resume.
219 *
220 * @returns VBox status code.
221 * @param pThis The driver instance.
222 * @param fActive The new state.
223 */
224static int drvR3IntNetSetActive(PDRVINTNET pThis, bool fActive)
225{
226 if (!pThis->pIAboveConfigR3)
227 return VINF_SUCCESS;
228
229 INTNETIFSETACTIVEREQ SetActiveReq;
230 SetActiveReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
231 SetActiveReq.Hdr.cbReq = sizeof(SetActiveReq);
232 SetActiveReq.pSession = NIL_RTR0PTR;
233 SetActiveReq.hIf = pThis->hIf;
234 SetActiveReq.fActive = fActive;
235 int rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SET_ACTIVE,
236 &SetActiveReq, sizeof(SetActiveReq));
237
238 Log(("drvR3IntNetSetActive: fActive=%d rc=%Rrc\n", fActive, rc));
239 AssertRC(rc);
240 return rc;
241}
242
243#endif /* IN_RING3 */
244
245/* -=-=-=-=- PDMINETWORKUP -=-=-=-=- */
246
247/**
248 * Helper for signalling the xmit thread.
249 *
250 * @returns VERR_TRY_AGAIN (convenience).
251 * @param pThis The instance data..
252 */
253DECLINLINE(int) drvIntNetSignalXmit(PDRVINTNET pThis)
254{
255 /// @todo if (!ASMAtomicXchgBool(&pThis->fXmitSignalled, true)) - needs careful optimizing.
256 {
257 int rc = SUPSemEventSignal(pThis->pSupDrvSession, pThis->hXmitEvt);
258 AssertRC(rc);
259 STAM_REL_COUNTER_INC(&pThis->CTX_SUFF(StatXmitWakeup));
260 }
261 return VERR_TRY_AGAIN;
262}
263
264
265/**
266 * Helper for processing the ring-0 consumer side of the xmit ring.
267 *
268 * The caller MUST own the xmit lock.
269 *
270 * @returns Status code from IntNetR0IfSend, except for VERR_TRY_AGAIN.
271 * @param pThis The instance data..
272 */
273DECLINLINE(int) drvIntNetProcessXmit(PDRVINTNET pThis)
274{
275 Assert(PDMCritSectIsOwner(&pThis->XmitLock));
276
277#ifdef IN_RING3
278 INTNETIFSENDREQ SendReq;
279 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
280 SendReq.Hdr.cbReq = sizeof(SendReq);
281 SendReq.pSession = NIL_RTR0PTR;
282 SendReq.hIf = pThis->hIf;
283 int rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
284#else
285 int rc = IntNetR0IfSend(pThis->hIf, pThis->pSupDrvSession);
286 if (rc == VERR_TRY_AGAIN)
287 {
288 ASMAtomicUoWriteBool(&pThis->fXmitProcessRing, true);
289 drvIntNetSignalXmit(pThis);
290 rc = VINF_SUCCESS;
291 }
292#endif
293 return rc;
294}
295
296
297
298/**
299 * @interface_method_impl{PDMINETWORKUP,pfnBeginXmit}
300 */
301PDMBOTHCBDECL(int) drvIntNetUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread)
302{
303 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
304#ifndef IN_RING3
305 Assert(!fOnWorkerThread);
306#endif
307
308 int rc = PDMCritSectTryEnter(&pThis->XmitLock);
309 if (RT_SUCCESS(rc))
310 {
311 if (fOnWorkerThread)
312 {
313 ASMAtomicUoWriteBool(&pThis->fXmitOnXmitThread, true);
314 ASMAtomicWriteBool(&pThis->fXmitSignalled, false);
315 }
316 }
317 else if (rc == VERR_SEM_BUSY)
318 {
319 /** @todo Does this actually make sense if the other dude is an EMT and so
320 * forth? I seriously think this is ring-0 only...
321 * We might end up waking up the xmit thread unnecessarily here, even when in
322 * ring-0... This needs some more thought and optimizations when the ring-0 bits
323 * are working. */
324#ifdef IN_RING3
325 if ( !fOnWorkerThread
326 /*&& !ASMAtomicUoReadBool(&pThis->fXmitOnXmitThread)
327 && ASMAtomicCmpXchgBool(&pThis->fXmitSignalled, true, false)*/)
328 {
329 rc = SUPSemEventSignal(pThis->pSupDrvSession, pThis->hXmitEvt);
330 AssertRC(rc);
331 }
332 rc = VERR_TRY_AGAIN;
333#else /* IN_RING0 */
334 rc = drvIntNetSignalXmit(pThis);
335#endif /* IN_RING0 */
336 }
337 return rc;
338}
339
340
341/**
342 * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
343 */
344PDMBOTHCBDECL(int) drvIntNetUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
345 PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf)
346{
347 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
348 int rc = VINF_SUCCESS;
349 Assert(cbMin < UINT32_MAX / 2);
350 Assert(PDMCritSectIsOwner(&pThis->XmitLock));
351
352 /*
353 * Allocate a S/G descriptor.
354 * This shouldn't normally fail as the NICs usually won't allocate more
355 * than one buffer at a time and the SG gets freed on sending.
356 */
357#ifdef IN_RING3
358 PPDMSCATTERGATHER pSgBuf = (PPDMSCATTERGATHER)RTMemCacheAlloc(pThis->hSgCache);
359 if (!pSgBuf)
360 return VERR_NO_MEMORY;
361#else
362 PPDMSCATTERGATHER pSgBuf = &pThis->u.Sg;
363 if (RT_UNLIKELY(pSgBuf->fFlags != 0))
364 return drvIntNetSignalXmit(pThis);
365#endif
366
367 /*
368 * Allocate room in the ring buffer.
369 *
370 * In ring-3 we may have to process the xmit ring before there is
371 * sufficient buffer space since we might have stacked up a few frames to the
372 * trunk while in ring-0. (There is not point of doing this in ring-0.)
373 */
374 PINTNETHDR pHdr = NULL; /* gcc silliness */
375 if (pGso)
376 rc = IntNetRingAllocateGsoFrame(&pThis->CTX_SUFF(pBuf)->Send, (uint32_t)cbMin, pGso,
377 &pHdr, &pSgBuf->aSegs[0].pvSeg);
378 else
379 rc = IntNetRingAllocateFrame(&pThis->CTX_SUFF(pBuf)->Send, (uint32_t)cbMin,
380 &pHdr, &pSgBuf->aSegs[0].pvSeg);
381#ifdef IN_RING3
382 if ( RT_FAILURE(rc)
383 && pThis->CTX_SUFF(pBuf)->cbSend >= cbMin * 2 + sizeof(INTNETHDR))
384 {
385 drvIntNetProcessXmit(pThis);
386 if (pGso)
387 rc = IntNetRingAllocateGsoFrame(&pThis->CTX_SUFF(pBuf)->Send, (uint32_t)cbMin, pGso,
388 &pHdr, &pSgBuf->aSegs[0].pvSeg);
389 else
390 rc = IntNetRingAllocateFrame(&pThis->CTX_SUFF(pBuf)->Send, (uint32_t)cbMin,
391 &pHdr, &pSgBuf->aSegs[0].pvSeg);
392 }
393#endif
394 if (RT_SUCCESS(rc))
395 {
396 /*
397 * Set up the S/G descriptor and return successfully.
398 */
399 pSgBuf->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
400 pSgBuf->cbUsed = 0;
401 pSgBuf->cbAvailable = cbMin;
402 pSgBuf->pvAllocator = pHdr;
403 pSgBuf->pvUser = pGso ? (PPDMNETWORKGSO)pSgBuf->aSegs[0].pvSeg - 1 : NULL;
404 pSgBuf->cSegs = 1;
405 pSgBuf->aSegs[0].cbSeg = cbMin;
406
407 *ppSgBuf = pSgBuf;
408 return VINF_SUCCESS;
409 }
410
411#ifdef IN_RING3
412 /*
413 * If the above fails, then we're really out of space. There are nobody
414 * competing with us here because of the xmit lock.
415 */
416 rc = VERR_NO_MEMORY;
417 RTMemCacheFree(pThis->hSgCache, pSgBuf);
418
419#else /* IN_RING0 */
420 /*
421 * If the request is reasonable, kick the xmit thread and tell it to
422 * process the xmit ring ASAP.
423 */
424 if (pThis->CTX_SUFF(pBuf)->cbSend >= cbMin * 2 + sizeof(INTNETHDR))
425 {
426 pThis->fXmitProcessRing = true;
427 rc = drvIntNetSignalXmit(pThis);
428 }
429 else
430 rc = VERR_NO_MEMORY;
431 pSgBuf->fFlags = 0;
432#endif /* IN_RING0 */
433 return rc;
434}
435
436
437/**
438 * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
439 */
440PDMBOTHCBDECL(int) drvIntNetUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
441{
442 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
443 PINTNETHDR pHdr = (PINTNETHDR)pSgBuf->pvAllocator;
444#ifdef IN_RING0
445 Assert(pSgBuf == &pThis->u.Sg);
446#endif
447 Assert(pSgBuf->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1));
448 Assert(pSgBuf->cbUsed <= pSgBuf->cbAvailable);
449 Assert( pHdr->u16Type == INTNETHDR_TYPE_FRAME
450 || pHdr->u16Type == INTNETHDR_TYPE_GSO);
451 Assert(PDMCritSectIsOwner(&pThis->XmitLock));
452
453 /** @todo LATER: try unalloc the frame. */
454 pHdr->u16Type = INTNETHDR_TYPE_PADDING;
455 IntNetRingCommitFrame(&pThis->CTX_SUFF(pBuf)->Send, pHdr);
456
457#ifdef IN_RING3
458 RTMemCacheFree(pThis->hSgCache, pSgBuf);
459#else
460 pSgBuf->fFlags = 0;
461#endif
462 return VINF_SUCCESS;
463}
464
465
466/**
467 * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
468 */
469PDMBOTHCBDECL(int) drvIntNetUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
470{
471 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
472 STAM_PROFILE_START(&pThis->StatTransmit, a);
473
474 AssertPtr(pSgBuf);
475 Assert(pSgBuf->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1));
476 Assert(pSgBuf->cbUsed <= pSgBuf->cbAvailable);
477 Assert(PDMCritSectIsOwner(&pThis->XmitLock));
478
479 if (pSgBuf->pvUser)
480 STAM_COUNTER_INC(&pThis->StatSentGso);
481
482 /* Set an FTM checkpoint as this operation changes the state permanently. */
483 PDMDrvHlpFTSetCheckpoint(pThis->CTX_SUFF(pDrvIns), FTMCHECKPOINTTYPE_NETWORK);
484
485 /*
486 * Commit the frame and push it thru the switch.
487 */
488 PINTNETHDR pHdr = (PINTNETHDR)pSgBuf->pvAllocator;
489 IntNetRingCommitFrameEx(&pThis->CTX_SUFF(pBuf)->Send, pHdr, pSgBuf->cbUsed);
490 int rc = drvIntNetProcessXmit(pThis);
491 STAM_PROFILE_STOP(&pThis->StatTransmit, a);
492
493 /*
494 * Free the descriptor and return.
495 */
496#ifdef IN_RING3
497 RTMemCacheFree(pThis->hSgCache, pSgBuf);
498#else
499 STAM_REL_COUNTER_INC(&pThis->StatSentR0);
500 pSgBuf->fFlags = 0;
501#endif
502 return rc;
503}
504
505
506/**
507 * @interface_method_impl{PDMINETWORKUP,pfnEndXmit}
508 */
509PDMBOTHCBDECL(void) drvIntNetUp_EndXmit(PPDMINETWORKUP pInterface)
510{
511 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
512 ASMAtomicUoWriteBool(&pThis->fXmitOnXmitThread, false);
513 PDMCritSectLeave(&pThis->XmitLock);
514}
515
516
517/**
518 * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
519 */
520PDMBOTHCBDECL(void) drvIntNetUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
521{
522 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
523
524#ifdef IN_RING3
525 INTNETIFSETPROMISCUOUSMODEREQ Req;
526 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
527 Req.Hdr.cbReq = sizeof(Req);
528 Req.pSession = NIL_RTR0PTR;
529 Req.hIf = pThis->hIf;
530 Req.fPromiscuous = fPromiscuous;
531 int rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, &Req, sizeof(Req));
532#else /* IN_RING0 */
533 int rc = IntNetR0IfSetPromiscuousMode(pThis->hIf, pThis->pSupDrvSession, fPromiscuous);
534#endif /* IN_RING0 */
535
536 LogFlow(("drvIntNetUp_SetPromiscuousMode: fPromiscuous=%RTbool\n", fPromiscuous));
537 AssertRC(rc);
538}
539
540#ifdef IN_RING3
541
542/**
543 * @interface_method_impl{PDMINETWORKUP,pfnNotifyLinkChanged}
544 */
545static DECLCALLBACK(void) drvR3IntNetUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
546{
547 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, CTX_SUFF(INetworkUp));
548 bool fLinkDown;
549 switch (enmLinkState)
550 {
551 case PDMNETWORKLINKSTATE_DOWN:
552 case PDMNETWORKLINKSTATE_DOWN_RESUME:
553 fLinkDown = true;
554 break;
555 default:
556 AssertMsgFailed(("enmLinkState=%d\n", enmLinkState));
557 case PDMNETWORKLINKSTATE_UP:
558 fLinkDown = false;
559 break;
560 }
561 LogFlow(("drvR3IntNetUp_NotifyLinkChanged: enmLinkState=%d %d->%d\n", enmLinkState, pThis->fLinkDown, fLinkDown));
562 ASMAtomicXchgSize(&pThis->fLinkDown, fLinkDown);
563}
564
565
566/* -=-=-=-=- Transmit Thread -=-=-=-=- */
567
568/**
569 * Async I/O thread for deferred packet transmission.
570 *
571 * @returns VBox status code. Returning failure will naturally terminate the thread.
572 * @param pDrvIns The internal networking driver instance.
573 * @param pThread The thread.
574 */
575static DECLCALLBACK(int) drvR3IntNetXmitThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
576{
577 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
578
579 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
580 {
581 /*
582 * Transmit any pending packets.
583 */
584 /** @todo Optimize this. We shouldn't call pfnXmitPending unless asked for.
585 * Also there is no need to call drvIntNetProcessXmit if we also
586 * called pfnXmitPending and send one or more frames. */
587 if (ASMAtomicXchgBool(&pThis->fXmitProcessRing, false))
588 {
589 STAM_REL_COUNTER_INC(&pThis->StatXmitProcessRing);
590 PDMCritSectEnter(&pThis->XmitLock, VERR_IGNORED);
591 drvIntNetProcessXmit(pThis);
592 PDMCritSectLeave(&pThis->XmitLock);
593 }
594
595 pThis->pIAboveNet->pfnXmitPending(pThis->pIAboveNet);
596
597 if (ASMAtomicXchgBool(&pThis->fXmitProcessRing, false))
598 {
599 STAM_REL_COUNTER_INC(&pThis->StatXmitProcessRing);
600 PDMCritSectEnter(&pThis->XmitLock, VERR_IGNORED);
601 drvIntNetProcessXmit(pThis);
602 PDMCritSectLeave(&pThis->XmitLock);
603 }
604
605 /*
606 * Block until we've got something to send or is supposed
607 * to leave the running state.
608 */
609 int rc = SUPSemEventWaitNoResume(pThis->pSupDrvSession, pThis->hXmitEvt, RT_INDEFINITE_WAIT);
610 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
611 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
612 break;
613
614 }
615
616 /* The thread is being initialized, suspended or terminated. */
617 return VINF_SUCCESS;
618}
619
620
621/**
622 * @copydoc FNPDMTHREADWAKEUPDRV
623 */
624static DECLCALLBACK(int) drvR3IntNetXmitWakeUp(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
625{
626 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
627 return SUPSemEventSignal(pThis->pSupDrvSession, pThis->hXmitEvt);
628}
629
630
631/* -=-=-=-=- Receive Thread -=-=-=-=- */
632
633/**
634 * Wait for space to become available up the driver/device chain.
635 *
636 * @returns VINF_SUCCESS if space is available.
637 * @returns VERR_STATE_CHANGED if the state changed.
638 * @returns VBox status code on other errors.
639 * @param pThis Pointer to the instance data.
640 */
641static int drvR3IntNetRecvWaitForSpace(PDRVINTNET pThis)
642{
643 LogFlow(("drvR3IntNetRecvWaitForSpace:\n"));
644 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
645 int rc = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, RT_INDEFINITE_WAIT);
646 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
647 LogFlow(("drvR3IntNetRecvWaitForSpace: returns %Rrc\n", rc));
648 return rc;
649}
650
651
652/**
653 * Executes async I/O (RUNNING mode).
654 *
655 * @returns VERR_STATE_CHANGED if the state changed.
656 * @returns Appropriate VBox status code (error) on fatal error.
657 * @param pThis The driver instance data.
658 */
659static int drvR3IntNetRecvRun(PDRVINTNET pThis)
660{
661 PPDMDRVINS pDrvIns = pThis->pDrvInsR3;
662 LogFlow(("drvR3IntNetRecvRun: pThis=%p\n", pThis));
663
664 /*
665 * The running loop - processing received data and waiting for more to arrive.
666 */
667 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
668 PINTNETBUF pBuf = pThis->CTX_SUFF(pBuf);
669 PINTNETRINGBUF pRingBuf = &pBuf->Recv;
670 for (;;)
671 {
672 /*
673 * Process the receive buffer.
674 */
675 PINTNETHDR pHdr;
676 while ((pHdr = IntNetRingGetNextFrameToRead(pRingBuf)) != NULL)
677 {
678 /*
679 * Check the state and then inspect the packet.
680 */
681 if (pThis->enmRecvState != RECVSTATE_RUNNING)
682 {
683 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
684 LogFlow(("drvR3IntNetRecvRun: returns VERR_STATE_CHANGED (state changed - #0)\n"));
685 return VERR_STATE_CHANGED;
686 }
687
688 Log2(("pHdr=%p offRead=%#x: %.8Rhxs\n", pHdr, pRingBuf->offReadX, pHdr));
689 uint16_t u16Type = pHdr->u16Type;
690 if ( ( u16Type == INTNETHDR_TYPE_FRAME
691 || u16Type == INTNETHDR_TYPE_GSO)
692 && !pThis->fLinkDown)
693 {
694 /*
695 * Check if there is room for the frame and pass it up.
696 */
697 size_t cbFrame = pHdr->cbFrame;
698 int rc = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, 0);
699 if (rc == VINF_SUCCESS)
700 {
701 if (u16Type == INTNETHDR_TYPE_FRAME)
702 {
703 /*
704 * Normal frame.
705 */
706#ifdef LOG_ENABLED
707 if (LogIsEnabled())
708 {
709 uint64_t u64Now = RTTimeProgramNanoTS();
710 LogFlow(("drvR3IntNetRecvRun: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
711 cbFrame, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
712 pThis->u64LastReceiveTS = u64Now;
713 Log2(("drvR3IntNetRecvRun: cbFrame=%#x\n"
714 "%.*Rhxd\n",
715 cbFrame, cbFrame, IntNetHdrGetFramePtr(pHdr, pBuf)));
716 }
717#endif
718 rc = pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, IntNetHdrGetFramePtr(pHdr, pBuf), cbFrame);
719 AssertRC(rc);
720
721 /* skip to the next frame. */
722 IntNetRingSkipFrame(pRingBuf);
723 }
724 else
725 {
726 /*
727 * Generic segment offload frame (INTNETHDR_TYPE_GSO).
728 */
729 STAM_COUNTER_INC(&pThis->StatReceivedGso);
730 PCPDMNETWORKGSO pGso = IntNetHdrGetGsoContext(pHdr, pBuf);
731 if (PDMNetGsoIsValid(pGso, cbFrame, cbFrame - sizeof(PDMNETWORKGSO)))
732 {
733 if (!pThis->pIAboveNet->pfnReceiveGso ||
734 RT_FAILURE(pThis->pIAboveNet->pfnReceiveGso(pThis->pIAboveNet,
735 (uint8_t *)(pGso + 1),
736 pHdr->cbFrame - sizeof(PDMNETWORKGSO),
737 pGso)))
738 {
739 /*
740 *
741 * This is where we do the offloading since this NIC
742 * does not support large receive offload (LRO).
743 */
744 cbFrame -= sizeof(PDMNETWORKGSO);
745
746 uint8_t abHdrScratch[256];
747 uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, cbFrame);
748#ifdef LOG_ENABLED
749 if (LogIsEnabled())
750 {
751 uint64_t u64Now = RTTimeProgramNanoTS();
752 LogFlow(("drvR3IntNetRecvRun: %-4d bytes at %llu ns deltas: r=%llu t=%llu; GSO - %u segs\n",
753 cbFrame, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS, cSegs));
754 pThis->u64LastReceiveTS = u64Now;
755 Log2(("drvR3IntNetRecvRun: cbFrame=%#x type=%d cbHdrs=%#x Hdr1=%#x Hdr2=%#x MMS=%#x\n"
756 "%.*Rhxd\n",
757 cbFrame, pGso->u8Type, pGso->cbHdrs, pGso->offHdr1, pGso->offHdr2, pGso->cbMaxSeg,
758 cbFrame - sizeof(*pGso), pGso + 1));
759 }
760#endif
761 for (size_t iSeg = 0; iSeg < cSegs; iSeg++)
762 {
763 uint32_t cbSegFrame;
764 void *pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)(pGso + 1), cbFrame, abHdrScratch,
765 iSeg, cSegs, &cbSegFrame);
766 rc = drvR3IntNetRecvWaitForSpace(pThis);
767 if (RT_FAILURE(rc))
768 {
769 Log(("drvR3IntNetRecvRun: drvR3IntNetRecvWaitForSpace -> %Rrc; iSeg=%u cSegs=%u\n", iSeg, cSegs));
770 break; /* we drop the rest. */
771 }
772 rc = pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, pvSegFrame, cbSegFrame);
773 AssertRC(rc);
774 }
775 }
776 }
777 else
778 {
779 AssertMsgFailed(("cbFrame=%#x type=%d cbHdrs=%#x Hdr1=%#x Hdr2=%#x MMS=%#x\n",
780 cbFrame, pGso->u8Type, pGso->cbHdrs, pGso->offHdr1, pGso->offHdr2, pGso->cbMaxSeg));
781 STAM_REL_COUNTER_INC(&pBuf->cStatBadFrames);
782 }
783
784 IntNetRingSkipFrame(pRingBuf);
785 }
786 }
787 else
788 {
789 /*
790 * Wait for sufficient space to become available and then retry.
791 */
792 rc = drvR3IntNetRecvWaitForSpace(pThis);
793 if (RT_FAILURE(rc))
794 {
795 if (rc == VERR_INTERRUPTED)
796 {
797 /*
798 * NIC is going down, likely because the VM is being reset. Skip the frame.
799 */
800 AssertMsg(IntNetIsValidFrameType(pHdr->u16Type), ("Unknown frame type %RX16! offRead=%#x\n", pHdr->u16Type, pRingBuf->offReadX));
801 IntNetRingSkipFrame(pRingBuf);
802 }
803 else
804 {
805 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
806 LogFlow(("drvR3IntNetRecvRun: returns %Rrc (wait-for-space)\n", rc));
807 return rc;
808 }
809 }
810 }
811 }
812 else
813 {
814 /*
815 * Link down or unknown frame - skip to the next frame.
816 */
817 AssertMsg(IntNetIsValidFrameType(pHdr->u16Type), ("Unknown frame type %RX16! offRead=%#x\n", pHdr->u16Type, pRingBuf->offReadX));
818 IntNetRingSkipFrame(pRingBuf);
819 STAM_REL_COUNTER_INC(&pBuf->cStatBadFrames);
820 }
821 } /* while more received data */
822
823 /*
824 * Wait for data, checking the state before we block.
825 */
826 if (pThis->enmRecvState != RECVSTATE_RUNNING)
827 {
828 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
829 LogFlow(("drvR3IntNetRecvRun: returns VINF_SUCCESS (state changed - #1)\n"));
830 return VERR_STATE_CHANGED;
831 }
832 INTNETIFWAITREQ WaitReq;
833 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
834 WaitReq.Hdr.cbReq = sizeof(WaitReq);
835 WaitReq.pSession = NIL_RTR0PTR;
836 WaitReq.hIf = pThis->hIf;
837 WaitReq.cMillies = 30000; /* 30s - don't wait forever, timeout now and then. */
838 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
839 int rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_WAIT, &WaitReq, sizeof(WaitReq));
840 if ( RT_FAILURE(rc)
841 && rc != VERR_TIMEOUT
842 && rc != VERR_INTERRUPTED)
843 {
844 LogFlow(("drvR3IntNetRecvRun: returns %Rrc\n", rc));
845 return rc;
846 }
847 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
848 }
849}
850
851
852/**
853 * Asynchronous I/O thread for handling receive.
854 *
855 * @returns VINF_SUCCESS (ignored).
856 * @param ThreadSelf Thread handle.
857 * @param pvUser Pointer to a DRVINTNET structure.
858 */
859static DECLCALLBACK(int) drvR3IntNetRecvThread(RTTHREAD ThreadSelf, void *pvUser)
860{
861 PDRVINTNET pThis = (PDRVINTNET)pvUser;
862 LogFlow(("drvR3IntNetRecvThread: pThis=%p\n", pThis));
863 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
864
865 /*
866 * The main loop - acting on state.
867 */
868 for (;;)
869 {
870 RECVSTATE enmRecvState = pThis->enmRecvState;
871 switch (enmRecvState)
872 {
873 case RECVSTATE_SUSPENDED:
874 {
875 int rc = RTSemEventWait(pThis->hRecvEvt, 30000);
876 if ( RT_FAILURE(rc)
877 && rc != VERR_TIMEOUT)
878 {
879 LogFlow(("drvR3IntNetRecvThread: returns %Rrc\n", rc));
880 return rc;
881 }
882 break;
883 }
884
885 case RECVSTATE_RUNNING:
886 {
887 int rc = drvR3IntNetRecvRun(pThis);
888 if ( rc != VERR_STATE_CHANGED
889 && RT_FAILURE(rc))
890 {
891 LogFlow(("drvR3IntNetRecvThread: returns %Rrc\n", rc));
892 return rc;
893 }
894 break;
895 }
896
897 default:
898 AssertMsgFailed(("Invalid state %d\n", enmRecvState));
899 case RECVSTATE_TERMINATE:
900 LogFlow(("drvR3IntNetRecvThread: returns VINF_SUCCESS\n"));
901 return VINF_SUCCESS;
902 }
903 }
904}
905
906
907/* -=-=-=-=- PDMIBASERC -=-=-=-=- */
908
909/**
910 * @interface_method_impl{PDMIBASERC,pfnQueryInterface}
911 */
912static DECLCALLBACK(RTRCPTR) drvR3IntNetIBaseRC_QueryInterface(PPDMIBASERC pInterface, const char *pszIID)
913{
914 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, IBaseRC);
915
916#if 0
917 PDMIBASERC_RETURN_INTERFACE(pThis->pDrvInsR3, pszIID, PDMINETWORKUP, &pThis->INetworkUpRC);
918#endif
919 return NIL_RTRCPTR;
920}
921
922
923/* -=-=-=-=- PDMIBASER0 -=-=-=-=- */
924
925/**
926 * @interface_method_impl{PDMIBASER0,pfnQueryInterface}
927 */
928static DECLCALLBACK(RTR0PTR) drvR3IntNetIBaseR0_QueryInterface(PPDMIBASER0 pInterface, const char *pszIID)
929{
930 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, IBaseR0);
931#ifdef VBOX_WITH_DRVINTNET_IN_R0
932 PDMIBASER0_RETURN_INTERFACE(pThis->pDrvInsR3, pszIID, PDMINETWORKUP, &pThis->INetworkUpR0);
933#endif
934 return NIL_RTR0PTR;
935}
936
937
938/* -=-=-=-=- PDMIBASE -=-=-=-=- */
939
940/**
941 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
942 */
943static DECLCALLBACK(void *) drvR3IntNetIBase_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
944{
945 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
946 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
947
948 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
949 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASER0, &pThis->IBaseR0);
950 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASERC, &pThis->IBaseRC);
951 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUpR3);
952 return NULL;
953}
954
955
956/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
957
958/**
959 * Power Off notification.
960 *
961 * @param pDrvIns The driver instance.
962 */
963static DECLCALLBACK(void) drvR3IntNetPowerOff(PPDMDRVINS pDrvIns)
964{
965 LogFlow(("drvR3IntNetPowerOff\n"));
966 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
967 if (!pThis->fActivateEarlyDeactivateLate)
968 {
969 ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_SUSPENDED);
970 drvR3IntNetSetActive(pThis, false /* fActive */);
971 }
972}
973
974
975/**
976 * drvR3IntNetResume helper.
977 */
978static int drvR3IntNetResumeSend(PDRVINTNET pThis, const void *pvBuf, size_t cb)
979{
980 /*
981 * Add the frame to the send buffer and push it onto the network.
982 */
983 int rc = IntNetRingWriteFrame(&pThis->pBufR3->Send, pvBuf, (uint32_t)cb);
984 if ( rc == VERR_BUFFER_OVERFLOW
985 && pThis->pBufR3->cbSend < cb)
986 {
987 INTNETIFSENDREQ SendReq;
988 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
989 SendReq.Hdr.cbReq = sizeof(SendReq);
990 SendReq.pSession = NIL_RTR0PTR;
991 SendReq.hIf = pThis->hIf;
992 PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
993
994 rc = IntNetRingWriteFrame(&pThis->pBufR3->Send, pvBuf, (uint32_t)cb);
995 }
996
997 if (RT_SUCCESS(rc))
998 {
999 INTNETIFSENDREQ SendReq;
1000 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1001 SendReq.Hdr.cbReq = sizeof(SendReq);
1002 SendReq.pSession = NIL_RTR0PTR;
1003 SendReq.hIf = pThis->hIf;
1004 rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
1005 }
1006
1007 AssertRC(rc);
1008 return rc;
1009}
1010
1011
1012/**
1013 * Resume notification.
1014 *
1015 * @param pDrvIns The driver instance.
1016 */
1017static DECLCALLBACK(void) drvR3IntNetResume(PPDMDRVINS pDrvIns)
1018{
1019 LogFlow(("drvR3IntNetPowerResume\n"));
1020 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
1021 if (!pThis->fActivateEarlyDeactivateLate)
1022 {
1023 ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_RUNNING);
1024 RTSemEventSignal(pThis->hRecvEvt);
1025 drvR3IntNetUpdateMacAddress(pThis); /* (could be a state restore) */
1026 drvR3IntNetSetActive(pThis, true /* fActive */);
1027 }
1028 if ( PDMDrvHlpVMTeleportedAndNotFullyResumedYet(pDrvIns)
1029 && pThis->pIAboveConfigR3)
1030 {
1031 /*
1032 * We've just been teleported and need to drop a hint to the switch
1033 * since we're likely to have changed to a different port. We just
1034 * push out some ethernet frame that doesn't mean anything to anyone.
1035 * For this purpose ethertype 0x801e was chosen since it was registered
1036 * to Sun (dunno what it is/was used for though).
1037 */
1038 union
1039 {
1040 RTNETETHERHDR Hdr;
1041 uint8_t ab[128];
1042 } Frame;
1043 RT_ZERO(Frame);
1044 Frame.Hdr.DstMac.au16[0] = 0xffff;
1045 Frame.Hdr.DstMac.au16[1] = 0xffff;
1046 Frame.Hdr.DstMac.au16[2] = 0xffff;
1047 Frame.Hdr.EtherType = RT_H2BE_U16_C(0x801e);
1048 int rc = pThis->pIAboveConfigR3->pfnGetMac(pThis->pIAboveConfigR3, &Frame.Hdr.SrcMac);
1049 if (RT_SUCCESS(rc))
1050 rc = drvR3IntNetResumeSend(pThis, &Frame, sizeof(Frame));
1051 if (RT_FAILURE(rc))
1052 LogRel(("IntNet#%u: Sending dummy frame failed: %Rrc\n", pDrvIns->iInstance, rc));
1053 }
1054}
1055
1056
1057/**
1058 * Suspend notification.
1059 *
1060 * @param pDrvIns The driver instance.
1061 */
1062static DECLCALLBACK(void) drvR3IntNetSuspend(PPDMDRVINS pDrvIns)
1063{
1064 LogFlow(("drvR3IntNetPowerSuspend\n"));
1065 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
1066 if (!pThis->fActivateEarlyDeactivateLate)
1067 {
1068 ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_SUSPENDED);
1069 drvR3IntNetSetActive(pThis, false /* fActive */);
1070 }
1071}
1072
1073
1074/**
1075 * Power On notification.
1076 *
1077 * @param pDrvIns The driver instance.
1078 */
1079static DECLCALLBACK(void) drvR3IntNetPowerOn(PPDMDRVINS pDrvIns)
1080{
1081 LogFlow(("drvR3IntNetPowerOn\n"));
1082 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
1083 if (!pThis->fActivateEarlyDeactivateLate)
1084 {
1085 ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_RUNNING);
1086 RTSemEventSignal(pThis->hRecvEvt);
1087 drvR3IntNetUpdateMacAddress(pThis);
1088 drvR3IntNetSetActive(pThis, true /* fActive */);
1089 }
1090}
1091
1092
1093/**
1094 * @interface_method_impl{PDMDRVREG,pfnRelocate}
1095 */
1096static DECLCALLBACK(void) drvR3IntNetRelocate(PPDMDRVINS pDrvIns, RTGCINTPTR offDelta)
1097{
1098 /* nothing to do here yet */
1099}
1100
1101
1102/**
1103 * Destruct a driver instance.
1104 *
1105 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
1106 * resources can be freed correctly.
1107 *
1108 * @param pDrvIns The driver instance data.
1109 */
1110static DECLCALLBACK(void) drvR3IntNetDestruct(PPDMDRVINS pDrvIns)
1111{
1112 LogFlow(("drvR3IntNetDestruct\n"));
1113 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
1114 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
1115
1116 /*
1117 * Indicate to the receive thread that it's time to quit.
1118 */
1119 ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_TERMINATE);
1120 ASMAtomicXchgSize(&pThis->fLinkDown, true);
1121 RTSEMEVENT hRecvEvt = pThis->hRecvEvt;
1122 pThis->hRecvEvt = NIL_RTSEMEVENT;
1123
1124 if (hRecvEvt != NIL_RTSEMEVENT)
1125 RTSemEventSignal(hRecvEvt);
1126
1127 if (pThis->hIf != INTNET_HANDLE_INVALID)
1128 {
1129 INTNETIFABORTWAITREQ AbortWaitReq;
1130 AbortWaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1131 AbortWaitReq.Hdr.cbReq = sizeof(AbortWaitReq);
1132 AbortWaitReq.pSession = NIL_RTR0PTR;
1133 AbortWaitReq.hIf = pThis->hIf;
1134 AbortWaitReq.fNoMoreWaits = true;
1135 int rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_ABORT_WAIT, &AbortWaitReq, sizeof(AbortWaitReq));
1136 AssertRC(rc);
1137 }
1138
1139 /*
1140 * Wait for the threads to terminate.
1141 */
1142 if (pThis->pXmitThread)
1143 {
1144 int rc = PDMR3ThreadDestroy(pThis->pXmitThread, NULL);
1145 AssertRC(rc);
1146 pThis->pXmitThread = NULL;
1147 }
1148
1149 if (pThis->hRecvThread != NIL_RTTHREAD)
1150 {
1151 int rc = RTThreadWait(pThis->hRecvThread, 5000, NULL);
1152 AssertRC(rc);
1153 pThis->hRecvThread = NIL_RTTHREAD;
1154 }
1155
1156 /*
1157 * Deregister statistics in case we're being detached.
1158 */
1159 if (pThis->pBufR3)
1160 {
1161 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Recv.cStatFrames);
1162 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Recv.cbStatWritten);
1163 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Recv.cOverflows);
1164 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Send.cStatFrames);
1165 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Send.cbStatWritten);
1166 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Send.cOverflows);
1167 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatYieldsOk);
1168 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatYieldsNok);
1169 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatLost);
1170 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatBadFrames);
1171 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->StatSend1);
1172 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->StatSend2);
1173 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->StatRecv1);
1174 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->StatRecv2);
1175 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceivedGso);
1176 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatSentGso);
1177#ifdef VBOX_WITH_STATISTICS
1178 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceive);
1179 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatTransmit);
1180#endif
1181 }
1182
1183 /*
1184 * Close the interface
1185 */
1186 if (pThis->hIf != INTNET_HANDLE_INVALID)
1187 {
1188 INTNETIFCLOSEREQ CloseReq;
1189 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1190 CloseReq.Hdr.cbReq = sizeof(CloseReq);
1191 CloseReq.pSession = NIL_RTR0PTR;
1192 CloseReq.hIf = pThis->hIf;
1193 pThis->hIf = INTNET_HANDLE_INVALID;
1194 int rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_CLOSE, &CloseReq, sizeof(CloseReq));
1195 AssertRC(rc);
1196 }
1197
1198
1199 /*
1200 * Destroy the semaphores, S/G cache and xmit lock.
1201 */
1202 if (hRecvEvt != NIL_RTSEMEVENT)
1203 RTSemEventDestroy(hRecvEvt);
1204
1205 if (pThis->hXmitEvt != NIL_SUPSEMEVENT)
1206 {
1207 SUPSemEventClose(pThis->pSupDrvSession, pThis->hXmitEvt);
1208 pThis->hXmitEvt = NIL_SUPSEMEVENT;
1209 }
1210
1211 RTMemCacheDestroy(pThis->hSgCache);
1212 pThis->hSgCache = NIL_RTMEMCACHE;
1213
1214 if (PDMCritSectIsInitialized(&pThis->XmitLock))
1215 PDMR3CritSectDelete(&pThis->XmitLock);
1216}
1217
1218
1219/**
1220 * Construct a TAP network transport driver instance.
1221 *
1222 * @copydoc FNPDMDRVCONSTRUCT
1223 */
1224static DECLCALLBACK(int) drvR3IntNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1225{
1226 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
1227 bool f;
1228 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1229
1230 /*
1231 * Init the static parts.
1232 */
1233 pThis->pDrvInsR3 = pDrvIns;
1234#ifdef VBOX_WITH_DRVINTNET_IN_R0
1235 pThis->pDrvInsR0 = PDMDRVINS_2_R0PTR(pDrvIns);
1236#endif
1237 pThis->hIf = INTNET_HANDLE_INVALID;
1238 pThis->hRecvThread = NIL_RTTHREAD;
1239 pThis->hRecvEvt = NIL_RTSEMEVENT;
1240 pThis->pXmitThread = NULL;
1241 pThis->hXmitEvt = NIL_SUPSEMEVENT;
1242 pThis->pSupDrvSession = PDMDrvHlpGetSupDrvSession(pDrvIns);
1243 pThis->hSgCache = NIL_RTMEMCACHE;
1244 pThis->enmRecvState = RECVSTATE_SUSPENDED;
1245 pThis->fActivateEarlyDeactivateLate = false;
1246 /* IBase* */
1247 pDrvIns->IBase.pfnQueryInterface = drvR3IntNetIBase_QueryInterface;
1248 pThis->IBaseR0.pfnQueryInterface = drvR3IntNetIBaseR0_QueryInterface;
1249 pThis->IBaseRC.pfnQueryInterface = drvR3IntNetIBaseRC_QueryInterface;
1250 /* INetworkUp */
1251 pThis->INetworkUpR3.pfnBeginXmit = drvIntNetUp_BeginXmit;
1252 pThis->INetworkUpR3.pfnAllocBuf = drvIntNetUp_AllocBuf;
1253 pThis->INetworkUpR3.pfnFreeBuf = drvIntNetUp_FreeBuf;
1254 pThis->INetworkUpR3.pfnSendBuf = drvIntNetUp_SendBuf;
1255 pThis->INetworkUpR3.pfnEndXmit = drvIntNetUp_EndXmit;
1256 pThis->INetworkUpR3.pfnSetPromiscuousMode = drvIntNetUp_SetPromiscuousMode;
1257 pThis->INetworkUpR3.pfnNotifyLinkChanged = drvR3IntNetUp_NotifyLinkChanged;
1258
1259 /*
1260 * Validate the config.
1261 */
1262 if (!CFGMR3AreValuesValid(pCfg,
1263 "Network\0"
1264 "Trunk\0"
1265 "TrunkType\0"
1266 "ReceiveBufferSize\0"
1267 "SendBufferSize\0"
1268 "RestrictAccess\0"
1269 "SharedMacOnWire\0"
1270 "IgnoreAllPromisc\0"
1271 "QuietlyIgnoreAllPromisc\0"
1272 "IgnoreClientPromisc\0"
1273 "QuietlyIgnoreClientPromisc\0"
1274 "IgnoreTrunkWirePromisc\0"
1275 "QuietlyIgnoreTrunkWirePromisc\0"
1276 "IgnoreTrunkHostPromisc\0"
1277 "QuietlyIgnoreTrunkHostPromisc\0"
1278 "IsService\0"))
1279 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
1280
1281 /*
1282 * Check that no-one is attached to us.
1283 */
1284 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
1285 ("Configuration error: Not possible to attach anything to this driver!\n"),
1286 VERR_PDM_DRVINS_NO_ATTACH);
1287
1288 /*
1289 * Query the network port interface.
1290 */
1291 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
1292 if (!pThis->pIAboveNet)
1293 {
1294 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
1295 return VERR_PDM_MISSING_INTERFACE_ABOVE;
1296 }
1297 pThis->pIAboveConfigR3 = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
1298
1299 /*
1300 * Read the configuration.
1301 */
1302 INTNETOPENREQ OpenReq;
1303 memset(&OpenReq, 0, sizeof(OpenReq));
1304 OpenReq.Hdr.cbReq = sizeof(OpenReq);
1305 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1306 OpenReq.pSession = NIL_RTR0PTR;
1307
1308 /** @cfgm{Network, string}
1309 * The name of the internal network to connect to.
1310 */
1311 int rc = CFGMR3QueryString(pCfg, "Network", OpenReq.szNetwork, sizeof(OpenReq.szNetwork));
1312 if (RT_FAILURE(rc))
1313 return PDMDRV_SET_ERROR(pDrvIns, rc,
1314 N_("Configuration error: Failed to get the \"Network\" value"));
1315 strcpy(pThis->szNetwork, OpenReq.szNetwork);
1316
1317 /** @cfgm{TrunkType, uint32_t, kIntNetTrunkType_None}
1318 * The trunk connection type see INTNETTRUNKTYPE.
1319 */
1320 uint32_t u32TrunkType;
1321 rc = CFGMR3QueryU32(pCfg, "TrunkType", &u32TrunkType);
1322 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1323 u32TrunkType = kIntNetTrunkType_None;
1324 else if (RT_FAILURE(rc))
1325 return PDMDRV_SET_ERROR(pDrvIns, rc,
1326 N_("Configuration error: Failed to get the \"TrunkType\" value"));
1327 OpenReq.enmTrunkType = (INTNETTRUNKTYPE)u32TrunkType;
1328
1329 /** @cfgm{Trunk, string, ""}
1330 * The name of the trunk connection.
1331 */
1332 rc = CFGMR3QueryString(pCfg, "Trunk", OpenReq.szTrunk, sizeof(OpenReq.szTrunk));
1333 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1334 OpenReq.szTrunk[0] = '\0';
1335 else if (RT_FAILURE(rc))
1336 return PDMDRV_SET_ERROR(pDrvIns, rc,
1337 N_("Configuration error: Failed to get the \"Trunk\" value"));
1338
1339 /** @cfgm{RestrictAccess, boolean, true}
1340 * Whether to restrict the access to the network or if it should be public. Everyone on
1341 * the computer can connect to a public network. Don't change this.
1342 */
1343 bool fRestrictAccess;
1344 rc = CFGMR3QueryBool(pCfg, "RestrictAccess", &fRestrictAccess);
1345 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1346 fRestrictAccess = true;
1347 else if (RT_FAILURE(rc))
1348 return PDMDRV_SET_ERROR(pDrvIns, rc,
1349 N_("Configuration error: Failed to get the \"RestrictAccess\" value"));
1350 OpenReq.fFlags = fRestrictAccess ? 0 : INTNET_OPEN_FLAGS_PUBLIC;
1351
1352 /** @cfgm{IgnoreAllPromisc, boolean, false}
1353 * When set all request for operating any interface or trunk in promiscuous
1354 * mode will be ignored. */
1355 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreAllPromisc", &f, false);
1356 if (RT_FAILURE(rc))
1357 return PDMDRV_SET_ERROR(pDrvIns, rc,
1358 N_("Configuration error: Failed to get the \"IgnoreAllPromisc\" value"));
1359 if (f)
1360 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC;
1361
1362 /** @cfgm{QuietlyIgnoreAllPromisc, boolean, false}
1363 * When set all request for operating any interface or trunk in promiscuous
1364 * mode will be ignored. This differs from IgnoreAllPromisc in that clients
1365 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1366 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreAllPromisc", &f, false);
1367 if (RT_FAILURE(rc))
1368 return PDMDRV_SET_ERROR(pDrvIns, rc,
1369 N_("Configuration error: Failed to get the \"QuietlyIgnoreAllPromisc\" value"));
1370 if (f)
1371 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC;
1372
1373 /** @cfgm{IgnoreClientPromisc, boolean, false}
1374 * When set all request for operating any non-trunk interface in promiscuous
1375 * mode will be ignored. */
1376 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreClientPromisc", &f, false);
1377 if (RT_FAILURE(rc))
1378 return PDMDRV_SET_ERROR(pDrvIns, rc,
1379 N_("Configuration error: Failed to get the \"IgnoreClientPromisc\" value"));
1380 if (f)
1381 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC; /** @todo add special flag for this. */
1382
1383 /** @cfgm{QuietlyIgnoreClientPromisc, boolean, false}
1384 * When set all request for operating any non-trunk interface promiscuous mode
1385 * will be ignored. This differs from IgnoreClientPromisc in that clients won't
1386 * get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1387 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreClientPromisc", &f, false);
1388 if (RT_FAILURE(rc))
1389 return PDMDRV_SET_ERROR(pDrvIns, rc,
1390 N_("Configuration error: Failed to get the \"QuietlyIgnoreClientPromisc\" value"));
1391 if (f)
1392 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC; /** @todo add special flag for this. */
1393
1394 /** @cfgm{IgnoreTrunkWirePromisc, boolean, false}
1395 * When set all request for operating the trunk-wire connection in promiscuous
1396 * mode will be ignored. */
1397 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreTrunkWirePromisc", &f, false);
1398 if (RT_FAILURE(rc))
1399 return PDMDRV_SET_ERROR(pDrvIns, rc,
1400 N_("Configuration error: Failed to get the \"IgnoreTrunkWirePromisc\" value"));
1401 if (f)
1402 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE;
1403
1404 /** @cfgm{QuietlyIgnoreTrunkWirePromisc, boolean, false}
1405 * When set all request for operating any trunk-wire connection promiscuous mode
1406 * will be ignored. This differs from IgnoreTrunkWirePromisc in that clients
1407 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1408 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreTrunkWirePromisc", &f, false);
1409 if (RT_FAILURE(rc))
1410 return PDMDRV_SET_ERROR(pDrvIns, rc,
1411 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkWirePromisc\" value"));
1412 if (f)
1413 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE;
1414
1415 /** @cfgm{IgnoreTrunkHostPromisc, boolean, false}
1416 * When set all request for operating the trunk-host connection in promiscuous
1417 * mode will be ignored. */
1418 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreTrunkHostPromisc", &f, false);
1419 if (RT_FAILURE(rc))
1420 return PDMDRV_SET_ERROR(pDrvIns, rc,
1421 N_("Configuration error: Failed to get the \"IgnoreTrunkHostPromisc\" value"));
1422 if (f)
1423 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST;
1424
1425 /** @cfgm{QuietlyIgnoreTrunkHostPromisc, boolean, false}
1426 * When set all request for operating any trunk-host connection promiscuous mode
1427 * will be ignored. This differs from IgnoreTrunkHostPromisc in that clients
1428 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1429 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreTrunkHostPromisc", &f, false);
1430 if (RT_FAILURE(rc))
1431 return PDMDRV_SET_ERROR(pDrvIns, rc,
1432 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkHostPromisc\" value"));
1433 if (f)
1434 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST;
1435
1436 /** @todo flags for not sending to the host and for setting the trunk-wire
1437 * connection in promiscuous mode. */
1438
1439
1440 /** @cfgm{SharedMacOnWire, boolean, false}
1441 * Whether to shared the MAC address of the host interface when using the wire. When
1442 * attaching to a wireless NIC this option is usually a requirement.
1443 */
1444 bool fSharedMacOnWire;
1445 rc = CFGMR3QueryBoolDef(pCfg, "SharedMacOnWire", &fSharedMacOnWire, false);
1446 if (RT_FAILURE(rc))
1447 return PDMDRV_SET_ERROR(pDrvIns, rc,
1448 N_("Configuration error: Failed to get the \"SharedMacOnWire\" value"));
1449 if (fSharedMacOnWire)
1450 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1451
1452 /** @cfgm{ReceiveBufferSize, uint32_t, 318 KB}
1453 * The size of the receive buffer.
1454 */
1455 rc = CFGMR3QueryU32(pCfg, "ReceiveBufferSize", &OpenReq.cbRecv);
1456 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1457 OpenReq.cbRecv = 318 * _1K ;
1458 else if (RT_FAILURE(rc))
1459 return PDMDRV_SET_ERROR(pDrvIns, rc,
1460 N_("Configuration error: Failed to get the \"ReceiveBufferSize\" value"));
1461
1462 /** @cfgm{SendBufferSize, uint32_t, 196 KB}
1463 * The size of the send (transmit) buffer.
1464 * This should be more than twice the size of the larges frame size because
1465 * the ring buffer is very simple and doesn't support splitting up frames
1466 * nor inserting padding. So, if this is too close to the frame size the
1467 * header will fragment the buffer such that the frame won't fit on either
1468 * side of it and the code will get very upset about it all.
1469 */
1470 rc = CFGMR3QueryU32(pCfg, "SendBufferSize", &OpenReq.cbSend);
1471 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1472 OpenReq.cbSend = RT_ALIGN_Z(VBOX_MAX_GSO_SIZE * 3, _1K);
1473 else if (RT_FAILURE(rc))
1474 return PDMDRV_SET_ERROR(pDrvIns, rc,
1475 N_("Configuration error: Failed to get the \"SendBufferSize\" value"));
1476 if (OpenReq.cbSend < 128)
1477 return PDMDRV_SET_ERROR(pDrvIns, rc,
1478 N_("Configuration error: The \"SendBufferSize\" value is too small"));
1479 if (OpenReq.cbSend < VBOX_MAX_GSO_SIZE * 3)
1480 LogRel(("DrvIntNet: Warning! SendBufferSize=%u, Recommended minimum size %u butes.\n", OpenReq.cbSend, VBOX_MAX_GSO_SIZE * 4));
1481
1482 /** @cfgm{IsService, boolean, true}
1483 * This alterns the way the thread is suspended and resumed. When it's being used by
1484 * a service such as LWIP/iSCSI it shouldn't suspend immediately like for a NIC.
1485 */
1486 rc = CFGMR3QueryBool(pCfg, "IsService", &pThis->fActivateEarlyDeactivateLate);
1487 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1488 pThis->fActivateEarlyDeactivateLate = false;
1489 else if (RT_FAILURE(rc))
1490 return PDMDRV_SET_ERROR(pDrvIns, rc,
1491 N_("Configuration error: Failed to get the \"IsService\" value"));
1492
1493 LogRel(("IntNet#%u: szNetwork={%s} enmTrunkType=%d szTrunk={%s} fFlags=%#x cbRecv=%u cbSend=%u\n",
1494 pDrvIns->iInstance, OpenReq.szNetwork, OpenReq.enmTrunkType, OpenReq.szTrunk, OpenReq.fFlags,
1495 OpenReq.cbRecv, OpenReq.cbSend));
1496
1497#ifdef RT_OS_DARWIN
1498 /* Temporary hack: attach to a network with the name 'if=en0' and you're hitting the wire. */
1499 if ( !OpenReq.szTrunk[0]
1500 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1501 && !strncmp(pThis->szNetwork, "if=en", sizeof("if=en") - 1)
1502 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("if=en") - 1])
1503 && !pThis->szNetwork[sizeof("if=en")])
1504 {
1505 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1506 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("if=") - 1]);
1507 }
1508 /* Temporary hack: attach to a network with the name 'wif=en0' and you're on the air. */
1509 if ( !OpenReq.szTrunk[0]
1510 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1511 && !strncmp(pThis->szNetwork, "wif=en", sizeof("wif=en") - 1)
1512 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("wif=en") - 1])
1513 && !pThis->szNetwork[sizeof("wif=en")])
1514 {
1515 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1516 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1517 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("wif=") - 1]);
1518 }
1519#endif /* DARWIN */
1520
1521 /*
1522 * Create the event semaphore, S/G cache and xmit critsect.
1523 */
1524 rc = RTSemEventCreate(&pThis->hRecvEvt);
1525 if (RT_FAILURE(rc))
1526 return rc;
1527 rc = RTMemCacheCreate(&pThis->hSgCache, sizeof(PDMSCATTERGATHER), 0, UINT32_MAX, NULL, NULL, pThis, 0);
1528 if (RT_FAILURE(rc))
1529 return rc;
1530 rc = PDMDrvHlpCritSectInit(pDrvIns, &pThis->XmitLock, RT_SRC_POS, "IntNetXmit");
1531 if (RT_FAILURE(rc))
1532 return rc;
1533
1534 /*
1535 * Create the interface.
1536 */
1537 OpenReq.hIf = INTNET_HANDLE_INVALID;
1538 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_OPEN, &OpenReq, sizeof(OpenReq));
1539 if (RT_FAILURE(rc))
1540 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1541 N_("Failed to open/create the internal network '%s'"), pThis->szNetwork);
1542 AssertRelease(OpenReq.hIf != INTNET_HANDLE_INVALID);
1543 pThis->hIf = OpenReq.hIf;
1544 Log(("IntNet%d: hIf=%RX32 '%s'\n", pDrvIns->iInstance, pThis->hIf, pThis->szNetwork));
1545
1546 /*
1547 * Get default buffer.
1548 */
1549 INTNETIFGETBUFFERPTRSREQ GetBufferPtrsReq;
1550 GetBufferPtrsReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1551 GetBufferPtrsReq.Hdr.cbReq = sizeof(GetBufferPtrsReq);
1552 GetBufferPtrsReq.pSession = NIL_RTR0PTR;
1553 GetBufferPtrsReq.hIf = pThis->hIf;
1554 GetBufferPtrsReq.pRing3Buf = NULL;
1555 GetBufferPtrsReq.pRing0Buf = NIL_RTR0PTR;
1556 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, &GetBufferPtrsReq, sizeof(GetBufferPtrsReq));
1557 if (RT_FAILURE(rc))
1558 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1559 N_("Failed to get ring-3 buffer for the newly created interface to '%s'"), pThis->szNetwork);
1560 AssertRelease(VALID_PTR(GetBufferPtrsReq.pRing3Buf));
1561 pThis->pBufR3 = GetBufferPtrsReq.pRing3Buf;
1562 pThis->pBufR0 = GetBufferPtrsReq.pRing0Buf;
1563
1564 /*
1565 * Register statistics.
1566 */
1567 PDMDrvHlpSTAMRegCounterEx(pDrvIns, &pThis->pBufR3->Recv.cbStatWritten, "Bytes/Received", STAMUNIT_BYTES, "Number of received bytes.");
1568 PDMDrvHlpSTAMRegCounterEx(pDrvIns, &pThis->pBufR3->Send.cbStatWritten, "Bytes/Sent", STAMUNIT_BYTES, "Number of sent bytes.");
1569 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Recv.cOverflows, "Overflows/Recv", "Number overflows.");
1570 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Send.cOverflows, "Overflows/Sent", "Number overflows.");
1571 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Recv.cStatFrames, "Packets/Received", "Number of received packets.");
1572 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Send.cStatFrames, "Packets/Sent", "Number of sent packets.");
1573 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatReceivedGso, "Packets/Received-Gso", "The GSO portion of the received packets.");
1574 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatSentGso, "Packets/Sent-Gso", "The GSO portion of the sent packets.");
1575 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatSentR0, "Packets/Sent-R0", "The ring-0 portion of the sent packets.");
1576
1577 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatLost, "Packets/Lost", "Number of lost packets.");
1578 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatYieldsNok, "YieldOk", "Number of times yielding helped fix an overflow.");
1579 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatYieldsOk, "YieldNok", "Number of times yielding didn't help fix an overflow.");
1580 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatBadFrames, "BadFrames", "Number of bad frames seed by the consumers.");
1581 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->pBufR3->StatSend1, "Send1", "Profiling IntNetR0IfSend.");
1582 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->pBufR3->StatSend2, "Send2", "Profiling sending to the trunk.");
1583 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->pBufR3->StatRecv1, "Recv1", "Reserved for future receive profiling.");
1584 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->pBufR3->StatRecv2, "Recv2", "Reserved for future receive profiling.");
1585 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->pBufR3->StatReserved, "Reserved", "Reserved for future use.");
1586#ifdef VBOX_WITH_STATISTICS
1587 PDMDrvHlpSTAMRegProfileAdv(pDrvIns, &pThis->StatReceive, "Receive", "Profiling packet receive runs.");
1588 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->StatTransmit, "Transmit", "Profiling packet transmit runs.");
1589#endif
1590 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatXmitWakeupR0, "XmitWakeup-R0", "Xmit thread wakeups from ring-0.");
1591 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatXmitWakeupR3, "XmitWakeup-R3", "Xmit thread wakeups from ring-3.");
1592 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatXmitProcessRing, "XmitProcessRing", "Time xmit thread was told to process the ring.");
1593
1594 /*
1595 * Create the async I/O threads.
1596 * Note! Using a PDM thread here doesn't fit with the IsService=true operation.
1597 */
1598 rc = RTThreadCreate(&pThis->hRecvThread, drvR3IntNetRecvThread, pThis, 0,
1599 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET-RECV");
1600 if (RT_FAILURE(rc))
1601 {
1602 AssertRC(rc);
1603 return rc;
1604 }
1605
1606 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pThis->hXmitEvt);
1607 AssertRCReturn(rc, rc);
1608
1609 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pXmitThread, pThis,
1610 drvR3IntNetXmitThread, drvR3IntNetXmitWakeUp, 0, RTTHREADTYPE_IO, "INTNET-XMIT");
1611 AssertRCReturn(rc, rc);
1612
1613#ifdef VBOX_WITH_DRVINTNET_IN_R0
1614 /*
1615 * Resolve the ring-0 context interface addresses.
1616 */
1617 rc = pDrvIns->pHlpR3->pfnLdrGetR0InterfaceSymbols(pDrvIns, &pThis->INetworkUpR0, sizeof(pThis->INetworkUpR0),
1618 "drvIntNetUp_", PDMINETWORKUP_SYM_LIST);
1619 AssertLogRelRCReturn(rc, rc);
1620#endif
1621
1622 /*
1623 * Activate data transmission as early as possible
1624 */
1625 if (pThis->fActivateEarlyDeactivateLate)
1626 {
1627 ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_RUNNING);
1628 RTSemEventSignal(pThis->hRecvEvt);
1629
1630 drvR3IntNetUpdateMacAddress(pThis);
1631 drvR3IntNetSetActive(pThis, true /* fActive */);
1632 }
1633
1634 return rc;
1635}
1636
1637
1638
1639/**
1640 * Internal networking transport driver registration record.
1641 */
1642const PDMDRVREG g_DrvIntNet =
1643{
1644 /* u32Version */
1645 PDM_DRVREG_VERSION,
1646 /* szName */
1647 "IntNet",
1648 /* szRCMod */
1649 "VBoxDDGC.rc",
1650 /* szR0Mod */
1651 "VBoxDDR0.r0",
1652 /* pszDescription */
1653 "Internal Networking Transport Driver",
1654 /* fFlags */
1655#ifdef VBOX_WITH_DRVINTNET_IN_R0
1656 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DRVREG_FLAGS_R0,
1657#else
1658 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1659#endif
1660 /* fClass. */
1661 PDM_DRVREG_CLASS_NETWORK,
1662 /* cMaxInstances */
1663 ~0,
1664 /* cbInstance */
1665 sizeof(DRVINTNET),
1666 /* pfnConstruct */
1667 drvR3IntNetConstruct,
1668 /* pfnDestruct */
1669 drvR3IntNetDestruct,
1670 /* pfnRelocate */
1671 drvR3IntNetRelocate,
1672 /* pfnIOCtl */
1673 NULL,
1674 /* pfnPowerOn */
1675 drvR3IntNetPowerOn,
1676 /* pfnReset */
1677 NULL,
1678 /* pfnSuspend */
1679 drvR3IntNetSuspend,
1680 /* pfnResume */
1681 drvR3IntNetResume,
1682 /* pfnAttach */
1683 NULL,
1684 /* pfnDetach */
1685 NULL,
1686 /* pfnPowerOff */
1687 drvR3IntNetPowerOff,
1688 /* pfnSoftReset */
1689 NULL,
1690 /* u32EndVersion */
1691 PDM_DRVREG_VERSION
1692};
1693
1694#endif /* IN_RING3 */
1695
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