VirtualBox

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

Last change on this file since 35951 was 35353, checked in by vboxsync, 14 years ago

Move the misc files the in src/VBox/Devices/ directory into a build/ subdirectory, changing their names to match the target module.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 66.1 KB
Line 
1/* $Id: DrvIntNet.cpp 35353 2010-12-27 17:25:52Z 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/vmm/pdmdrv.h>
23#include <VBox/vmm/pdmnetinline.h>
24#include <VBox/vmm/pdmnetifs.h>
25#include <VBox/vmm/cfgm.h>
26#include <VBox/intnet.h>
27#include <VBox/intnetinline.h>
28#include <VBox/vmm/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 "VBoxDD.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 bool fIgnoreConnectFailure;
1229 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1230
1231 /*
1232 * Init the static parts.
1233 */
1234 pThis->pDrvInsR3 = pDrvIns;
1235#ifdef VBOX_WITH_DRVINTNET_IN_R0
1236 pThis->pDrvInsR0 = PDMDRVINS_2_R0PTR(pDrvIns);
1237#endif
1238 pThis->hIf = INTNET_HANDLE_INVALID;
1239 pThis->hRecvThread = NIL_RTTHREAD;
1240 pThis->hRecvEvt = NIL_RTSEMEVENT;
1241 pThis->pXmitThread = NULL;
1242 pThis->hXmitEvt = NIL_SUPSEMEVENT;
1243 pThis->pSupDrvSession = PDMDrvHlpGetSupDrvSession(pDrvIns);
1244 pThis->hSgCache = NIL_RTMEMCACHE;
1245 pThis->enmRecvState = RECVSTATE_SUSPENDED;
1246 pThis->fActivateEarlyDeactivateLate = false;
1247 /* IBase* */
1248 pDrvIns->IBase.pfnQueryInterface = drvR3IntNetIBase_QueryInterface;
1249 pThis->IBaseR0.pfnQueryInterface = drvR3IntNetIBaseR0_QueryInterface;
1250 pThis->IBaseRC.pfnQueryInterface = drvR3IntNetIBaseRC_QueryInterface;
1251 /* INetworkUp */
1252 pThis->INetworkUpR3.pfnBeginXmit = drvIntNetUp_BeginXmit;
1253 pThis->INetworkUpR3.pfnAllocBuf = drvIntNetUp_AllocBuf;
1254 pThis->INetworkUpR3.pfnFreeBuf = drvIntNetUp_FreeBuf;
1255 pThis->INetworkUpR3.pfnSendBuf = drvIntNetUp_SendBuf;
1256 pThis->INetworkUpR3.pfnEndXmit = drvIntNetUp_EndXmit;
1257 pThis->INetworkUpR3.pfnSetPromiscuousMode = drvIntNetUp_SetPromiscuousMode;
1258 pThis->INetworkUpR3.pfnNotifyLinkChanged = drvR3IntNetUp_NotifyLinkChanged;
1259
1260 /*
1261 * Validate the config.
1262 */
1263 if (!CFGMR3AreValuesValid(pCfg,
1264 "Network\0"
1265 "Trunk\0"
1266 "TrunkType\0"
1267 "ReceiveBufferSize\0"
1268 "SendBufferSize\0"
1269 "RestrictAccess\0"
1270 "SharedMacOnWire\0"
1271 "IgnoreAllPromisc\0"
1272 "QuietlyIgnoreAllPromisc\0"
1273 "IgnoreClientPromisc\0"
1274 "QuietlyIgnoreClientPromisc\0"
1275 "IgnoreTrunkWirePromisc\0"
1276 "QuietlyIgnoreTrunkWirePromisc\0"
1277 "IgnoreTrunkHostPromisc\0"
1278 "IgnoreConnectFailure\0"
1279 "QuietlyIgnoreTrunkHostPromisc\0"
1280 "IsService\0"))
1281 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
1282
1283 /*
1284 * Check that no-one is attached to us.
1285 */
1286 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
1287 ("Configuration error: Not possible to attach anything to this driver!\n"),
1288 VERR_PDM_DRVINS_NO_ATTACH);
1289
1290 /*
1291 * Query the network port interface.
1292 */
1293 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
1294 if (!pThis->pIAboveNet)
1295 {
1296 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
1297 return VERR_PDM_MISSING_INTERFACE_ABOVE;
1298 }
1299 pThis->pIAboveConfigR3 = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
1300
1301 /*
1302 * Read the configuration.
1303 */
1304 INTNETOPENREQ OpenReq;
1305 memset(&OpenReq, 0, sizeof(OpenReq));
1306 OpenReq.Hdr.cbReq = sizeof(OpenReq);
1307 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1308 OpenReq.pSession = NIL_RTR0PTR;
1309
1310 /** @cfgm{Network, string}
1311 * The name of the internal network to connect to.
1312 */
1313 int rc = CFGMR3QueryString(pCfg, "Network", OpenReq.szNetwork, sizeof(OpenReq.szNetwork));
1314 if (RT_FAILURE(rc))
1315 return PDMDRV_SET_ERROR(pDrvIns, rc,
1316 N_("Configuration error: Failed to get the \"Network\" value"));
1317 strcpy(pThis->szNetwork, OpenReq.szNetwork);
1318
1319 /** @cfgm{TrunkType, uint32_t, kIntNetTrunkType_None}
1320 * The trunk connection type see INTNETTRUNKTYPE.
1321 */
1322 uint32_t u32TrunkType;
1323 rc = CFGMR3QueryU32(pCfg, "TrunkType", &u32TrunkType);
1324 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1325 u32TrunkType = kIntNetTrunkType_None;
1326 else if (RT_FAILURE(rc))
1327 return PDMDRV_SET_ERROR(pDrvIns, rc,
1328 N_("Configuration error: Failed to get the \"TrunkType\" value"));
1329 OpenReq.enmTrunkType = (INTNETTRUNKTYPE)u32TrunkType;
1330
1331 /** @cfgm{Trunk, string, ""}
1332 * The name of the trunk connection.
1333 */
1334 rc = CFGMR3QueryString(pCfg, "Trunk", OpenReq.szTrunk, sizeof(OpenReq.szTrunk));
1335 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1336 OpenReq.szTrunk[0] = '\0';
1337 else if (RT_FAILURE(rc))
1338 return PDMDRV_SET_ERROR(pDrvIns, rc,
1339 N_("Configuration error: Failed to get the \"Trunk\" value"));
1340
1341 /** @cfgm{RestrictAccess, boolean, true}
1342 * Whether to restrict the access to the network or if it should be public. Everyone on
1343 * the computer can connect to a public network. Don't change this.
1344 */
1345 bool fRestrictAccess;
1346 rc = CFGMR3QueryBool(pCfg, "RestrictAccess", &fRestrictAccess);
1347 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1348 fRestrictAccess = true;
1349 else if (RT_FAILURE(rc))
1350 return PDMDRV_SET_ERROR(pDrvIns, rc,
1351 N_("Configuration error: Failed to get the \"RestrictAccess\" value"));
1352 OpenReq.fFlags = fRestrictAccess ? 0 : INTNET_OPEN_FLAGS_PUBLIC;
1353
1354 /** @cfgm{IgnoreAllPromisc, boolean, false}
1355 * When set all request for operating any interface or trunk in promiscuous
1356 * mode will be ignored. */
1357 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreAllPromisc", &f, false);
1358 if (RT_FAILURE(rc))
1359 return PDMDRV_SET_ERROR(pDrvIns, rc,
1360 N_("Configuration error: Failed to get the \"IgnoreAllPromisc\" value"));
1361 if (f)
1362 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC;
1363
1364 /** @cfgm{QuietlyIgnoreAllPromisc, boolean, false}
1365 * When set all request for operating any interface or trunk in promiscuous
1366 * mode will be ignored. This differs from IgnoreAllPromisc in that clients
1367 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1368 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreAllPromisc", &f, false);
1369 if (RT_FAILURE(rc))
1370 return PDMDRV_SET_ERROR(pDrvIns, rc,
1371 N_("Configuration error: Failed to get the \"QuietlyIgnoreAllPromisc\" value"));
1372 if (f)
1373 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC;
1374
1375 /** @cfgm{IgnoreClientPromisc, boolean, false}
1376 * When set all request for operating any non-trunk interface in promiscuous
1377 * mode will be ignored. */
1378 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreClientPromisc", &f, false);
1379 if (RT_FAILURE(rc))
1380 return PDMDRV_SET_ERROR(pDrvIns, rc,
1381 N_("Configuration error: Failed to get the \"IgnoreClientPromisc\" value"));
1382 if (f)
1383 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC; /** @todo add special flag for this. */
1384
1385 /** @cfgm{QuietlyIgnoreClientPromisc, boolean, false}
1386 * When set all request for operating any non-trunk interface promiscuous mode
1387 * will be ignored. This differs from IgnoreClientPromisc in that clients won't
1388 * get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1389 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreClientPromisc", &f, false);
1390 if (RT_FAILURE(rc))
1391 return PDMDRV_SET_ERROR(pDrvIns, rc,
1392 N_("Configuration error: Failed to get the \"QuietlyIgnoreClientPromisc\" value"));
1393 if (f)
1394 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC; /** @todo add special flag for this. */
1395
1396 /** @cfgm{IgnoreTrunkWirePromisc, boolean, false}
1397 * When set all request for operating the trunk-wire connection in promiscuous
1398 * mode will be ignored. */
1399 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreTrunkWirePromisc", &f, false);
1400 if (RT_FAILURE(rc))
1401 return PDMDRV_SET_ERROR(pDrvIns, rc,
1402 N_("Configuration error: Failed to get the \"IgnoreTrunkWirePromisc\" value"));
1403 if (f)
1404 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE;
1405
1406 /** @cfgm{QuietlyIgnoreTrunkWirePromisc, boolean, false}
1407 * When set all request for operating any trunk-wire connection promiscuous mode
1408 * will be ignored. This differs from IgnoreTrunkWirePromisc in that clients
1409 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1410 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreTrunkWirePromisc", &f, false);
1411 if (RT_FAILURE(rc))
1412 return PDMDRV_SET_ERROR(pDrvIns, rc,
1413 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkWirePromisc\" value"));
1414 if (f)
1415 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE;
1416
1417 /** @cfgm{IgnoreTrunkHostPromisc, boolean, false}
1418 * When set all request for operating the trunk-host connection in promiscuous
1419 * mode will be ignored. */
1420 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreTrunkHostPromisc", &f, false);
1421 if (RT_FAILURE(rc))
1422 return PDMDRV_SET_ERROR(pDrvIns, rc,
1423 N_("Configuration error: Failed to get the \"IgnoreTrunkHostPromisc\" value"));
1424 if (f)
1425 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST;
1426
1427 /** @cfgm{QuietlyIgnoreTrunkHostPromisc, boolean, false}
1428 * When set all request for operating any trunk-host connection promiscuous mode
1429 * will be ignored. This differs from IgnoreTrunkHostPromisc in that clients
1430 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1431 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreTrunkHostPromisc", &f, false);
1432 if (RT_FAILURE(rc))
1433 return PDMDRV_SET_ERROR(pDrvIns, rc,
1434 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkHostPromisc\" value"));
1435 if (f)
1436 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST;
1437
1438 /** @todo flags for not sending to the host and for setting the trunk-wire
1439 * connection in promiscuous mode. */
1440
1441
1442 /** @cfgm{IgnoreConnectFailure, boolean, false}
1443 * When set only raise a runtime error if we cannot connect to the internal
1444 * network. */
1445 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreConnectFailure", &fIgnoreConnectFailure, false);
1446 if (RT_FAILURE(rc))
1447 return PDMDRV_SET_ERROR(pDrvIns, rc,
1448 N_("Configuration error: Failed to get the \"IgnoreConnectFailure\" value"));
1449 if (f)
1450 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC;
1451
1452
1453 /** @cfgm{SharedMacOnWire, boolean, false}
1454 * Whether to shared the MAC address of the host interface when using the wire. When
1455 * attaching to a wireless NIC this option is usually a requirement.
1456 */
1457 bool fSharedMacOnWire;
1458 rc = CFGMR3QueryBoolDef(pCfg, "SharedMacOnWire", &fSharedMacOnWire, false);
1459 if (RT_FAILURE(rc))
1460 return PDMDRV_SET_ERROR(pDrvIns, rc,
1461 N_("Configuration error: Failed to get the \"SharedMacOnWire\" value"));
1462 if (fSharedMacOnWire)
1463 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1464
1465 /** @cfgm{ReceiveBufferSize, uint32_t, 318 KB}
1466 * The size of the receive buffer.
1467 */
1468 rc = CFGMR3QueryU32(pCfg, "ReceiveBufferSize", &OpenReq.cbRecv);
1469 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1470 OpenReq.cbRecv = 318 * _1K ;
1471 else if (RT_FAILURE(rc))
1472 return PDMDRV_SET_ERROR(pDrvIns, rc,
1473 N_("Configuration error: Failed to get the \"ReceiveBufferSize\" value"));
1474
1475 /** @cfgm{SendBufferSize, uint32_t, 196 KB}
1476 * The size of the send (transmit) buffer.
1477 * This should be more than twice the size of the larges frame size because
1478 * the ring buffer is very simple and doesn't support splitting up frames
1479 * nor inserting padding. So, if this is too close to the frame size the
1480 * header will fragment the buffer such that the frame won't fit on either
1481 * side of it and the code will get very upset about it all.
1482 */
1483 rc = CFGMR3QueryU32(pCfg, "SendBufferSize", &OpenReq.cbSend);
1484 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1485 OpenReq.cbSend = RT_ALIGN_Z(VBOX_MAX_GSO_SIZE * 3, _1K);
1486 else if (RT_FAILURE(rc))
1487 return PDMDRV_SET_ERROR(pDrvIns, rc,
1488 N_("Configuration error: Failed to get the \"SendBufferSize\" value"));
1489 if (OpenReq.cbSend < 128)
1490 return PDMDRV_SET_ERROR(pDrvIns, rc,
1491 N_("Configuration error: The \"SendBufferSize\" value is too small"));
1492 if (OpenReq.cbSend < VBOX_MAX_GSO_SIZE * 3)
1493 LogRel(("DrvIntNet: Warning! SendBufferSize=%u, Recommended minimum size %u butes.\n", OpenReq.cbSend, VBOX_MAX_GSO_SIZE * 4));
1494
1495 /** @cfgm{IsService, boolean, true}
1496 * This alterns the way the thread is suspended and resumed. When it's being used by
1497 * a service such as LWIP/iSCSI it shouldn't suspend immediately like for a NIC.
1498 */
1499 rc = CFGMR3QueryBool(pCfg, "IsService", &pThis->fActivateEarlyDeactivateLate);
1500 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1501 pThis->fActivateEarlyDeactivateLate = false;
1502 else if (RT_FAILURE(rc))
1503 return PDMDRV_SET_ERROR(pDrvIns, rc,
1504 N_("Configuration error: Failed to get the \"IsService\" value"));
1505
1506 LogRel(("IntNet#%u: szNetwork={%s} enmTrunkType=%d szTrunk={%s} fFlags=%#x cbRecv=%u cbSend=%u\n",
1507 pDrvIns->iInstance, OpenReq.szNetwork, OpenReq.enmTrunkType, OpenReq.szTrunk, OpenReq.fFlags,
1508 OpenReq.cbRecv, OpenReq.cbSend));
1509
1510#ifdef RT_OS_DARWIN
1511 /* Temporary hack: attach to a network with the name 'if=en0' and you're hitting the wire. */
1512 if ( !OpenReq.szTrunk[0]
1513 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1514 && !strncmp(pThis->szNetwork, "if=en", sizeof("if=en") - 1)
1515 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("if=en") - 1])
1516 && !pThis->szNetwork[sizeof("if=en")])
1517 {
1518 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1519 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("if=") - 1]);
1520 }
1521 /* Temporary hack: attach to a network with the name 'wif=en0' and you're on the air. */
1522 if ( !OpenReq.szTrunk[0]
1523 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1524 && !strncmp(pThis->szNetwork, "wif=en", sizeof("wif=en") - 1)
1525 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("wif=en") - 1])
1526 && !pThis->szNetwork[sizeof("wif=en")])
1527 {
1528 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1529 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1530 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("wif=") - 1]);
1531 }
1532#endif /* DARWIN */
1533
1534 /*
1535 * Create the event semaphore, S/G cache and xmit critsect.
1536 */
1537 rc = RTSemEventCreate(&pThis->hRecvEvt);
1538 if (RT_FAILURE(rc))
1539 return rc;
1540 rc = RTMemCacheCreate(&pThis->hSgCache, sizeof(PDMSCATTERGATHER), 0, UINT32_MAX, NULL, NULL, pThis, 0);
1541 if (RT_FAILURE(rc))
1542 return rc;
1543 rc = PDMDrvHlpCritSectInit(pDrvIns, &pThis->XmitLock, RT_SRC_POS, "IntNetXmit");
1544 if (RT_FAILURE(rc))
1545 return rc;
1546
1547 /*
1548 * Create the interface.
1549 */
1550 OpenReq.hIf = INTNET_HANDLE_INVALID;
1551 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_OPEN, &OpenReq, sizeof(OpenReq));
1552 if (RT_FAILURE(rc))
1553 {
1554 if (fIgnoreConnectFailure)
1555 {
1556 /*
1557 * During VM restore it is fatal if the network is not available because the
1558 * VM settings are locked and the user has no chance to fix network settings.
1559 * Therefore don't abort but just raise a runtime warning.
1560 */
1561 PDMDrvHlpVMSetRuntimeError (pDrvIns, 0 /*fFlags*/, "HostIfNotConnecting",
1562 N_ ("Cannot connect to the network interface '%s'. The virtual "
1563 "network card will appear to work but the guest will not "
1564 "be able to connect. Please choose a different network in the "
1565 "network settings"), OpenReq.szTrunk);
1566
1567 return VERR_PDM_NO_ATTACHED_DRIVER;
1568 }
1569 else
1570 {
1571 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1572 N_("Failed to open/create the internal network '%s'"), pThis->szNetwork);
1573 }
1574 }
1575
1576 AssertRelease(OpenReq.hIf != INTNET_HANDLE_INVALID);
1577 pThis->hIf = OpenReq.hIf;
1578 Log(("IntNet%d: hIf=%RX32 '%s'\n", pDrvIns->iInstance, pThis->hIf, pThis->szNetwork));
1579
1580 /*
1581 * Get default buffer.
1582 */
1583 INTNETIFGETBUFFERPTRSREQ GetBufferPtrsReq;
1584 GetBufferPtrsReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1585 GetBufferPtrsReq.Hdr.cbReq = sizeof(GetBufferPtrsReq);
1586 GetBufferPtrsReq.pSession = NIL_RTR0PTR;
1587 GetBufferPtrsReq.hIf = pThis->hIf;
1588 GetBufferPtrsReq.pRing3Buf = NULL;
1589 GetBufferPtrsReq.pRing0Buf = NIL_RTR0PTR;
1590 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, &GetBufferPtrsReq, sizeof(GetBufferPtrsReq));
1591 if (RT_FAILURE(rc))
1592 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1593 N_("Failed to get ring-3 buffer for the newly created interface to '%s'"), pThis->szNetwork);
1594 AssertRelease(VALID_PTR(GetBufferPtrsReq.pRing3Buf));
1595 pThis->pBufR3 = GetBufferPtrsReq.pRing3Buf;
1596 pThis->pBufR0 = GetBufferPtrsReq.pRing0Buf;
1597
1598 /*
1599 * Register statistics.
1600 */
1601 PDMDrvHlpSTAMRegCounterEx(pDrvIns, &pThis->pBufR3->Recv.cbStatWritten, "Bytes/Received", STAMUNIT_BYTES, "Number of received bytes.");
1602 PDMDrvHlpSTAMRegCounterEx(pDrvIns, &pThis->pBufR3->Send.cbStatWritten, "Bytes/Sent", STAMUNIT_BYTES, "Number of sent bytes.");
1603 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Recv.cOverflows, "Overflows/Recv", "Number overflows.");
1604 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Send.cOverflows, "Overflows/Sent", "Number overflows.");
1605 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Recv.cStatFrames, "Packets/Received", "Number of received packets.");
1606 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->Send.cStatFrames, "Packets/Sent", "Number of sent packets.");
1607 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatReceivedGso, "Packets/Received-Gso", "The GSO portion of the received packets.");
1608 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatSentGso, "Packets/Sent-Gso", "The GSO portion of the sent packets.");
1609 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatSentR0, "Packets/Sent-R0", "The ring-0 portion of the sent packets.");
1610
1611 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatLost, "Packets/Lost", "Number of lost packets.");
1612 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatYieldsNok, "YieldOk", "Number of times yielding helped fix an overflow.");
1613 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatYieldsOk, "YieldNok", "Number of times yielding didn't help fix an overflow.");
1614 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->pBufR3->cStatBadFrames, "BadFrames", "Number of bad frames seed by the consumers.");
1615 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->pBufR3->StatSend1, "Send1", "Profiling IntNetR0IfSend.");
1616 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->pBufR3->StatSend2, "Send2", "Profiling sending to the trunk.");
1617 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->pBufR3->StatRecv1, "Recv1", "Reserved for future receive profiling.");
1618 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->pBufR3->StatRecv2, "Recv2", "Reserved for future receive profiling.");
1619 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->pBufR3->StatReserved, "Reserved", "Reserved for future use.");
1620#ifdef VBOX_WITH_STATISTICS
1621 PDMDrvHlpSTAMRegProfileAdv(pDrvIns, &pThis->StatReceive, "Receive", "Profiling packet receive runs.");
1622 PDMDrvHlpSTAMRegProfile(pDrvIns, &pThis->StatTransmit, "Transmit", "Profiling packet transmit runs.");
1623#endif
1624 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatXmitWakeupR0, "XmitWakeup-R0", "Xmit thread wakeups from ring-0.");
1625 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatXmitWakeupR3, "XmitWakeup-R3", "Xmit thread wakeups from ring-3.");
1626 PDMDrvHlpSTAMRegCounter(pDrvIns, &pThis->StatXmitProcessRing, "XmitProcessRing", "Time xmit thread was told to process the ring.");
1627
1628 /*
1629 * Create the async I/O threads.
1630 * Note! Using a PDM thread here doesn't fit with the IsService=true operation.
1631 */
1632 rc = RTThreadCreate(&pThis->hRecvThread, drvR3IntNetRecvThread, pThis, 0,
1633 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET-RECV");
1634 if (RT_FAILURE(rc))
1635 {
1636 AssertRC(rc);
1637 return rc;
1638 }
1639
1640 rc = SUPSemEventCreate(pThis->pSupDrvSession, &pThis->hXmitEvt);
1641 AssertRCReturn(rc, rc);
1642
1643 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pXmitThread, pThis,
1644 drvR3IntNetXmitThread, drvR3IntNetXmitWakeUp, 0, RTTHREADTYPE_IO, "INTNET-XMIT");
1645 AssertRCReturn(rc, rc);
1646
1647#ifdef VBOX_WITH_DRVINTNET_IN_R0
1648 /*
1649 * Resolve the ring-0 context interface addresses.
1650 */
1651 rc = pDrvIns->pHlpR3->pfnLdrGetR0InterfaceSymbols(pDrvIns, &pThis->INetworkUpR0, sizeof(pThis->INetworkUpR0),
1652 "drvIntNetUp_", PDMINETWORKUP_SYM_LIST);
1653 AssertLogRelRCReturn(rc, rc);
1654#endif
1655
1656 /*
1657 * Activate data transmission as early as possible
1658 */
1659 if (pThis->fActivateEarlyDeactivateLate)
1660 {
1661 ASMAtomicXchgSize(&pThis->enmRecvState, RECVSTATE_RUNNING);
1662 RTSemEventSignal(pThis->hRecvEvt);
1663
1664 drvR3IntNetUpdateMacAddress(pThis);
1665 drvR3IntNetSetActive(pThis, true /* fActive */);
1666 }
1667
1668 return rc;
1669}
1670
1671
1672
1673/**
1674 * Internal networking transport driver registration record.
1675 */
1676const PDMDRVREG g_DrvIntNet =
1677{
1678 /* u32Version */
1679 PDM_DRVREG_VERSION,
1680 /* szName */
1681 "IntNet",
1682 /* szRCMod */
1683 "VBoxDDGC.rc",
1684 /* szR0Mod */
1685 "VBoxDDR0.r0",
1686 /* pszDescription */
1687 "Internal Networking Transport Driver",
1688 /* fFlags */
1689#ifdef VBOX_WITH_DRVINTNET_IN_R0
1690 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DRVREG_FLAGS_R0,
1691#else
1692 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1693#endif
1694 /* fClass. */
1695 PDM_DRVREG_CLASS_NETWORK,
1696 /* cMaxInstances */
1697 ~0,
1698 /* cbInstance */
1699 sizeof(DRVINTNET),
1700 /* pfnConstruct */
1701 drvR3IntNetConstruct,
1702 /* pfnDestruct */
1703 drvR3IntNetDestruct,
1704 /* pfnRelocate */
1705 drvR3IntNetRelocate,
1706 /* pfnIOCtl */
1707 NULL,
1708 /* pfnPowerOn */
1709 drvR3IntNetPowerOn,
1710 /* pfnReset */
1711 NULL,
1712 /* pfnSuspend */
1713 drvR3IntNetSuspend,
1714 /* pfnResume */
1715 drvR3IntNetResume,
1716 /* pfnAttach */
1717 NULL,
1718 /* pfnDetach */
1719 NULL,
1720 /* pfnPowerOff */
1721 drvR3IntNetPowerOff,
1722 /* pfnSoftReset */
1723 NULL,
1724 /* u32EndVersion */
1725 PDM_DRVREG_VERSION
1726};
1727
1728#endif /* IN_RING3 */
1729
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