VirtualBox

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

Last change on this file since 27973 was 27973, checked in by vboxsync, 15 years ago

PDM,Network/*: GSO preps.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.1 KB
Line 
1/* $Id: DrvIntNet.cpp 27973 2010-04-04 00:33:03Z vboxsync $ */
2/** @file
3 * DrvIntNet - Internal network transport driver.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_DRV_INTNET
26#include <VBox/pdmdrv.h>
27#include <VBox/pdmnetifs.h>
28#include <VBox/cfgm.h>
29#include <VBox/intnet.h>
30#include <VBox/intnetinline.h>
31#include <VBox/vmm.h>
32#include <VBox/err.h>
33
34#include <VBox/log.h>
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/ctype.h>
38#include <iprt/memcache.h>
39#include <iprt/net.h>
40#include <iprt/semaphore.h>
41#include <iprt/string.h>
42#include <iprt/time.h>
43#include <iprt/thread.h>
44#include <iprt/uuid.h>
45
46#include "../Builtins.h"
47
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/**
53 * The state of the asynchronous thread.
54 */
55typedef enum ASYNCSTATE
56{
57 /** The thread is suspended. */
58 ASYNCSTATE_SUSPENDED = 1,
59 /** The thread is running. */
60 ASYNCSTATE_RUNNING,
61 /** The thread must (/has) terminate. */
62 ASYNCSTATE_TERMINATE,
63 /** The usual 32-bit type blowup. */
64 ASYNCSTATE_32BIT_HACK = 0x7fffffff
65} ASYNCSTATE;
66
67/**
68 * Internal networking driver instance data.
69 *
70 * @implements PDMINETWORKUP
71 */
72typedef struct DRVINTNET
73{
74 /** The network interface. */
75 PDMINETWORKUP INetworkUpR3;
76 /** The network interface. */
77 R3PTRTYPE(PPDMINETWORKDOWN) pIAboveNet;
78 /** The network config interface.
79 * Can (in theory at least) be NULL. */
80 R3PTRTYPE(PPDMINETWORKCONFIG) pIAboveConfigR3;
81 /** Pointer to the driver instance. */
82 PPDMDRVINSR3 pDrvInsR3;
83 /** Pointer to the communication buffer. */
84 R3PTRTYPE(PINTNETBUF) pBufR3;
85 /** Interface handle. */
86 INTNETIFHANDLE hIf;
87
88 /** The thread state. */
89 ASYNCSTATE volatile enmState;
90 /** Reader thread. */
91 RTTHREAD Thread;
92 /** Event semaphore the Thread waits on while the VM is suspended. */
93 RTSEMEVENT hEvtSuspended;
94 /** Scatter/gather descriptor cache. */
95 RTMEMCACHE hSgCache;
96 /** Set if the link is down.
97 * When the link is down all incoming packets will be dropped. */
98 bool volatile fLinkDown;
99 /** Set if data transmission should start immediately and deactivate
100 * as late as possible. */
101 bool fActivateEarlyDeactivateLate;
102 /** Padding. */
103 bool afReserved[2];
104 /** The network name. */
105 char szNetwork[INTNET_MAX_NETWORK_NAME];
106
107 /** Base interface for ring-0. */
108 PDMIBASER0 IBaseR0;
109 /** Base interface for ring-0. */
110 PDMIBASERC IBaseRC;
111
112#ifdef LOG_ENABLED
113 /** The nano ts of the last transfer. */
114 uint64_t u64LastTransferTS;
115 /** The nano ts of the last receive. */
116 uint64_t u64LastReceiveTS;
117#endif
118#ifdef VBOX_WITH_STATISTICS
119 /** Profiling packet transmit runs. */
120 STAMPROFILE StatTransmit;
121 /** Profiling packet receive runs. */
122 STAMPROFILEADV StatReceive;
123#endif /* VBOX_WITH_STATISTICS */
124} DRVINTNET;
125/** Pointer to instance data of the internal networking driver. */
126typedef DRVINTNET *PDRVINTNET;
127
128
129#ifdef IN_RING3
130
131/* -=-=-=-=- PDMINETWORKUP -=-=-=-=- */
132
133
134/**
135 * Updates the MAC address on the kernel side.
136 *
137 * @returns VBox status code.
138 * @param pThis The driver instance.
139 */
140static int drvR3IntNetUpdateMacAddress(PDRVINTNET pThis)
141{
142 if (!pThis->pIAboveConfigR3)
143 return VINF_SUCCESS;
144
145 INTNETIFSETMACADDRESSREQ SetMacAddressReq;
146 SetMacAddressReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
147 SetMacAddressReq.Hdr.cbReq = sizeof(SetMacAddressReq);
148 SetMacAddressReq.pSession = NIL_RTR0PTR;
149 SetMacAddressReq.hIf = pThis->hIf;
150 int rc = pThis->pIAboveConfigR3->pfnGetMac(pThis->pIAboveConfigR3, &SetMacAddressReq.Mac);
151 if (RT_SUCCESS(rc))
152 rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS,
153 &SetMacAddressReq, sizeof(SetMacAddressReq));
154
155 Log(("drvR3IntNetUpdateMacAddress: %.*Rhxs rc=%Rrc\n", sizeof(SetMacAddressReq.Mac), &SetMacAddressReq.Mac, rc));
156 return rc;
157}
158
159
160/**
161 * Sets the kernel interface active or inactive.
162 *
163 * Worker for poweron, poweroff, suspend and resume.
164 *
165 * @returns VBox status code.
166 * @param pThis The driver instance.
167 * @param fActive The new state.
168 */
169static int drvR3IntNetSetActive(PDRVINTNET pThis, bool fActive)
170{
171 if (!pThis->pIAboveConfigR3)
172 return VINF_SUCCESS;
173
174 INTNETIFSETACTIVEREQ SetActiveReq;
175 SetActiveReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
176 SetActiveReq.Hdr.cbReq = sizeof(SetActiveReq);
177 SetActiveReq.pSession = NIL_RTR0PTR;
178 SetActiveReq.hIf = pThis->hIf;
179 SetActiveReq.fActive = fActive;
180 int rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SET_ACTIVE,
181 &SetActiveReq, sizeof(SetActiveReq));
182
183 Log(("drvR3IntNetSetActive: fActive=%d rc=%Rrc\n", fActive, rc));
184 AssertRC(rc);
185 return rc;
186}
187
188
189/**
190 * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
191 */
192static DECLCALLBACK(int) drvR3IntNetUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
193 PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf)
194{
195 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
196 int rc = VINF_SUCCESS;
197 Assert(cbMin < UINT32_MAX / 2);
198AssertReturn(!pGso, VERR_NOT_IMPLEMENTED); /** @todo GSO buffer allocation. */
199
200 /*
201 * Allocate a S/G buffer.
202 */
203 PPDMSCATTERGATHER pSgBuf = (PPDMSCATTERGATHER)RTMemCacheAlloc(pThis->hSgCache);
204 if (pSgBuf)
205 {
206 PINTNETHDR pHdr;
207 rc = INTNETRingAllocateFrame(&pThis->pBufR3->Send, (uint32_t)cbMin,
208 &pHdr, &pSgBuf->aSegs[0].pvSeg);
209#if 1 /** @todo implement VERR_TRY_AGAIN once this moves to EMT. */
210 if ( RT_FAILURE(rc)
211 && pThis->pBufR3->cbSend >= cbMin * 2 + sizeof(INTNETHDR))
212 {
213 INTNETIFSENDREQ SendReq;
214 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
215 SendReq.Hdr.cbReq = sizeof(SendReq);
216 SendReq.pSession = NIL_RTR0PTR;
217 SendReq.hIf = pThis->hIf;
218 PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
219
220 rc = INTNETRingAllocateFrame(&pThis->pBufR3->Send, (uint32_t)cbMin,
221 &pHdr, &pSgBuf->aSegs[0].pvSeg);
222 }
223#endif
224 if (RT_SUCCESS(rc))
225 {
226 pSgBuf->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
227 pSgBuf->cbUsed = 0;
228 pSgBuf->cbAvailable = cbMin;
229 pSgBuf->pvUser = pHdr;
230 pSgBuf->cSegs = 1;
231 pSgBuf->aSegs[0].cbSeg = cbMin;
232
233 *ppSgBuf = pSgBuf;
234 return VINF_SUCCESS;
235 }
236
237 /*
238 * Arm the try again stuff.
239 */
240/** @todo if (pThis->pBufR3->cbSend >= cbMin * 2 + sizeof(INTNETHDR))
241 rc = VERR_TRY_AGAIN;
242 else */
243 rc = VERR_NO_MEMORY;
244
245 RTMemCacheFree(pThis->hSgCache, pSgBuf);
246 }
247 else
248 rc = VERR_NO_MEMORY;
249 /** @todo implement VERR_TRY_AGAIN */
250 return rc;
251}
252
253/**
254 * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
255 */
256static DECLCALLBACK(int) drvR3IntNetUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
257{
258 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
259 PINTNETHDR pHdr = (PINTNETHDR)pSgBuf->pvUser;
260 Assert(pSgBuf->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1));
261 Assert(pSgBuf->cbUsed <= pSgBuf->cbAvailable);
262 Assert(pHdr->u16Type == INTNETHDR_TYPE_FRAME);
263
264 /** @todo LATER: try unalloc the frame. */
265 pHdr->u16Type = INTNETHDR_TYPE_PADDING;
266 INTNETRingCommitFrame(&pThis->pBufR3->Send, pHdr);
267
268 RTMemCacheFree(pThis->hSgCache, pSgBuf);
269 return VINF_SUCCESS;
270}
271
272/**
273 * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
274 */
275static DECLCALLBACK(int) drvR3IntNetUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
276{
277 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
278 STAM_PROFILE_START(&pThis->StatTransmit, a);
279
280 AssertPtr(pSgBuf);
281 Assert(pSgBuf->fFlags == (PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1));
282 Assert(pSgBuf->cbUsed <= pSgBuf->cbAvailable);
283
284 /*
285 * Commit the frame and push it thru the switch.
286 */
287 PINTNETHDR pHdr = (PINTNETHDR)pSgBuf->pvUser;
288 INTNETRingCommitFrameEx(&pThis->pBufR3->Send, pHdr, pSgBuf->cbUsed);
289
290 INTNETIFSENDREQ SendReq;
291 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
292 SendReq.Hdr.cbReq = sizeof(SendReq);
293 SendReq.pSession = NIL_RTR0PTR;
294 SendReq.hIf = pThis->hIf;
295 PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
296
297 RTMemCacheFree(pThis->hSgCache, pSgBuf);
298
299 STAM_PROFILE_STOP(&pThis->StatTransmit, a);
300 return VINF_SUCCESS;
301}
302
303/**
304 * @interface_method_impl{PDMINETWORKUP,pfnSendDeprecated}
305 */
306static DECLCALLBACK(int) drvR3IntNetUp_SendDeprecated(PPDMINETWORKUP pInterface, const void *pvBuf, size_t cb)
307{
308 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
309 STAM_PROFILE_START(&pThis->StatTransmit, a);
310
311#ifdef LOG_ENABLED
312 uint64_t u64Now = RTTimeProgramNanoTS();
313 LogFlow(("drvR3IntNetSend: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
314 cb, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
315 pThis->u64LastTransferTS = u64Now;
316 Log2(("drvR3IntNetSend: pvBuf=%p cb=%#x\n"
317 "%.*Rhxd\n",
318 pvBuf, cb, cb, pvBuf));
319#endif
320
321 /*
322 * Add the frame to the send buffer and push it onto the network.
323 */
324 int rc = INTNETRingWriteFrame(&pThis->pBufR3->Send, pvBuf, (uint32_t)cb);
325 if ( rc == VERR_BUFFER_OVERFLOW
326 && pThis->pBufR3->cbSend < cb)
327 {
328 INTNETIFSENDREQ SendReq;
329 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
330 SendReq.Hdr.cbReq = sizeof(SendReq);
331 SendReq.pSession = NIL_RTR0PTR;
332 SendReq.hIf = pThis->hIf;
333 PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
334
335 rc = INTNETRingWriteFrame(&pThis->pBufR3->Send, pvBuf, (uint32_t)cb);
336 }
337
338 if (RT_SUCCESS(rc))
339 {
340 INTNETIFSENDREQ SendReq;
341 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
342 SendReq.Hdr.cbReq = sizeof(SendReq);
343 SendReq.pSession = NIL_RTR0PTR;
344 SendReq.hIf = pThis->hIf;
345 rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
346 }
347
348 STAM_PROFILE_STOP(&pThis->StatTransmit, a);
349 AssertRC(rc);
350 return rc;
351}
352
353
354/**
355 * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
356 */
357static DECLCALLBACK(void) drvR3IntNetUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
358{
359 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
360 INTNETIFSETPROMISCUOUSMODEREQ Req;
361 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
362 Req.Hdr.cbReq = sizeof(Req);
363 Req.pSession = NIL_RTR0PTR;
364 Req.hIf = pThis->hIf;
365 Req.fPromiscuous = fPromiscuous;
366 int rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvInsR3, VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, &Req, sizeof(Req));
367 LogFlow(("drvR3IntNetUp_SetPromiscuousMode: fPromiscuous=%RTbool\n", fPromiscuous));
368 AssertRC(rc);
369}
370
371
372/**
373 * @interface_method_impl{PDMINETWORKUP,pfnNotifyLinkChanged}
374 */
375static DECLCALLBACK(void) drvR3IntNetUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
376{
377 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, INetworkUpR3);
378 bool fLinkDown;
379 switch (enmLinkState)
380 {
381 case PDMNETWORKLINKSTATE_DOWN:
382 case PDMNETWORKLINKSTATE_DOWN_RESUME:
383 fLinkDown = true;
384 break;
385 default:
386 AssertMsgFailed(("enmLinkState=%d\n", enmLinkState));
387 case PDMNETWORKLINKSTATE_UP:
388 fLinkDown = false;
389 break;
390 }
391 LogFlow(("drvR3IntNetUp_NotifyLinkChanged: enmLinkState=%d %d->%d\n", enmLinkState, pThis->fLinkDown, fLinkDown));
392 ASMAtomicXchgSize(&pThis->fLinkDown, fLinkDown);
393}
394
395
396/**
397 * Wait for space to become available up the driver/device chain.
398 *
399 * @returns VINF_SUCCESS if space is available.
400 * @returns VERR_STATE_CHANGED if the state changed.
401 * @returns VBox status code on other errors.
402 * @param pThis Pointer to the instance data.
403 */
404static int drvR3IntNetAsyncIoWaitForSpace(PDRVINTNET pThis)
405{
406 LogFlow(("drvR3IntNetAsyncIoWaitForSpace:\n"));
407 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
408 int rc = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, RT_INDEFINITE_WAIT);
409 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
410 LogFlow(("drvR3IntNetAsyncIoWaitForSpace: returns %Rrc\n", rc));
411 return rc;
412}
413
414
415/**
416 * Executes async I/O (RUNNING mode).
417 *
418 * @returns VERR_STATE_CHANGED if the state changed.
419 * @returns Appropriate VBox status code (error) on fatal error.
420 * @param pThis The driver instance data.
421 */
422static int drvR3IntNetAsyncIoRun(PDRVINTNET pThis)
423{
424 PPDMDRVINS pDrvIns = pThis->pDrvInsR3;
425 LogFlow(("drvR3IntNetAsyncIoRun: pThis=%p\n", pThis));
426
427 /*
428 * The running loop - processing received data and waiting for more to arrive.
429 */
430 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
431 PINTNETBUF pBuf = pThis->pBufR3;
432 PINTNETRINGBUF pRingBuf = &pBuf->Recv;
433 for (;;)
434 {
435 /*
436 * Process the receive buffer.
437 */
438 PINTNETHDR pHdr;
439 while ((pHdr = INTNETRingGetNextFrameToRead(pRingBuf)) != NULL)
440 {
441 /*
442 * Check the state and then inspect the packet.
443 */
444 if (pThis->enmState != ASYNCSTATE_RUNNING)
445 {
446 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
447 LogFlow(("drvR3IntNetAsyncIoRun: returns VERR_STATE_CHANGED (state changed - #0)\n"));
448 return VERR_STATE_CHANGED;
449 }
450
451 Log2(("pHdr=%p offRead=%#x: %.8Rhxs\n", pHdr, pRingBuf->offReadX, pHdr));
452 if ( pHdr->u16Type == INTNETHDR_TYPE_FRAME
453 && !pThis->fLinkDown)
454 {
455 /*
456 * Check if there is room for the frame and pass it up.
457 */
458 size_t cbFrame = pHdr->cbFrame;
459 int rc = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, 0);
460 if (rc == VINF_SUCCESS)
461 {
462#ifdef LOG_ENABLED
463 uint64_t u64Now = RTTimeProgramNanoTS();
464 LogFlow(("drvR3IntNetAsyncIoRun: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
465 cbFrame, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
466 pThis->u64LastReceiveTS = u64Now;
467 Log2(("drvR3IntNetAsyncIoRun: cbFrame=%#x\n"
468 "%.*Rhxd\n",
469 cbFrame, cbFrame, INTNETHdrGetFramePtr(pHdr, pBuf)));
470#endif
471 rc = pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, INTNETHdrGetFramePtr(pHdr, pBuf), cbFrame);
472 AssertRC(rc);
473
474 /* skip to the next frame. */
475 INTNETRingSkipFrame(pRingBuf);
476 }
477 else
478 {
479 /*
480 * Wait for sufficient space to become available and then retry.
481 */
482 rc = drvR3IntNetAsyncIoWaitForSpace(pThis);
483 if (RT_FAILURE(rc))
484 {
485 if (rc == VERR_INTERRUPTED)
486 {
487 /*
488 * NIC is going down, likely because the VM is being reset. Skip the frame.
489 */
490 AssertMsg( pHdr->u16Type == INTNETHDR_TYPE_FRAME
491 || pHdr->u16Type == INTNETHDR_TYPE_PADDING,
492 ("Unknown frame type %RX16! offRead=%#x\n", pHdr->u16Type, pRingBuf->offReadX));
493 INTNETRingSkipFrame(pRingBuf);
494 }
495 else
496 {
497 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
498 LogFlow(("drvR3IntNetAsyncIoRun: returns %Rrc (wait-for-space)\n", rc));
499 return rc;
500 }
501 }
502 }
503 }
504 else
505 {
506 /*
507 * Link down or unknown frame - skip to the next frame.
508 */
509 AssertMsg( pHdr->u16Type == INTNETHDR_TYPE_FRAME
510 || pHdr->u16Type == INTNETHDR_TYPE_PADDING,
511 ("Unknown frame type %RX16! offRead=%#x\n", pHdr->u16Type, pRingBuf->offReadX));
512 INTNETRingSkipFrame(pRingBuf);
513 STAM_REL_COUNTER_INC(&pBuf->cStatBadFrames);
514 }
515 } /* while more received data */
516
517 /*
518 * Wait for data, checking the state before we block.
519 */
520 if (pThis->enmState != ASYNCSTATE_RUNNING)
521 {
522 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
523 LogFlow(("drvR3IntNetAsyncIoRun: returns VINF_SUCCESS (state changed - #1)\n"));
524 return VERR_STATE_CHANGED;
525 }
526 INTNETIFWAITREQ WaitReq;
527 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
528 WaitReq.Hdr.cbReq = sizeof(WaitReq);
529 WaitReq.pSession = NIL_RTR0PTR;
530 WaitReq.hIf = pThis->hIf;
531 WaitReq.cMillies = 30000; /* 30s - don't wait forever, timeout now and then. */
532 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
533 int rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_WAIT, &WaitReq, sizeof(WaitReq));
534 if ( RT_FAILURE(rc)
535 && rc != VERR_TIMEOUT
536 && rc != VERR_INTERRUPTED)
537 {
538 LogFlow(("drvR3IntNetAsyncIoRun: returns %Rrc\n", rc));
539 return rc;
540 }
541 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
542 }
543}
544
545
546/**
547 * Asynchronous I/O thread for handling receive.
548 *
549 * @returns VINF_SUCCESS (ignored).
550 * @param ThreadSelf Thread handle.
551 * @param pvUser Pointer to a DRVINTNET structure.
552 */
553static DECLCALLBACK(int) drvR3IntNetAsyncIoThread(RTTHREAD ThreadSelf, void *pvUser)
554{
555 PDRVINTNET pThis = (PDRVINTNET)pvUser;
556 LogFlow(("drvR3IntNetAsyncIoThread: pThis=%p\n", pThis));
557 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
558
559 /*
560 * The main loop - acting on state.
561 */
562 for (;;)
563 {
564 ASYNCSTATE enmState = pThis->enmState;
565 switch (enmState)
566 {
567 case ASYNCSTATE_SUSPENDED:
568 {
569 int rc = RTSemEventWait(pThis->hEvtSuspended, 30000);
570 if ( RT_FAILURE(rc)
571 && rc != VERR_TIMEOUT)
572 {
573 LogFlow(("drvR3IntNetAsyncIoThread: returns %Rrc\n", rc));
574 return rc;
575 }
576 break;
577 }
578
579 case ASYNCSTATE_RUNNING:
580 {
581 int rc = drvR3IntNetAsyncIoRun(pThis);
582 if ( rc != VERR_STATE_CHANGED
583 && RT_FAILURE(rc))
584 {
585 LogFlow(("drvR3IntNetAsyncIoThread: returns %Rrc\n", rc));
586 return rc;
587 }
588 break;
589 }
590
591 default:
592 AssertMsgFailed(("Invalid state %d\n", enmState));
593 case ASYNCSTATE_TERMINATE:
594 LogFlow(("drvR3IntNetAsyncIoThread: returns VINF_SUCCESS\n"));
595 return VINF_SUCCESS;
596 }
597 }
598}
599
600/* -=-=-=-=- PDMIBASERC -=-=-=-=- */
601
602/**
603 * @interface_method_impl{PDMIBASERC,pfnQueryInterface}
604 */
605static DECLCALLBACK(RTRCPTR) drvR3IntNetIBaseRC_QueryInterface(PPDMIBASERC pInterface, const char *pszIID)
606{
607 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, IBaseRC);
608
609 PDMIBASERC_RETURN_INTERFACE(pThis->pDrvInsR3, pszIID, PDMIBASERC, &pThis->IBaseRC);
610 return NIL_RTRCPTR;
611}
612
613/* -=-=-=-=- PDMIBASER0 -=-=-=-=- */
614
615/**
616 * @interface_method_impl{PDMIBASER0,pfnQueryInterface}
617 */
618static DECLCALLBACK(RTR0PTR) drvR3IntNetIBaseR0_QueryInterface(PPDMIBASER0 pInterface, const char *pszIID)
619{
620 PDRVINTNET pThis = RT_FROM_MEMBER(pInterface, DRVINTNET, IBaseR0);
621
622 PDMIBASER0_RETURN_INTERFACE(pThis->pDrvInsR3, pszIID, PDMIBASER0, &pThis->IBaseR0);
623 return NIL_RTR0PTR;
624}
625
626/* -=-=-=-=- PDMIBASE -=-=-=-=- */
627
628/**
629 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
630 */
631static DECLCALLBACK(void *) drvR3IntNetIBase_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
632{
633 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
634 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
635
636 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
637 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASER0, &pThis->IBaseR0);
638 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASERC, &pThis->IBaseRC);
639 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUpR3);
640 return NULL;
641}
642
643/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
644
645/**
646 * Power Off notification.
647 *
648 * @param pDrvIns The driver instance.
649 */
650static DECLCALLBACK(void) drvR3IntNetPowerOff(PPDMDRVINS pDrvIns)
651{
652 LogFlow(("drvR3IntNetPowerOff\n"));
653 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
654 if (!pThis->fActivateEarlyDeactivateLate)
655 {
656 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
657 drvR3IntNetSetActive(pThis, false /* fActive */);
658 }
659}
660
661
662/**
663 * Resume notification.
664 *
665 * @param pDrvIns The driver instance.
666 */
667static DECLCALLBACK(void) drvR3IntNetResume(PPDMDRVINS pDrvIns)
668{
669 LogFlow(("drvR3IntNetPowerResume\n"));
670 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
671 if (!pThis->fActivateEarlyDeactivateLate)
672 {
673 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
674 RTSemEventSignal(pThis->hEvtSuspended);
675 drvR3IntNetUpdateMacAddress(pThis); /* (could be a state restore) */
676 drvR3IntNetSetActive(pThis, true /* fActive */);
677 }
678 if ( PDMDrvHlpVMTeleportedAndNotFullyResumedYet(pDrvIns)
679 && pThis->pIAboveConfigR3)
680 {
681 /*
682 * We've just been teleported and need to drop a hint to the switch
683 * since we're likely to have changed to a different port. We just
684 * push out some ethernet frame that doesn't mean anything to anyone.
685 * For this purpose ethertype 0x801e was chosen since it was registered
686 * to Sun (dunno what it is/was used for though).
687 */
688 union
689 {
690 RTNETETHERHDR Hdr;
691 uint8_t ab[128];
692 } Frame;
693 RT_ZERO(Frame);
694 Frame.Hdr.DstMac.au16[0] = 0xffff;
695 Frame.Hdr.DstMac.au16[1] = 0xffff;
696 Frame.Hdr.DstMac.au16[2] = 0xffff;
697 Frame.Hdr.EtherType = RT_H2BE_U16(0x801e);
698 int rc = pThis->pIAboveConfigR3->pfnGetMac(pThis->pIAboveConfigR3, &Frame.Hdr.SrcMac);
699 if (RT_SUCCESS(rc))
700 rc = drvR3IntNetUp_SendDeprecated(&pThis->INetworkUpR3, &Frame, sizeof(Frame));
701 if (RT_FAILURE(rc))
702 LogRel(("IntNet#%u: Sending dummy frame failed: %Rrc\n", pDrvIns->iInstance, rc));
703 }
704}
705
706
707/**
708 * Suspend notification.
709 *
710 * @param pDrvIns The driver instance.
711 */
712static DECLCALLBACK(void) drvR3IntNetSuspend(PPDMDRVINS pDrvIns)
713{
714 LogFlow(("drvR3IntNetPowerSuspend\n"));
715 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
716 if (!pThis->fActivateEarlyDeactivateLate)
717 {
718 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
719 drvR3IntNetSetActive(pThis, false /* fActive */);
720 }
721}
722
723
724/**
725 * Power On notification.
726 *
727 * @param pDrvIns The driver instance.
728 */
729static DECLCALLBACK(void) drvR3IntNetPowerOn(PPDMDRVINS pDrvIns)
730{
731 LogFlow(("drvR3IntNetPowerOn\n"));
732 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
733 if (!pThis->fActivateEarlyDeactivateLate)
734 {
735 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
736 RTSemEventSignal(pThis->hEvtSuspended);
737 drvR3IntNetUpdateMacAddress(pThis);
738 drvR3IntNetSetActive(pThis, true /* fActive */);
739 }
740}
741
742
743/**
744 * Destruct a driver instance.
745 *
746 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
747 * resources can be freed correctly.
748 *
749 * @param pDrvIns The driver instance data.
750 */
751static DECLCALLBACK(void) drvR3IntNetDestruct(PPDMDRVINS pDrvIns)
752{
753 LogFlow(("drvR3IntNetDestruct\n"));
754 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
755 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
756
757 /*
758 * Indicate to the thread that it's time to quit.
759 */
760 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_TERMINATE);
761 ASMAtomicXchgSize(&pThis->fLinkDown, true);
762 RTSEMEVENT hEvtSuspended = pThis->hEvtSuspended;
763 pThis->hEvtSuspended = NIL_RTSEMEVENT;
764
765 /*
766 * Close the interface
767 */
768 if (pThis->hIf != INTNET_HANDLE_INVALID)
769 {
770 INTNETIFCLOSEREQ CloseReq;
771 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
772 CloseReq.Hdr.cbReq = sizeof(CloseReq);
773 CloseReq.pSession = NIL_RTR0PTR;
774 CloseReq.hIf = pThis->hIf;
775 pThis->hIf = INTNET_HANDLE_INVALID;
776 int rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_CLOSE, &CloseReq, sizeof(CloseReq));
777 AssertRC(rc);
778 }
779
780 /*
781 * Wait for the thread to terminate.
782 */
783 if (pThis->Thread != NIL_RTTHREAD)
784 {
785 if (hEvtSuspended != NIL_RTSEMEVENT)
786 RTSemEventSignal(hEvtSuspended);
787 int rc = RTThreadWait(pThis->Thread, 5000, NULL);
788 AssertRC(rc);
789 pThis->Thread = NIL_RTTHREAD;
790 }
791
792 /*
793 * Destroy the semaphore and S/G cache.
794 */
795 if (hEvtSuspended != NIL_RTSEMEVENT)
796 RTSemEventDestroy(hEvtSuspended);
797
798 RTMemCacheDestroy(pThis->hSgCache);
799 pThis->hSgCache = NIL_RTMEMCACHE;
800
801 if (pThis->pBufR3)
802 {
803 /*
804 * Deregister statistics in case we're being detached.
805 */
806 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Recv.cStatFrames);
807 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Recv.cbStatWritten);
808 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Recv.cOverflows);
809 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Send.cStatFrames);
810 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Send.cbStatWritten);
811 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->Send.cOverflows);
812 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatYieldsOk);
813 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatYieldsNok);
814 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatLost);
815 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatBadFrames);
816#ifdef VBOX_WITH_STATISTICS
817 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceive);
818 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatTransmit);
819#endif
820 }
821}
822
823
824/**
825 * Construct a TAP network transport driver instance.
826 *
827 * @copydoc FNPDMDRVCONSTRUCT
828 */
829static DECLCALLBACK(int) drvR3IntNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
830{
831 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
832 bool f;
833 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
834
835 /*
836 * Init the static parts.
837 */
838 pThis->pDrvInsR3 = pDrvIns;
839 pThis->hIf = INTNET_HANDLE_INVALID;
840 pThis->Thread = NIL_RTTHREAD;
841 pThis->hEvtSuspended = NIL_RTSEMEVENT;
842 pThis->hSgCache = NIL_RTMEMCACHE;
843 pThis->enmState = ASYNCSTATE_SUSPENDED;
844 pThis->fActivateEarlyDeactivateLate = false;
845 /* IBase* */
846 pDrvIns->IBase.pfnQueryInterface = drvR3IntNetIBase_QueryInterface;
847 pThis->IBaseR0.pfnQueryInterface = drvR3IntNetIBaseR0_QueryInterface;
848 pThis->IBaseRC.pfnQueryInterface = drvR3IntNetIBaseRC_QueryInterface;
849 /* INetworkUp */
850 pThis->INetworkUpR3.pfnAllocBuf = drvR3IntNetUp_AllocBuf;
851 pThis->INetworkUpR3.pfnFreeBuf = drvR3IntNetUp_FreeBuf;
852 pThis->INetworkUpR3.pfnSendBuf = drvR3IntNetUp_SendBuf;
853 pThis->INetworkUpR3.pfnSendDeprecated = drvR3IntNetUp_SendDeprecated;
854 pThis->INetworkUpR3.pfnSetPromiscuousMode = drvR3IntNetUp_SetPromiscuousMode;
855 pThis->INetworkUpR3.pfnNotifyLinkChanged = drvR3IntNetUp_NotifyLinkChanged;
856
857 /*
858 * Validate the config.
859 */
860 if (!CFGMR3AreValuesValid(pCfg,
861 "Network\0"
862 "Trunk\0"
863 "TrunkType\0"
864 "ReceiveBufferSize\0"
865 "SendBufferSize\0"
866 "RestrictAccess\0"
867 "SharedMacOnWire\0"
868 "IgnoreAllPromisc\0"
869 "QuietlyIgnoreAllPromisc\0"
870 "IgnoreClientPromisc\0"
871 "QuietlyIgnoreClientPromisc\0"
872 "IgnoreTrunkWirePromisc\0"
873 "QuietlyIgnoreTrunkWirePromisc\0"
874 "IgnoreTrunkHostPromisc\0"
875 "QuietlyIgnoreTrunkHostPromisc\0"
876 "IsService\0"))
877 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
878
879 /*
880 * Check that no-one is attached to us.
881 */
882 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
883 ("Configuration error: Not possible to attach anything to this driver!\n"),
884 VERR_PDM_DRVINS_NO_ATTACH);
885
886 /*
887 * Query the network port interface.
888 */
889 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
890 if (!pThis->pIAboveNet)
891 {
892 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
893 return VERR_PDM_MISSING_INTERFACE_ABOVE;
894 }
895 pThis->pIAboveConfigR3 = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
896
897 /*
898 * Read the configuration.
899 */
900 INTNETOPENREQ OpenReq;
901 memset(&OpenReq, 0, sizeof(OpenReq));
902 OpenReq.Hdr.cbReq = sizeof(OpenReq);
903 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
904 OpenReq.pSession = NIL_RTR0PTR;
905
906 /** @cfgm{Network, string}
907 * The name of the internal network to connect to.
908 */
909 int rc = CFGMR3QueryString(pCfg, "Network", OpenReq.szNetwork, sizeof(OpenReq.szNetwork));
910 if (RT_FAILURE(rc))
911 return PDMDRV_SET_ERROR(pDrvIns, rc,
912 N_("Configuration error: Failed to get the \"Network\" value"));
913 strcpy(pThis->szNetwork, OpenReq.szNetwork);
914
915 /** @cfgm{TrunkType, uint32_t, kIntNetTrunkType_None}
916 * The trunk connection type see INTNETTRUNKTYPE.
917 */
918 uint32_t u32TrunkType;
919 rc = CFGMR3QueryU32(pCfg, "TrunkType", &u32TrunkType);
920 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
921 u32TrunkType = kIntNetTrunkType_None;
922 else if (RT_FAILURE(rc))
923 return PDMDRV_SET_ERROR(pDrvIns, rc,
924 N_("Configuration error: Failed to get the \"TrunkType\" value"));
925 OpenReq.enmTrunkType = (INTNETTRUNKTYPE)u32TrunkType;
926
927 /** @cfgm{Trunk, string, ""}
928 * The name of the trunk connection.
929 */
930 rc = CFGMR3QueryString(pCfg, "Trunk", OpenReq.szTrunk, sizeof(OpenReq.szTrunk));
931 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
932 OpenReq.szTrunk[0] = '\0';
933 else if (RT_FAILURE(rc))
934 return PDMDRV_SET_ERROR(pDrvIns, rc,
935 N_("Configuration error: Failed to get the \"Trunk\" value"));
936
937 /** @cfgm{RestrictAccess, boolean, true}
938 * Whether to restrict the access to the network or if it should be public. Everyone on
939 * the computer can connect to a public network. Don't change this.
940 */
941 bool fRestrictAccess;
942 rc = CFGMR3QueryBool(pCfg, "RestrictAccess", &fRestrictAccess);
943 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
944 fRestrictAccess = true;
945 else if (RT_FAILURE(rc))
946 return PDMDRV_SET_ERROR(pDrvIns, rc,
947 N_("Configuration error: Failed to get the \"RestrictAccess\" value"));
948 OpenReq.fFlags = fRestrictAccess ? 0 : INTNET_OPEN_FLAGS_PUBLIC;
949
950 /** @cfgm{IgnoreAllPromisc, boolean, false}
951 * When set all request for operating any interface or trunk in promiscuous
952 * mode will be ignored. */
953 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreAllPromisc", &f, false);
954 if (RT_FAILURE(rc))
955 return PDMDRV_SET_ERROR(pDrvIns, rc,
956 N_("Configuration error: Failed to get the \"IgnoreAllPromisc\" value"));
957 if (f)
958 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC;
959
960 /** @cfgm{QuietlyIgnoreAllPromisc, boolean, false}
961 * When set all request for operating any interface or trunk in promiscuous
962 * mode will be ignored. This differs from IgnoreAllPromisc in that clients
963 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
964 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreAllPromisc", &f, false);
965 if (RT_FAILURE(rc))
966 return PDMDRV_SET_ERROR(pDrvIns, rc,
967 N_("Configuration error: Failed to get the \"QuietlyIgnoreAllPromisc\" value"));
968 if (f)
969 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC;
970
971 /** @cfgm{IgnoreClientPromisc, boolean, false}
972 * When set all request for operating any non-trunk interface in promiscuous
973 * mode will be ignored. */
974 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreClientPromisc", &f, false);
975 if (RT_FAILURE(rc))
976 return PDMDRV_SET_ERROR(pDrvIns, rc,
977 N_("Configuration error: Failed to get the \"IgnoreClientPromisc\" value"));
978 if (f)
979 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC; /** @todo add special flag for this. */
980
981 /** @cfgm{QuietlyIgnoreClientPromisc, boolean, false}
982 * When set all request for operating any non-trunk interface promiscuous mode
983 * will be ignored. This differs from IgnoreClientPromisc in that clients won't
984 * get VERR_INTNET_INCOMPATIBLE_FLAGS. */
985 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreClientPromisc", &f, false);
986 if (RT_FAILURE(rc))
987 return PDMDRV_SET_ERROR(pDrvIns, rc,
988 N_("Configuration error: Failed to get the \"QuietlyIgnoreClientPromisc\" value"));
989 if (f)
990 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC; /** @todo add special flag for this. */
991
992 /** @cfgm{IgnoreTrunkWirePromisc, boolean, false}
993 * When set all request for operating the trunk-wire connection in promiscuous
994 * mode will be ignored. */
995 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreTrunkWirePromisc", &f, false);
996 if (RT_FAILURE(rc))
997 return PDMDRV_SET_ERROR(pDrvIns, rc,
998 N_("Configuration error: Failed to get the \"IgnoreTrunkWirePromisc\" value"));
999 if (f)
1000 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE;
1001
1002 /** @cfgm{QuietlyIgnoreTrunkWirePromisc, boolean, false}
1003 * When set all request for operating any trunk-wire connection promiscuous mode
1004 * will be ignored. This differs from IgnoreTrunkWirePromisc in that clients
1005 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1006 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreTrunkWirePromisc", &f, false);
1007 if (RT_FAILURE(rc))
1008 return PDMDRV_SET_ERROR(pDrvIns, rc,
1009 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkWirePromisc\" value"));
1010 if (f)
1011 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE;
1012
1013 /** @cfgm{IgnoreTrunkHostPromisc, boolean, false}
1014 * When set all request for operating the trunk-host connection in promiscuous
1015 * mode will be ignored. */
1016 rc = CFGMR3QueryBoolDef(pCfg, "IgnoreTrunkHostPromisc", &f, false);
1017 if (RT_FAILURE(rc))
1018 return PDMDRV_SET_ERROR(pDrvIns, rc,
1019 N_("Configuration error: Failed to get the \"IgnoreTrunkHostPromisc\" value"));
1020 if (f)
1021 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST;
1022
1023 /** @cfgm{QuietlyIgnoreTrunkHostPromisc, boolean, false}
1024 * When set all request for operating any trunk-host connection promiscuous mode
1025 * will be ignored. This differs from IgnoreTrunkHostPromisc in that clients
1026 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
1027 rc = CFGMR3QueryBoolDef(pCfg, "QuietlyIgnoreTrunkHostPromisc", &f, false);
1028 if (RT_FAILURE(rc))
1029 return PDMDRV_SET_ERROR(pDrvIns, rc,
1030 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkHostPromisc\" value"));
1031 if (f)
1032 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST;
1033
1034 /** @todo flags for not sending to the host and for setting the trunk-wire
1035 * connection in promiscuous mode. */
1036
1037
1038 /** @cfgm{SharedMacOnWire, boolean, false}
1039 * Whether to shared the MAC address of the host interface when using the wire. When
1040 * attaching to a wireless NIC this option is usally a requirement.
1041 */
1042 bool fSharedMacOnWire;
1043 rc = CFGMR3QueryBoolDef(pCfg, "SharedMacOnWire", &fSharedMacOnWire, false);
1044 if (RT_FAILURE(rc))
1045 return PDMDRV_SET_ERROR(pDrvIns, rc,
1046 N_("Configuration error: Failed to get the \"SharedMacOnWire\" value"));
1047 if (fSharedMacOnWire)
1048 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1049
1050 /** @cfgm{ReceiveBufferSize, uint32_t, 218 KB}
1051 * The size of the receive buffer.
1052 */
1053 rc = CFGMR3QueryU32(pCfg, "ReceiveBufferSize", &OpenReq.cbRecv);
1054 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1055 OpenReq.cbRecv = 218 * _1K ;
1056 else if (RT_FAILURE(rc))
1057 return PDMDRV_SET_ERROR(pDrvIns, rc,
1058 N_("Configuration error: Failed to get the \"ReceiveBufferSize\" value"));
1059
1060 /** @cfgm{SendBufferSize, uint32_t, 36 KB}
1061 * The size of the send (transmit) buffer.
1062 * This should be more than twice the size of the larges frame size because
1063 * the ring buffer is very simple and doesn't support splitting up frames
1064 * nor inserting padding. So, if this is too close to the frame size the
1065 * header will fragment the buffer such that the frame won't fit on either
1066 * side of it and the code will get very upset about it all.
1067 */
1068 rc = CFGMR3QueryU32(pCfg, "SendBufferSize", &OpenReq.cbSend);
1069 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1070 OpenReq.cbSend = 36*_1K;
1071 else if (RT_FAILURE(rc))
1072 return PDMDRV_SET_ERROR(pDrvIns, rc,
1073 N_("Configuration error: Failed to get the \"SendBufferSize\" value"));
1074 if (OpenReq.cbSend < 32)
1075 return PDMDRV_SET_ERROR(pDrvIns, rc,
1076 N_("Configuration error: The \"SendBufferSize\" value is too small"));
1077 if (OpenReq.cbSend < 16384*2 + 64)
1078 LogRel(("DrvIntNet: Warning! SendBufferSize=%u, Recommended minimum size %u butes.\n", OpenReq.cbSend, 16384*2 + 64));
1079
1080 /** @cfgm{IsService, boolean, true}
1081 * This alterns the way the thread is suspended and resumed. When it's being used by
1082 * a service such as LWIP/iSCSI it shouldn't suspend immediately like for a NIC.
1083 */
1084 rc = CFGMR3QueryBool(pCfg, "IsService", &pThis->fActivateEarlyDeactivateLate);
1085 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1086 pThis->fActivateEarlyDeactivateLate = false;
1087 else if (RT_FAILURE(rc))
1088 return PDMDRV_SET_ERROR(pDrvIns, rc,
1089 N_("Configuration error: Failed to get the \"IsService\" value"));
1090
1091 LogRel(("IntNet#%u: szNetwork={%s} enmTrunkType=%d szTrunk={%s} fFlags=%#x cbRecv=%u cbSend=%u\n",
1092 pDrvIns->iInstance, OpenReq.szNetwork, OpenReq.enmTrunkType, OpenReq.szTrunk, OpenReq.fFlags,
1093 OpenReq.cbRecv, OpenReq.cbSend));
1094
1095#ifdef RT_OS_DARWIN
1096 /* Temporary hack: attach to a network with the name 'if=en0' and you're hitting the wire. */
1097 if ( !OpenReq.szTrunk[0]
1098 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1099 && !strncmp(pThis->szNetwork, "if=en", sizeof("if=en") - 1)
1100 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("if=en") - 1])
1101 && !pThis->szNetwork[sizeof("if=en")])
1102 {
1103 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1104 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("if=") - 1]);
1105 }
1106 /* Temporary hack: attach to a network with the name 'wif=en0' and you're on the air. */
1107 if ( !OpenReq.szTrunk[0]
1108 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1109 && !strncmp(pThis->szNetwork, "wif=en", sizeof("wif=en") - 1)
1110 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("wif=en") - 1])
1111 && !pThis->szNetwork[sizeof("wif=en")])
1112 {
1113 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1114 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1115 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("wif=") - 1]);
1116 }
1117#endif /* DARWIN */
1118
1119 /*
1120 * Create the event semaphore and S/G cache.
1121 */
1122 rc = RTSemEventCreate(&pThis->hEvtSuspended);
1123 if (RT_FAILURE(rc))
1124 return rc;
1125 rc = RTMemCacheCreate(&pThis->hSgCache, sizeof(PDMSCATTERGATHER), 0, UINT32_MAX, NULL, NULL, pThis, 0);
1126 if (RT_FAILURE(rc))
1127 return rc;
1128
1129 /*
1130 * Create the interface.
1131 */
1132 OpenReq.hIf = INTNET_HANDLE_INVALID;
1133 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_OPEN, &OpenReq, sizeof(OpenReq));
1134 if (RT_FAILURE(rc))
1135 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1136 N_("Failed to open/create the internal network '%s'"), pThis->szNetwork);
1137 AssertRelease(OpenReq.hIf != INTNET_HANDLE_INVALID);
1138 pThis->hIf = OpenReq.hIf;
1139 Log(("IntNet%d: hIf=%RX32 '%s'\n", pDrvIns->iInstance, pThis->hIf, pThis->szNetwork));
1140
1141 /*
1142 * Get default buffer.
1143 */
1144 INTNETIFGETRING3BUFFERREQ GetRing3BufferReq;
1145 GetRing3BufferReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1146 GetRing3BufferReq.Hdr.cbReq = sizeof(GetRing3BufferReq);
1147 GetRing3BufferReq.pSession = NIL_RTR0PTR;
1148 GetRing3BufferReq.hIf = pThis->hIf;
1149 GetRing3BufferReq.pRing3Buf = NULL;
1150 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_GET_RING3_BUFFER, &GetRing3BufferReq, sizeof(GetRing3BufferReq));
1151 if (RT_FAILURE(rc))
1152 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1153 N_("Failed to get ring-3 buffer for the newly created interface to '%s'"), pThis->szNetwork);
1154 AssertRelease(VALID_PTR(GetRing3BufferReq.pRing3Buf));
1155 pThis->pBufR3 = GetRing3BufferReq.pRing3Buf;
1156
1157 /*
1158 * Create the async I/O thread.
1159 * Note! Using a PDM thread here doesn't fit with the IsService=true operation.
1160 */
1161 rc = RTThreadCreate(&pThis->Thread, drvR3IntNetAsyncIoThread, pThis, _128K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET");
1162 if (RT_FAILURE(rc))
1163 {
1164 AssertRC(rc);
1165 return rc;
1166 }
1167 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->Recv.cbStatWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Net/IntNet%d/Bytes/Received", pDrvIns->iInstance);
1168 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->Send.cbStatWritten, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Net/IntNet%d/Bytes/Sent", pDrvIns->iInstance);
1169 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->Recv.cOverflows, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number overflows.", "/Net/IntNet%d/Overflows/Recv", pDrvIns->iInstance);
1170 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->Send.cOverflows, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number overflows.", "/Net/IntNet%d/Overflows/Sent", pDrvIns->iInstance);
1171 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->Recv.cStatFrames, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of received packets.", "/Net/IntNet%d/Packets/Received", pDrvIns->iInstance);
1172 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->Send.cStatFrames, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of sent packets.", "/Net/IntNet%d/Packets/Sent", pDrvIns->iInstance);
1173 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->cStatLost, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of lost packets.", "/Net/IntNet%d/Packets/Lost", pDrvIns->iInstance);
1174 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->cStatYieldsNok, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of times yielding helped fix an overflow.", "/Net/IntNet%d/YieldOk", pDrvIns->iInstance);
1175 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->cStatYieldsOk, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of times yielding didn't help fix an overflow.", "/Net/IntNet%d/YieldNok", pDrvIns->iInstance);
1176 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->cStatBadFrames, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of bad frames seed by the consumers.", "/Net/IntNet%d/BadFrames", pDrvIns->iInstance);
1177#ifdef VBOX_WITH_STATISTICS
1178 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Net/IntNet%d/Receive", pDrvIns->iInstance);
1179 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Net/IntNet%d/Transmit", pDrvIns->iInstance);
1180#endif
1181
1182 /*
1183 * Activate data transmission as early as possible
1184 */
1185 if (pThis->fActivateEarlyDeactivateLate)
1186 {
1187 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
1188 RTSemEventSignal(pThis->hEvtSuspended);
1189 drvR3IntNetUpdateMacAddress(pThis);
1190 drvR3IntNetSetActive(pThis, true /* fActive */);
1191 }
1192
1193 return rc;
1194}
1195
1196
1197/**
1198 * Internal networking transport driver registration record.
1199 */
1200const PDMDRVREG g_DrvIntNet =
1201{
1202 /* u32Version */
1203 PDM_DRVREG_VERSION,
1204 /* szName */
1205 "IntNet",
1206 /* szRCMod */
1207 "VBoxDD",
1208 /* szR0Mod */
1209 "VBoxDD",
1210 /* pszDescription */
1211 "Internal Networking Transport Driver",
1212 /* fFlags */
1213#ifdef VBOX_WITH_R0_AND_RC_DRIVERS
1214 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DRVREG_FLAGS_R0 | PDM_DRVREG_FLAGS_RC,
1215#else
1216 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1217#endif
1218 /* fClass. */
1219 PDM_DRVREG_CLASS_NETWORK,
1220 /* cMaxInstances */
1221 ~0,
1222 /* cbInstance */
1223 sizeof(DRVINTNET),
1224 /* pfnConstruct */
1225 drvR3IntNetConstruct,
1226 /* pfnDestruct */
1227 drvR3IntNetDestruct,
1228 /* pfnRelocate */
1229 NULL,
1230 /* pfnIOCtl */
1231 NULL,
1232 /* pfnPowerOn */
1233 drvR3IntNetPowerOn,
1234 /* pfnReset */
1235 NULL,
1236 /* pfnSuspend */
1237 drvR3IntNetSuspend,
1238 /* pfnResume */
1239 drvR3IntNetResume,
1240 /* pfnAttach */
1241 NULL,
1242 /* pfnDetach */
1243 NULL,
1244 /* pfnPowerOff */
1245 drvR3IntNetPowerOff,
1246 /* pfnSoftReset */
1247 NULL,
1248 /* u32EndVersion */
1249 PDM_DRVREG_VERSION
1250};
1251
1252#endif /* IN_RING3 */
1253
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