VirtualBox

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

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

Networking: Preparing to make the driver return a send buffer to the device emulation.

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