VirtualBox

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

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

DrvIntNet,DrvTAP: Deregister statistics during destruction. (untested)

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