VirtualBox

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

Last change on this file since 19167 was 19079, checked in by vboxsync, 16 years ago

DrvIntNet: correct the unit for 4 of the stats.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.1 KB
Line 
1/* $Id: DrvIntNet.cpp 19079 2009-04-21 13:59:10Z 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
728/**
729 * Construct a TAP network transport driver instance.
730 *
731 * @returns VBox status.
732 * @param pDrvIns The driver instance data.
733 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
734 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
735 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
736 * iInstance it's expected to be used a bit in this function.
737 */
738static DECLCALLBACK(int) drvIntNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
739{
740 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
741 bool f;
742
743 /*
744 * Init the static parts.
745 */
746 pThis->pDrvIns = pDrvIns;
747 pThis->hIf = INTNET_HANDLE_INVALID;
748 pThis->Thread = NIL_RTTHREAD;
749 pThis->EventSuspended = NIL_RTSEMEVENT;
750 pThis->enmState = ASYNCSTATE_SUSPENDED;
751 pThis->fActivateEarlyDeactivateLate = false;
752 /* IBase */
753 pDrvIns->IBase.pfnQueryInterface = drvIntNetQueryInterface;
754 /* INetwork */
755 pThis->INetworkConnector.pfnSend = drvIntNetSend;
756 pThis->INetworkConnector.pfnSetPromiscuousMode = drvIntNetSetPromiscuousMode;
757 pThis->INetworkConnector.pfnNotifyLinkChanged = drvIntNetNotifyLinkChanged;
758
759 /*
760 * Validate the config.
761 */
762 if (!CFGMR3AreValuesValid(pCfgHandle,
763 "Network\0"
764 "Trunk\0"
765 "TrunkType\0"
766 "ReceiveBufferSize\0"
767 "SendBufferSize\0"
768 "RestrictAccess\0"
769 "SharedMacOnWire\0"
770 "IgnoreAllPromisc\0"
771 "QuietlyIgnoreAllPromisc\0"
772 "IgnoreClientPromisc\0"
773 "QuietlyIgnoreClientPromisc\0"
774 "IgnoreTrunkWirePromisc\0"
775 "QuietlyIgnoreTrunkWirePromisc\0"
776 "IgnoreTrunkHostPromisc\0"
777 "QuietlyIgnoreTrunkHostPromisc\0"
778 "IsService\0"))
779 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
780
781 /*
782 * Check that no-one is attached to us.
783 */
784 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, NULL);
785 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
786 {
787 AssertMsgFailed(("Configuration error: Cannot attach drivers to the TAP driver!\n"));
788 return VERR_PDM_DRVINS_NO_ATTACH;
789 }
790
791 /*
792 * Query the network port interface.
793 */
794 pThis->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
795 if (!pThis->pPort)
796 {
797 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
798 return VERR_PDM_MISSING_INTERFACE_ABOVE;
799 }
800 pThis->pConfigIf = (PPDMINETWORKCONFIG)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_CONFIG);
801
802 /*
803 * Read the configuration.
804 */
805 INTNETOPENREQ OpenReq;
806 memset(&OpenReq, 0, sizeof(OpenReq));
807 OpenReq.Hdr.cbReq = sizeof(OpenReq);
808 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
809 OpenReq.pSession = NIL_RTR0PTR;
810
811 /** @cfgm{Network, string}
812 * The name of the internal network to connect to.
813 */
814 rc = CFGMR3QueryString(pCfgHandle, "Network", OpenReq.szNetwork, sizeof(OpenReq.szNetwork));
815 if (RT_FAILURE(rc))
816 return PDMDRV_SET_ERROR(pDrvIns, rc,
817 N_("Configuration error: Failed to get the \"Network\" value"));
818 strcpy(pThis->szNetwork, OpenReq.szNetwork);
819
820 /** @cfgm{TrunkType, uint32_t, kIntNetTrunkType_None}
821 * The trunk connection type see INTNETTRUNKTYPE.
822 */
823 uint32_t u32TrunkType;
824 rc = CFGMR3QueryU32(pCfgHandle, "TrunkType", &u32TrunkType);
825 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
826 u32TrunkType = kIntNetTrunkType_None;
827 else if (RT_FAILURE(rc))
828 return PDMDRV_SET_ERROR(pDrvIns, rc,
829 N_("Configuration error: Failed to get the \"TrunkType\" value"));
830 OpenReq.enmTrunkType = (INTNETTRUNKTYPE)u32TrunkType;
831
832 /** @cfgm{Trunk, string, ""}
833 * The name of the trunk connection.
834 */
835 rc = CFGMR3QueryString(pCfgHandle, "Trunk", OpenReq.szTrunk, sizeof(OpenReq.szTrunk));
836 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
837 OpenReq.szTrunk[0] = '\0';
838 else if (RT_FAILURE(rc))
839 return PDMDRV_SET_ERROR(pDrvIns, rc,
840 N_("Configuration error: Failed to get the \"Trunk\" value"));
841
842 /** @cfgm{RestrictAccess, boolean, true}
843 * Whether to restrict the access to the network or if it should be public. Everyone on
844 * the computer can connect to a public network. Don't change this.
845 */
846 bool fRestrictAccess;
847 rc = CFGMR3QueryBool(pCfgHandle, "RestrictAccess", &fRestrictAccess);
848 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
849 fRestrictAccess = true;
850 else if (RT_FAILURE(rc))
851 return PDMDRV_SET_ERROR(pDrvIns, rc,
852 N_("Configuration error: Failed to get the \"RestrictAccess\" value"));
853 OpenReq.fFlags = fRestrictAccess ? 0 : INTNET_OPEN_FLAGS_PUBLIC;
854
855 /** @cfgm{IgnoreAllPromisc, boolean, false}
856 * When set all request for operating any interface or trunk in promiscuous
857 * mode will be ignored. */
858 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreAllPromisc", &f, false);
859 if (RT_FAILURE(rc))
860 return PDMDRV_SET_ERROR(pDrvIns, rc,
861 N_("Configuration error: Failed to get the \"IgnoreAllPromisc\" value"));
862 if (f)
863 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC;
864
865 /** @cfgm{QuietlyIgnoreAllPromisc, boolean, false}
866 * When set all request for operating any interface or trunk in promiscuous
867 * mode will be ignored. This differs from IgnoreAllPromisc in that clients
868 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
869 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreAllPromisc", &f, false);
870 if (RT_FAILURE(rc))
871 return PDMDRV_SET_ERROR(pDrvIns, rc,
872 N_("Configuration error: Failed to get the \"QuietlyIgnoreAllPromisc\" value"));
873 if (f)
874 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC;
875
876 /** @cfgm{IgnoreClientPromisc, boolean, false}
877 * When set all request for operating any non-trunk interface in promiscuous
878 * mode will be ignored. */
879 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreClientPromisc", &f, false);
880 if (RT_FAILURE(rc))
881 return PDMDRV_SET_ERROR(pDrvIns, rc,
882 N_("Configuration error: Failed to get the \"IgnoreClientPromisc\" value"));
883 if (f)
884 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC; /** @todo add special flag for this. */
885
886 /** @cfgm{QuietlyIgnoreClientPromisc, boolean, false}
887 * When set all request for operating any non-trunk interface promiscuous mode
888 * will be ignored. This differs from IgnoreClientPromisc in that clients won't
889 * get VERR_INTNET_INCOMPATIBLE_FLAGS. */
890 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreClientPromisc", &f, false);
891 if (RT_FAILURE(rc))
892 return PDMDRV_SET_ERROR(pDrvIns, rc,
893 N_("Configuration error: Failed to get the \"QuietlyIgnoreClientPromisc\" value"));
894 if (f)
895 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC; /** @todo add special flag for this. */
896
897 /** @cfgm{IgnoreTrunkWirePromisc, boolean, false}
898 * When set all request for operating the trunk-wire connection in promiscuous
899 * mode will be ignored. */
900 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreTrunkWirePromisc", &f, false);
901 if (RT_FAILURE(rc))
902 return PDMDRV_SET_ERROR(pDrvIns, rc,
903 N_("Configuration error: Failed to get the \"IgnoreTrunkWirePromisc\" value"));
904 if (f)
905 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE;
906
907 /** @cfgm{QuietlyIgnoreTrunkWirePromisc, boolean, false}
908 * When set all request for operating any trunk-wire connection promiscuous mode
909 * will be ignored. This differs from IgnoreTrunkWirePromisc in that clients
910 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
911 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreTrunkWirePromisc", &f, false);
912 if (RT_FAILURE(rc))
913 return PDMDRV_SET_ERROR(pDrvIns, rc,
914 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkWirePromisc\" value"));
915 if (f)
916 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE;
917
918 /** @cfgm{IgnoreTrunkHostPromisc, boolean, false}
919 * When set all request for operating the trunk-host connection in promiscuous
920 * mode will be ignored. */
921 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreTrunkHostPromisc", &f, false);
922 if (RT_FAILURE(rc))
923 return PDMDRV_SET_ERROR(pDrvIns, rc,
924 N_("Configuration error: Failed to get the \"IgnoreTrunkHostPromisc\" value"));
925 if (f)
926 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST;
927
928 /** @cfgm{QuietlyIgnoreTrunkHostPromisc, boolean, false}
929 * When set all request for operating any trunk-host connection promiscuous mode
930 * will be ignored. This differs from IgnoreTrunkHostPromisc in that clients
931 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
932 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreTrunkHostPromisc", &f, false);
933 if (RT_FAILURE(rc))
934 return PDMDRV_SET_ERROR(pDrvIns, rc,
935 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkHostPromisc\" value"));
936 if (f)
937 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST;
938
939 /** @todo flags for not sending to the host and for setting the trunk-wire
940 * connection in promiscuous mode. */
941
942
943 /** @cfgm{SharedMacOnWire, boolean, false}
944 * Whether to shared the MAC address of the host interface when using the wire. When
945 * attaching to a wireless NIC this option is usally a requirement.
946 */
947 bool fSharedMacOnWire;
948 rc = CFGMR3QueryBoolDef(pCfgHandle, "SharedMacOnWire", &fSharedMacOnWire, false);
949 if (RT_FAILURE(rc))
950 return PDMDRV_SET_ERROR(pDrvIns, rc,
951 N_("Configuration error: Failed to get the \"SharedMacOnWire\" value"));
952 if (fSharedMacOnWire)
953 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
954
955 /** @cfgm{ReceiveBufferSize, uint32_t, 218 KB}
956 * The size of the receive buffer.
957 */
958 rc = CFGMR3QueryU32(pCfgHandle, "ReceiveBufferSize", &OpenReq.cbRecv);
959 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
960 OpenReq.cbRecv = 218 * _1K ;
961 else if (RT_FAILURE(rc))
962 return PDMDRV_SET_ERROR(pDrvIns, rc,
963 N_("Configuration error: Failed to get the \"ReceiveBufferSize\" value"));
964
965 /** @cfgm{SendBufferSize, uint32_t, 36 KB}
966 * The size of the send (transmit) buffer.
967 * This should be more than twice the size of the larges frame size because
968 * the ring buffer is very simple and doesn't support splitting up frames
969 * nor inserting padding. So, if this is too close to the frame size the
970 * header will fragment the buffer such that the frame won't fit on either
971 * side of it and the code will get very upset about it all.
972 */
973 rc = CFGMR3QueryU32(pCfgHandle, "SendBufferSize", &OpenReq.cbSend);
974 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
975 OpenReq.cbSend = 36*_1K;
976 else if (RT_FAILURE(rc))
977 return PDMDRV_SET_ERROR(pDrvIns, rc,
978 N_("Configuration error: Failed to get the \"SendBufferSize\" value"));
979 if (OpenReq.cbSend < 32)
980 return PDMDRV_SET_ERROR(pDrvIns, rc,
981 N_("Configuration error: The \"SendBufferSize\" value is too small"));
982 if (OpenReq.cbSend < 16384*2 + 64)
983 LogRel(("DrvIntNet: Warning! SendBufferSize=%u, Recommended minimum size %u butes.\n", OpenReq.cbSend, 16384*2 + 64));
984
985 /** @cfgm{IsService, boolean, true}
986 * This alterns the way the thread is suspended and resumed. When it's being used by
987 * a service such as LWIP/iSCSI it shouldn't suspend immediately like for a NIC.
988 */
989 rc = CFGMR3QueryBool(pCfgHandle, "IsService", &pThis->fActivateEarlyDeactivateLate);
990 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
991 pThis->fActivateEarlyDeactivateLate = false;
992 else if (RT_FAILURE(rc))
993 return PDMDRV_SET_ERROR(pDrvIns, rc,
994 N_("Configuration error: Failed to get the \"IsService\" value"));
995
996 LogRel(("IntNet#%u: szNetwork={%s} enmTrunkType=%d szTrunk={%s} fFlags=%#x cbRecv=%u cbSend=%u\n",
997 pDrvIns->iInstance, OpenReq.szNetwork, OpenReq.enmTrunkType, OpenReq.szTrunk, OpenReq.fFlags,
998 OpenReq.cbRecv, OpenReq.cbSend));
999
1000#ifdef RT_OS_DARWIN
1001 /* Temporary hack: attach to a network with the name 'if=en0' and you're hitting the wire. */
1002 if ( !OpenReq.szTrunk[0]
1003 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1004 && !strncmp(pThis->szNetwork, "if=en", sizeof("if=en") - 1)
1005 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("if=en") - 1])
1006 && !pThis->szNetwork[sizeof("if=en")])
1007 {
1008 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1009 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("if=") - 1]);
1010 }
1011 /* Temporary hack: attach to a network with the name 'wif=en0' and you're on the air. */
1012 if ( !OpenReq.szTrunk[0]
1013 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1014 && !strncmp(pThis->szNetwork, "wif=en", sizeof("wif=en") - 1)
1015 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("wif=en") - 1])
1016 && !pThis->szNetwork[sizeof("wif=en")])
1017 {
1018 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1019 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1020 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("wif=") - 1]);
1021 }
1022#endif /* DARWIN */
1023
1024 /*
1025 * Create the event semaphores
1026 */
1027 rc = RTSemEventCreate(&pThis->EventSuspended);
1028 if (RT_FAILURE(rc))
1029 return rc;
1030
1031 /*
1032 * Create the interface.
1033 */
1034 OpenReq.hIf = INTNET_HANDLE_INVALID;
1035 rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_OPEN, &OpenReq, sizeof(OpenReq));
1036 if (RT_FAILURE(rc))
1037 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1038 N_("Failed to open/create the internal network '%s'"), pThis->szNetwork);
1039 AssertRelease(OpenReq.hIf != INTNET_HANDLE_INVALID);
1040 pThis->hIf = OpenReq.hIf;
1041 Log(("IntNet%d: hIf=%RX32 '%s'\n", pDrvIns->iInstance, pThis->hIf, pThis->szNetwork));
1042
1043 /*
1044 * Get default buffer.
1045 */
1046 INTNETIFGETRING3BUFFERREQ GetRing3BufferReq;
1047 GetRing3BufferReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1048 GetRing3BufferReq.Hdr.cbReq = sizeof(GetRing3BufferReq);
1049 GetRing3BufferReq.pSession = NIL_RTR0PTR;
1050 GetRing3BufferReq.hIf = pThis->hIf;
1051 GetRing3BufferReq.pRing3Buf = NULL;
1052 rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_GET_RING3_BUFFER, &GetRing3BufferReq, sizeof(GetRing3BufferReq));
1053 if (RT_FAILURE(rc))
1054 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1055 N_("Failed to get ring-3 buffer for the newly created interface to '%s'"), pThis->szNetwork);
1056 AssertRelease(VALID_PTR(GetRing3BufferReq.pRing3Buf));
1057 pThis->pBuf = GetRing3BufferReq.pRing3Buf;
1058
1059 /*
1060 * Create the async I/O thread.
1061 * Note! Using a PDM thread here doesn't fit with the IsService=true operation.
1062 */
1063 rc = RTThreadCreate(&pThis->Thread, drvIntNetAsyncIoThread, pThis, _128K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET");
1064 if (RT_FAILURE(rc))
1065 {
1066 AssertRC(rc);
1067 return rc;
1068 }
1069
1070 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cbStatRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Net/IntNet%d/Bytes/Received", pDrvIns->iInstance);
1071 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cbStatSend, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Net/IntNet%d/Bytes/Sent", pDrvIns->iInstance);
1072 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatRecvs, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of received packets.", "/Net/IntNet%d/Packets/Received", pDrvIns->iInstance);
1073 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatSends, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of sent packets.", "/Net/IntNet%d/Packets/Sent", pDrvIns->iInstance);
1074 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatLost, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of sent packets.", "/Net/IntNet%d/Packets/Lost", pDrvIns->iInstance);
1075 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);
1076#ifdef VBOX_WITH_STATISTICS
1077 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Net/IntNet%d/Receive", pDrvIns->iInstance);
1078 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Net/IntNet%d/Transmit", pDrvIns->iInstance);
1079#endif
1080
1081 /*
1082 * Activate data transmission as early as possible
1083 */
1084 if (pThis->fActivateEarlyDeactivateLate)
1085 {
1086 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
1087 RTSemEventSignal(pThis->EventSuspended);
1088 drvIntNetUpdateMacAddress(pThis);
1089 drvIntNetSetActive(pThis, true /* fActive */);
1090 }
1091
1092 return rc;
1093}
1094
1095
1096/**
1097 * Internal networking transport driver registration record.
1098 */
1099const PDMDRVREG g_DrvIntNet =
1100{
1101 /* u32Version */
1102 PDM_DRVREG_VERSION,
1103 /* szDriverName */
1104 "IntNet",
1105 /* pszDescription */
1106 "Internal Networking Transport Driver",
1107 /* fFlags */
1108 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1109 /* fClass. */
1110 PDM_DRVREG_CLASS_NETWORK,
1111 /* cMaxInstances */
1112 ~0,
1113 /* cbInstance */
1114 sizeof(DRVINTNET),
1115 /* pfnConstruct */
1116 drvIntNetConstruct,
1117 /* pfnDestruct */
1118 drvIntNetDestruct,
1119 /* pfnIOCtl */
1120 NULL,
1121 /* pfnPowerOn */
1122 drvIntNetPowerOn,
1123 /* pfnReset */
1124 NULL,
1125 /* pfnSuspend */
1126 drvIntNetSuspend,
1127 /* pfnResume */
1128 drvIntNetResume,
1129 /* pfnDetach */
1130 NULL,
1131 /* pfnPowerOff */
1132 drvIntNetPowerOff
1133};
1134
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