VirtualBox

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

Last change on this file since 16249 was 15541, checked in by vboxsync, 16 years ago

Don't exit intnet receive loop if sem wait inside NIC was interrupted. Fixes hostif net loss after VM reboot.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.1 KB
Line 
1/* $Id: DrvIntNet.cpp 15541 2008-12-15 20:29:08Z 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 "%.*Rhxd\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 "%.*Rhxd\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 if (rc == VERR_INTERRUPTED)
467 {
468 /*
469 * NIC is going down, likely because the VM is being reset. Skip the frame.
470 */
471 AssertMsg(pHdr->u16Type == INTNETHDR_TYPE_FRAME, ("Unknown frame type %RX16! offRead=%#x\n",
472 pHdr->u16Type, pRingBuf->offRead));
473 INTNETRingSkipFrame(pBuf, pRingBuf);
474 }
475 else
476 {
477 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
478 LogFlow(("drvIntNetAsyncIoRun: returns %Rrc (wait-for-space)\n", rc));
479 return rc;
480 }
481 }
482 }
483 }
484 else
485 {
486 /*
487 * Link down or unknown frame - skip to the next frame.
488 */
489 AssertMsg(pHdr->u16Type == INTNETHDR_TYPE_FRAME, ("Unknown frame type %RX16! offRead=%#x\n",
490 pHdr->u16Type, pRingBuf->offRead));
491 INTNETRingSkipFrame(pBuf, pRingBuf);
492 }
493 } /* while more received data */
494
495 /*
496 * Wait for data, checking the state before we block.
497 */
498 if (pThis->enmState != ASYNCSTATE_RUNNING)
499 {
500 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
501 LogFlow(("drvIntNetAsyncIoRun: returns VINF_SUCCESS (state changed - #1)\n"));
502 return VERR_STATE_CHANGED;
503 }
504 INTNETIFWAITREQ WaitReq;
505 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
506 WaitReq.Hdr.cbReq = sizeof(WaitReq);
507 WaitReq.pSession = NIL_RTR0PTR;
508 WaitReq.hIf = pThis->hIf;
509 WaitReq.cMillies = 30000; /* 30s - don't wait forever, timeout now and then. */
510 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
511 int rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_WAIT, &WaitReq, sizeof(WaitReq));
512 if ( RT_FAILURE(rc)
513 && rc != VERR_TIMEOUT
514 && rc != VERR_INTERRUPTED)
515 {
516 LogFlow(("drvIntNetAsyncIoRun: returns %Rrc\n", rc));
517 return rc;
518 }
519 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
520 }
521}
522
523
524/**
525 * Asynchronous I/O thread for handling receive.
526 *
527 * @returns VINF_SUCCESS (ignored).
528 * @param ThreadSelf Thread handle.
529 * @param pvUser Pointer to a DRVINTNET structure.
530 */
531static DECLCALLBACK(int) drvIntNetAsyncIoThread(RTTHREAD ThreadSelf, void *pvUser)
532{
533 PDRVINTNET pThis = (PDRVINTNET)pvUser;
534 LogFlow(("drvIntNetAsyncIoThread: pThis=%p\n", pThis));
535 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
536
537 /*
538 * The main loop - acting on state.
539 */
540 for (;;)
541 {
542 ASYNCSTATE enmState = pThis->enmState;
543 switch (enmState)
544 {
545 case ASYNCSTATE_SUSPENDED:
546 {
547 int rc = RTSemEventWait(pThis->EventSuspended, 30000);
548 if ( RT_FAILURE(rc)
549 && rc != VERR_TIMEOUT)
550 {
551 LogFlow(("drvIntNetAsyncIoThread: returns %Rrc\n", rc));
552 return rc;
553 }
554 break;
555 }
556
557 case ASYNCSTATE_RUNNING:
558 {
559 int rc = drvIntNetAsyncIoRun(pThis);
560 if ( rc != VERR_STATE_CHANGED
561 && RT_FAILURE(rc))
562 {
563 LogFlow(("drvIntNetAsyncIoThread: returns %Rrc\n", rc));
564 return rc;
565 }
566 break;
567 }
568
569 default:
570 AssertMsgFailed(("Invalid state %d\n", enmState));
571 case ASYNCSTATE_TERMINATE:
572 LogFlow(("drvIntNetAsyncIoThread: returns VINF_SUCCESS\n"));
573 return VINF_SUCCESS;
574 }
575 }
576}
577
578
579/**
580 * Queries an interface to the driver.
581 *
582 * @returns Pointer to interface.
583 * @returns NULL if the interface was not supported by the driver.
584 * @param pInterface Pointer to this interface structure.
585 * @param enmInterface The requested interface identification.
586 * @thread Any thread.
587 */
588static DECLCALLBACK(void *) drvIntNetQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
589{
590 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
591 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
592 switch (enmInterface)
593 {
594 case PDMINTERFACE_BASE:
595 return &pDrvIns->IBase;
596 case PDMINTERFACE_NETWORK_CONNECTOR:
597 return &pThis->INetworkConnector;
598 default:
599 return NULL;
600 }
601}
602
603
604/**
605 * Power Off notification.
606 *
607 * @param pDrvIns The driver instance.
608 */
609static DECLCALLBACK(void) drvIntNetPowerOff(PPDMDRVINS pDrvIns)
610{
611 LogFlow(("drvIntNetPowerOff\n"));
612 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
613 if (!pThis->fActivateEarlyDeactivateLate)
614 {
615 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
616 drvIntNetSetActive(pThis, false /* fActive */);
617 }
618}
619
620
621/**
622 * Resume notification.
623 *
624 * @param pDrvIns The driver instance.
625 */
626static DECLCALLBACK(void) drvIntNetResume(PPDMDRVINS pDrvIns)
627{
628 LogFlow(("drvIntNetPowerResume\n"));
629 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
630 if (!pThis->fActivateEarlyDeactivateLate)
631 {
632 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
633 RTSemEventSignal(pThis->EventSuspended);
634 drvIntNetUpdateMacAddress(pThis); /* (could be a state restore) */
635 drvIntNetSetActive(pThis, true /* fActive */);
636 }
637}
638
639
640/**
641 * Suspend notification.
642 *
643 * @param pDrvIns The driver instance.
644 */
645static DECLCALLBACK(void) drvIntNetSuspend(PPDMDRVINS pDrvIns)
646{
647 LogFlow(("drvIntNetPowerSuspend\n"));
648 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
649 if (!pThis->fActivateEarlyDeactivateLate)
650 {
651 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
652 drvIntNetSetActive(pThis, false /* fActive */);
653 }
654}
655
656
657/**
658 * Power On notification.
659 *
660 * @param pDrvIns The driver instance.
661 */
662static DECLCALLBACK(void) drvIntNetPowerOn(PPDMDRVINS pDrvIns)
663{
664 LogFlow(("drvIntNetPowerOn\n"));
665 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
666 if (!pThis->fActivateEarlyDeactivateLate)
667 {
668 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
669 RTSemEventSignal(pThis->EventSuspended);
670 drvIntNetUpdateMacAddress(pThis);
671 drvIntNetSetActive(pThis, true /* fActive */);
672 }
673}
674
675
676/**
677 * Destruct a driver instance.
678 *
679 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
680 * resources can be freed correctly.
681 *
682 * @param pDrvIns The driver instance data.
683 */
684static DECLCALLBACK(void) drvIntNetDestruct(PPDMDRVINS pDrvIns)
685{
686 LogFlow(("drvIntNetDestruct\n"));
687 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
688
689 /*
690 * Indicate to the thread that it's time to quit.
691 */
692 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_TERMINATE);
693 ASMAtomicXchgSize(&pThis->fLinkDown, true);
694 RTSEMEVENT EventSuspended = pThis->EventSuspended;
695 pThis->EventSuspended = NIL_RTSEMEVENT;
696
697 /*
698 * Close the interface
699 */
700 if (pThis->hIf != INTNET_HANDLE_INVALID)
701 {
702 INTNETIFCLOSEREQ CloseReq;
703 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
704 CloseReq.Hdr.cbReq = sizeof(CloseReq);
705 CloseReq.pSession = NIL_RTR0PTR;
706 CloseReq.hIf = pThis->hIf;
707 pThis->hIf = INTNET_HANDLE_INVALID;
708 int rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_CLOSE, &CloseReq, sizeof(CloseReq));
709 AssertRC(rc);
710 }
711
712 /*
713 * Wait for the thread to terminate.
714 */
715 if (pThis->Thread != NIL_RTTHREAD)
716 {
717 if (EventSuspended != NIL_RTSEMEVENT)
718 RTSemEventSignal(EventSuspended);
719 int rc = RTThreadWait(pThis->Thread, 5000, NULL);
720 AssertRC(rc);
721 pThis->Thread = NIL_RTTHREAD;
722 }
723
724 /*
725 * Destroy the semaphores.
726 */
727 if (EventSuspended != NIL_RTSEMEVENT)
728 RTSemEventDestroy(EventSuspended);
729}
730
731
732/**
733 * Construct a TAP network transport driver instance.
734 *
735 * @returns VBox status.
736 * @param pDrvIns The driver instance data.
737 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
738 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
739 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
740 * iInstance it's expected to be used a bit in this function.
741 */
742static DECLCALLBACK(int) drvIntNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
743{
744 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
745 bool f;
746
747 /*
748 * Init the static parts.
749 */
750 pThis->pDrvIns = pDrvIns;
751 pThis->hIf = INTNET_HANDLE_INVALID;
752 pThis->Thread = NIL_RTTHREAD;
753 pThis->EventSuspended = NIL_RTSEMEVENT;
754 pThis->enmState = ASYNCSTATE_SUSPENDED;
755 pThis->fActivateEarlyDeactivateLate = false;
756 /* IBase */
757 pDrvIns->IBase.pfnQueryInterface = drvIntNetQueryInterface;
758 /* INetwork */
759 pThis->INetworkConnector.pfnSend = drvIntNetSend;
760 pThis->INetworkConnector.pfnSetPromiscuousMode = drvIntNetSetPromiscuousMode;
761 pThis->INetworkConnector.pfnNotifyLinkChanged = drvIntNetNotifyLinkChanged;
762
763 /*
764 * Validate the config.
765 */
766 if (!CFGMR3AreValuesValid(pCfgHandle,
767 "Network\0"
768 "Trunk\0"
769 "TrunkType\0"
770 "ReceiveBufferSize\0"
771 "SendBufferSize\0"
772 "RestrictAccess\0"
773 "SharedMacOnWire\0"
774 "IgnoreAllPromisc\0"
775 "QuietlyIgnoreAllPromisc\0"
776 "IgnoreClientPromisc\0"
777 "QuietlyIgnoreClientPromisc\0"
778 "IgnoreTrunkWirePromisc\0"
779 "QuietlyIgnoreTrunkWirePromisc\0"
780 "IgnoreTrunkHostPromisc\0"
781 "QuietlyIgnoreTrunkHostPromisc\0"
782 "IsService\0"))
783 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
784
785 /*
786 * Check that no-one is attached to us.
787 */
788 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, NULL);
789 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
790 {
791 AssertMsgFailed(("Configuration error: Cannot attach drivers to the TAP driver!\n"));
792 return VERR_PDM_DRVINS_NO_ATTACH;
793 }
794
795 /*
796 * Query the network port interface.
797 */
798 pThis->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
799 if (!pThis->pPort)
800 {
801 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
802 return VERR_PDM_MISSING_INTERFACE_ABOVE;
803 }
804 pThis->pConfigIf = (PPDMINETWORKCONFIG)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_CONFIG);
805
806 /*
807 * Read the configuration.
808 */
809 INTNETOPENREQ OpenReq;
810 memset(&OpenReq, 0, sizeof(OpenReq));
811 OpenReq.Hdr.cbReq = sizeof(OpenReq);
812 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
813 OpenReq.pSession = NIL_RTR0PTR;
814
815 /** @cfgm{Network, string}
816 * The name of the internal network to connect to.
817 */
818 rc = CFGMR3QueryString(pCfgHandle, "Network", OpenReq.szNetwork, sizeof(OpenReq.szNetwork));
819 if (RT_FAILURE(rc))
820 return PDMDRV_SET_ERROR(pDrvIns, rc,
821 N_("Configuration error: Failed to get the \"Network\" value"));
822 strcpy(pThis->szNetwork, OpenReq.szNetwork);
823
824 /** @cfgm{TrunkType, uint32_t, kIntNetTrunkType_None}
825 * The trunk connection type see INTNETTRUNKTYPE.
826 */
827 uint32_t u32TrunkType;
828 rc = CFGMR3QueryU32(pCfgHandle, "TrunkType", &u32TrunkType);
829 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
830 u32TrunkType = kIntNetTrunkType_None;
831 else if (RT_FAILURE(rc))
832 return PDMDRV_SET_ERROR(pDrvIns, rc,
833 N_("Configuration error: Failed to get the \"TrunkType\" value"));
834 OpenReq.enmTrunkType = (INTNETTRUNKTYPE)u32TrunkType;
835
836 /** @cfgm{Trunk, string, ""}
837 * The name of the trunk connection.
838 */
839 rc = CFGMR3QueryString(pCfgHandle, "Trunk", OpenReq.szTrunk, sizeof(OpenReq.szTrunk));
840 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
841 OpenReq.szTrunk[0] = '\0';
842 else if (RT_FAILURE(rc))
843 return PDMDRV_SET_ERROR(pDrvIns, rc,
844 N_("Configuration error: Failed to get the \"Trunk\" value"));
845
846 /** @cfgm{RestrictAccess, boolean, true}
847 * Whether to restrict the access to the network or if it should be public. Everyone on
848 * the computer can connect to a public network. Don't change this.
849 */
850 bool fRestrictAccess;
851 rc = CFGMR3QueryBool(pCfgHandle, "RestrictAccess", &fRestrictAccess);
852 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
853 fRestrictAccess = true;
854 else if (RT_FAILURE(rc))
855 return PDMDRV_SET_ERROR(pDrvIns, rc,
856 N_("Configuration error: Failed to get the \"RestrictAccess\" value"));
857 OpenReq.fFlags = fRestrictAccess ? 0 : INTNET_OPEN_FLAGS_PUBLIC;
858
859 /** @cfgm{IgnoreAllPromisc, boolean, false}
860 * When set all request for operating any interface or trunk in promiscuous
861 * mode will be ignored. */
862 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreAllPromisc", &f, false);
863 if (RT_FAILURE(rc))
864 return PDMDRV_SET_ERROR(pDrvIns, rc,
865 N_("Configuration error: Failed to get the \"IgnoreAllPromisc\" value"));
866 if (f)
867 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC;
868
869 /** @cfgm{QuietlyIgnoreAllPromisc, boolean, false}
870 * When set all request for operating any interface or trunk in promiscuous
871 * mode will be ignored. This differs from IgnoreAllPromisc in that clients
872 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
873 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreAllPromisc", &f, false);
874 if (RT_FAILURE(rc))
875 return PDMDRV_SET_ERROR(pDrvIns, rc,
876 N_("Configuration error: Failed to get the \"QuietlyIgnoreAllPromisc\" value"));
877 if (f)
878 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC;
879
880 /** @cfgm{IgnoreClientPromisc, boolean, false}
881 * When set all request for operating any non-trunk interface in promiscuous
882 * mode will be ignored. */
883 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreClientPromisc", &f, false);
884 if (RT_FAILURE(rc))
885 return PDMDRV_SET_ERROR(pDrvIns, rc,
886 N_("Configuration error: Failed to get the \"IgnoreClientPromisc\" value"));
887 if (f)
888 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC; /** @todo add special flag for this. */
889
890 /** @cfgm{QuietlyIgnoreClientPromisc, boolean, false}
891 * When set all request for operating any non-trunk interface promiscuous mode
892 * will be ignored. This differs from IgnoreClientPromisc in that clients won't
893 * get VERR_INTNET_INCOMPATIBLE_FLAGS. */
894 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreClientPromisc", &f, false);
895 if (RT_FAILURE(rc))
896 return PDMDRV_SET_ERROR(pDrvIns, rc,
897 N_("Configuration error: Failed to get the \"QuietlyIgnoreClientPromisc\" value"));
898 if (f)
899 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC; /** @todo add special flag for this. */
900
901 /** @cfgm{IgnoreTrunkWirePromisc, boolean, false}
902 * When set all request for operating the trunk-wire connection in promiscuous
903 * mode will be ignored. */
904 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreTrunkWirePromisc", &f, false);
905 if (RT_FAILURE(rc))
906 return PDMDRV_SET_ERROR(pDrvIns, rc,
907 N_("Configuration error: Failed to get the \"IgnoreTrunkWirePromisc\" value"));
908 if (f)
909 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE;
910
911 /** @cfgm{QuietlyIgnoreTrunkWirePromisc, boolean, false}
912 * When set all request for operating any trunk-wire connection promiscuous mode
913 * will be ignored. This differs from IgnoreTrunkWirePromisc in that clients
914 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
915 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreTrunkWirePromisc", &f, false);
916 if (RT_FAILURE(rc))
917 return PDMDRV_SET_ERROR(pDrvIns, rc,
918 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkWirePromisc\" value"));
919 if (f)
920 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE;
921
922 /** @cfgm{IgnoreTrunkHostPromisc, boolean, false}
923 * When set all request for operating the trunk-host connection in promiscuous
924 * mode will be ignored. */
925 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreTrunkHostPromisc", &f, false);
926 if (RT_FAILURE(rc))
927 return PDMDRV_SET_ERROR(pDrvIns, rc,
928 N_("Configuration error: Failed to get the \"IgnoreTrunkHostPromisc\" value"));
929 if (f)
930 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST;
931
932 /** @cfgm{QuietlyIgnoreTrunkHostPromisc, boolean, false}
933 * When set all request for operating any trunk-host connection promiscuous mode
934 * will be ignored. This differs from IgnoreTrunkHostPromisc in that clients
935 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
936 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreTrunkHostPromisc", &f, false);
937 if (RT_FAILURE(rc))
938 return PDMDRV_SET_ERROR(pDrvIns, rc,
939 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkHostPromisc\" value"));
940 if (f)
941 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST;
942
943 /** @todo flags for not sending to the host and for setting the trunk-wire
944 * connection in promiscuous mode. */
945
946
947 /** @cfgm{SharedMacOnWire, boolean, false}
948 * Whether to shared the MAC address of the host interface when using the wire. When
949 * attaching to a wireless NIC this option is usally a requirement.
950 */
951 bool fSharedMacOnWire;
952 rc = CFGMR3QueryBoolDef(pCfgHandle, "SharedMacOnWire", &fSharedMacOnWire, false);
953 if (RT_FAILURE(rc))
954 return PDMDRV_SET_ERROR(pDrvIns, rc,
955 N_("Configuration error: Failed to get the \"SharedMacOnWire\" value"));
956 if (fSharedMacOnWire)
957 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
958
959 /** @cfgm{ReceiveBufferSize, uint32_t, 218 KB}
960 * The size of the receive buffer.
961 */
962 rc = CFGMR3QueryU32(pCfgHandle, "ReceiveBufferSize", &OpenReq.cbRecv);
963 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
964 OpenReq.cbRecv = 218 * _1K ;
965 else if (RT_FAILURE(rc))
966 return PDMDRV_SET_ERROR(pDrvIns, rc,
967 N_("Configuration error: Failed to get the \"ReceiveBufferSize\" value"));
968
969 /** @cfgm{SendBufferSize, uint32_t, 36 KB}
970 * The size of the send (transmit) buffer.
971 * This should be more than twice the size of the larges frame size because
972 * the ring buffer is very simple and doesn't support splitting up frames
973 * nor inserting padding. So, if this is too close to the frame size the
974 * header will fragment the buffer such that the frame won't fit on either
975 * side of it and the code will get very upset about it all.
976 */
977 rc = CFGMR3QueryU32(pCfgHandle, "SendBufferSize", &OpenReq.cbSend);
978 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
979 OpenReq.cbSend = 36*_1K;
980 else if (RT_FAILURE(rc))
981 return PDMDRV_SET_ERROR(pDrvIns, rc,
982 N_("Configuration error: Failed to get the \"SendBufferSize\" value"));
983 if (OpenReq.cbSend < 32)
984 return PDMDRV_SET_ERROR(pDrvIns, rc,
985 N_("Configuration error: The \"SendBufferSize\" value is too small"));
986 if (OpenReq.cbSend < 16384*2 + 64)
987 LogRel(("DrvIntNet: Warning! SendBufferSize=%u, Recommended minimum size %u butes.\n", OpenReq.cbSend, 16384*2 + 64));
988
989 /** @cfgm{IsService, boolean, true}
990 * This alterns the way the thread is suspended and resumed. When it's being used by
991 * a service such as LWIP/iSCSI it shouldn't suspend immediately like for a NIC.
992 */
993 rc = CFGMR3QueryBool(pCfgHandle, "IsService", &pThis->fActivateEarlyDeactivateLate);
994 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
995 pThis->fActivateEarlyDeactivateLate = false;
996 else if (RT_FAILURE(rc))
997 return PDMDRV_SET_ERROR(pDrvIns, rc,
998 N_("Configuration error: Failed to get the \"IsService\" value"));
999
1000 LogRel(("IntNet#%u: szNetwork={%s} enmTrunkType=%d szTrunk={%s} fFlags=%#x cbRecv=%u cbSend=%u\n",
1001 pDrvIns->iInstance, OpenReq.szNetwork, OpenReq.enmTrunkType, OpenReq.szTrunk, OpenReq.fFlags,
1002 OpenReq.cbRecv, OpenReq.cbSend));
1003
1004#ifdef RT_OS_DARWIN
1005 /* Temporary hack: attach to a network with the name 'if=en0' and you're hitting the wire. */
1006 if ( !OpenReq.szTrunk[0]
1007 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1008 && !strncmp(pThis->szNetwork, "if=en", sizeof("if=en") - 1)
1009 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("if=en") - 1])
1010 && !pThis->szNetwork[sizeof("if=en")])
1011 {
1012 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1013 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("if=") - 1]);
1014 }
1015 /* Temporary hack: attach to a network with the name 'wif=en0' and you're on the air. */
1016 if ( !OpenReq.szTrunk[0]
1017 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1018 && !strncmp(pThis->szNetwork, "wif=en", sizeof("wif=en") - 1)
1019 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("wif=en") - 1])
1020 && !pThis->szNetwork[sizeof("wif=en")])
1021 {
1022 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1023 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1024 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("wif=") - 1]);
1025 }
1026
1027#elif defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
1028 if (OpenReq.enmTrunkType == kIntNetTrunkType_NetFlt)
1029 {
1030# ifndef VBOX_NETFLT_ONDEMAND_BIND
1031 /*
1032 * We have a ndis filter driver started on system boot before the VBoxDrv,
1033 * tell the filter driver to init VBoxNetFlt functionality.
1034 */
1035 rc = drvIntNetWinConstruct(pDrvIns, pCfgHandle);
1036 AssertLogRelMsgRCReturn(rc, ("drvIntNetWinConstruct failed, rc=%Rrc", rc), rc);
1037# endif
1038
1039 /*
1040 * <Describe what this does here or/and in the function docs of drvIntNetWinIfGuidToBindName>.
1041 */
1042 char szBindName[INTNET_MAX_TRUNK_NAME];
1043 rc = drvIntNetWinIfGuidToBindName(OpenReq.szTrunk, szBindName, INTNET_MAX_TRUNK_NAME);
1044 AssertLogRelMsgRCReturn(rc, ("drvIntNetWinIfGuidToBindName failed, rc=%Rrc", rc), rc);
1045 strcpy(OpenReq.szTrunk, szBindName);
1046 }
1047#endif /* WINDOWS && NETFLT */
1048
1049 /*
1050 * Create the event semaphores
1051 */
1052 rc = RTSemEventCreate(&pThis->EventSuspended);
1053 if (RT_FAILURE(rc))
1054 return rc;
1055
1056 /*
1057 * Create the interface.
1058 */
1059 OpenReq.hIf = INTNET_HANDLE_INVALID;
1060 rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_OPEN, &OpenReq, sizeof(OpenReq));
1061 if (RT_FAILURE(rc))
1062 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1063 N_("Failed to open/create the internal network '%s'"), pThis->szNetwork);
1064 AssertRelease(OpenReq.hIf != INTNET_HANDLE_INVALID);
1065 pThis->hIf = OpenReq.hIf;
1066 Log(("IntNet%d: hIf=%RX32 '%s'\n", pDrvIns->iInstance, pThis->hIf, pThis->szNetwork));
1067
1068 /*
1069 * Get default buffer.
1070 */
1071 INTNETIFGETRING3BUFFERREQ GetRing3BufferReq;
1072 GetRing3BufferReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1073 GetRing3BufferReq.Hdr.cbReq = sizeof(GetRing3BufferReq);
1074 GetRing3BufferReq.pSession = NIL_RTR0PTR;
1075 GetRing3BufferReq.hIf = pThis->hIf;
1076 GetRing3BufferReq.pRing3Buf = NULL;
1077 rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_GET_RING3_BUFFER, &GetRing3BufferReq, sizeof(GetRing3BufferReq));
1078 if (RT_FAILURE(rc))
1079 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1080 N_("Failed to get ring-3 buffer for the newly created interface to '%s'"), pThis->szNetwork);
1081 AssertRelease(VALID_PTR(GetRing3BufferReq.pRing3Buf));
1082 pThis->pBuf = GetRing3BufferReq.pRing3Buf;
1083
1084 /*
1085 * Create the async I/O thread.
1086 * Note! Using a PDM thread here doesn't fit with the IsService=true operation.
1087 */
1088 rc = RTThreadCreate(&pThis->Thread, drvIntNetAsyncIoThread, pThis, _128K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET");
1089 if (RT_FAILURE(rc))
1090 {
1091 AssertRC(rc);
1092 return rc;
1093 }
1094
1095 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cbStatRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Net/IntNet%d/Bytes/Received", pDrvIns->iInstance);
1096 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cbStatSend, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Net/IntNet%d/Bytes/Sent", pDrvIns->iInstance);
1097 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatRecvs, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received packets.", "/Net/IntNet%d/Packets/Received", pDrvIns->iInstance);
1098 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatSends, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent packets.", "/Net/IntNet%d/Packets/Sent", pDrvIns->iInstance);
1099 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatLost, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent packets.", "/Net/IntNet%d/Packets/Lost", pDrvIns->iInstance);
1100 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);
1101#ifdef VBOX_WITH_STATISTICS
1102 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Net/IntNet%d/Receive", pDrvIns->iInstance);
1103 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Net/IntNet%d/Transmit", pDrvIns->iInstance);
1104#endif
1105
1106 /*
1107 * Activate data transmission as early as possible
1108 */
1109 if (pThis->fActivateEarlyDeactivateLate)
1110 {
1111 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
1112 RTSemEventSignal(pThis->EventSuspended);
1113 drvIntNetUpdateMacAddress(pThis);
1114 drvIntNetSetActive(pThis, true /* fActive */);
1115 }
1116
1117 return rc;
1118}
1119
1120
1121/**
1122 * Internal networking transport driver registration record.
1123 */
1124const PDMDRVREG g_DrvIntNet =
1125{
1126 /* u32Version */
1127 PDM_DRVREG_VERSION,
1128 /* szDriverName */
1129 "IntNet",
1130 /* pszDescription */
1131 "Internal Networking Transport Driver",
1132 /* fFlags */
1133 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1134 /* fClass. */
1135 PDM_DRVREG_CLASS_NETWORK,
1136 /* cMaxInstances */
1137 ~0,
1138 /* cbInstance */
1139 sizeof(DRVINTNET),
1140 /* pfnConstruct */
1141 drvIntNetConstruct,
1142 /* pfnDestruct */
1143 drvIntNetDestruct,
1144 /* pfnIOCtl */
1145 NULL,
1146 /* pfnPowerOn */
1147 drvIntNetPowerOn,
1148 /* pfnReset */
1149 NULL,
1150 /* pfnSuspend */
1151 drvIntNetSuspend,
1152 /* pfnResume */
1153 drvIntNetResume,
1154 /* pfnDetach */
1155 NULL,
1156 /* pfnPowerOff */
1157 drvIntNetPowerOff
1158};
1159
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