VirtualBox

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

Last change on this file since 18235 was 18208, checked in by vboxsync, 16 years ago

#3569: DHCP Server is now started from VBoxSVC and terminates with it.

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