VirtualBox

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

Last change on this file since 13733 was 13416, checked in by vboxsync, 16 years ago

DrvIntNet: Expose the promisc ignore flags.

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