VirtualBox

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

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

pdmifs.h: Moved the network interfaces to a separate header called pdmnetifs.h.

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