VirtualBox

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

Last change on this file since 4071 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.8 KB
Line 
1/** @file
2 *
3 * VBox network devices:
4 * Internal network transport driver
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#define LOG_GROUP LOG_GROUP_DRV_INTNET
24#include <VBox/pdmdrv.h>
25#include <VBox/cfgm.h>
26#include <VBox/intnet.h>
27#include <VBox/vmm.h>
28#include <VBox/err.h>
29
30#include <VBox/log.h>
31#include <iprt/asm.h>
32#include <iprt/assert.h>
33#include <iprt/thread.h>
34#include <iprt/semaphore.h>
35#include <iprt/string.h>
36#include <iprt/time.h>
37
38#include "Builtins.h"
39
40
41/*******************************************************************************
42* Structures and Typedefs *
43*******************************************************************************/
44/**
45 * The state of the asynchronous thread.
46 */
47typedef enum ASYNCSTATE
48{
49 /** The thread is suspended. */
50 ASYNCSTATE_SUSPENDED = 1,
51 /** The thread is running. */
52 ASYNCSTATE_RUNNING,
53 /** The thread must (/has) terminate. */
54 ASYNCSTATE_TERMINATE,
55 /** The usual 32-bit type blowup. */
56 ASYNCSTATE_32BIT_HACK = 0x7fffffff
57} ASYNCSTATE;
58
59/**
60 * Block driver instance data.
61 */
62typedef struct DRVINTNET
63{
64 /** The network interface. */
65 PDMINETWORKCONNECTOR INetworkConnector;
66 /** The network interface. */
67 PPDMINETWORKPORT pPort;
68 /** Pointer to the driver instance. */
69 PPDMDRVINS pDrvIns;
70 /** Interface handle. */
71 INTNETIFHANDLE hIf;
72 /** Pointer to the communication buffer. */
73 PINTNETBUF pBuf;
74 /** The thread state. */
75 ASYNCSTATE volatile enmState;
76 /** Reader thread. */
77 RTTHREAD Thread;
78 /** Event semaphore the Thread waits on while the VM is suspended. */
79 RTSEMEVENT EventSuspended;
80 /** Indicates that we're in waiting for recieve space to become available. */
81 bool volatile fOutOfSpace;
82 /** Event semaphore the Thread sleeps on while polling for more
83 * buffer space to become available.
84 * @todo We really need the network device to signal this! */
85 RTSEMEVENT EventOutOfSpace;
86 /** Set if the link is down.
87 * When the link is down all incoming packets will be dropped. */
88 bool volatile fLinkDown;
89
90#ifdef VBOX_WITH_STATISTICS
91 /** Profiling packet transmit runs. */
92 STAMPROFILE StatTransmit;
93 /** Profiling packet receive runs. */
94 STAMPROFILEADV StatReceive;
95 /** Number of receive overflows. */
96 STAMPROFILE StatRecvOverflows;
97#endif /* VBOX_WITH_STATISTICS */
98
99#ifdef LOG_ENABLED
100 /** The nano ts of the last transfer. */
101 uint64_t u64LastTransferTS;
102 /** The nano ts of the last receive. */
103 uint64_t u64LastReceiveTS;
104#endif
105 /** The network name. */
106 char szNetwork[INTNET_MAX_NETWORK_NAME];
107} DRVINTNET, *PDRVINTNET;
108
109
110/** Converts a pointer to DRVINTNET::INetworkConnector to a PDRVINTNET. */
111#define PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface) ( (PDRVINTNET)((uintptr_t)pInterface - RT_OFFSETOF(DRVINTNET, INetworkConnector)) )
112
113
114/**
115 * Send data to the network.
116 *
117 * @returns VBox status code.
118 * @param pInterface Pointer to the interface structure containing the called function pointer.
119 * @param pvBuf Data to send.
120 * @param cb Number of bytes to send.
121 * @thread EMT
122 */
123static DECLCALLBACK(int) drvIntNetSend(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
124{
125 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
126 STAM_PROFILE_START(&pThis->StatTransmit, a);
127
128#ifdef LOG_ENABLED
129 uint64_t u64Now = RTTimeProgramNanoTS();
130 LogFlow(("drvIntNetSend: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
131 cb, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
132 pThis->u64LastTransferTS = u64Now;
133 Log2(("drvIntNetSend: pvBuf=%p cb=%#x\n"
134 "%.*Vhxd\n",
135 pvBuf, cb, cb, pvBuf));
136#endif
137
138 /** @todo copy to send buffer, this is not safe. */
139 INTNETIFSENDARGS SendArgs;
140 SendArgs.hIf = pThis->hIf;
141 SendArgs.pvFrame = pvBuf;
142 SendArgs.cbFrame = cb;
143 int rc = pThis->pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pThis->pDrvIns, VMMR0_DO_INTNET_IF_SEND, &SendArgs, sizeof(SendArgs));
144
145 STAM_PROFILE_STOP(&pThis->StatTransmit, a);
146 AssertRC(rc);
147 return rc;
148}
149
150
151/**
152 * Set promiscuous mode.
153 *
154 * This is called when the promiscuous mode is set. This means that there doesn't have
155 * to be a mode change when it's called.
156 *
157 * @param pInterface Pointer to the interface structure containing the called function pointer.
158 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
159 * @thread EMT
160 */
161static DECLCALLBACK(void) drvIntNetSetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
162{
163 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
164 INTNETIFSETPROMISCUOUSMODEARGS SetArgs = {0};
165 SetArgs.hIf = pThis->hIf;
166 SetArgs.fPromiscuous = fPromiscuous;
167 int rc = pThis->pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pThis->pDrvIns, VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, &SetArgs, sizeof(SetArgs));
168 LogFlow(("drvIntNetSetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
169 AssertRC(rc);
170}
171
172
173/**
174 * Notification on link status changes.
175 *
176 * @param pInterface Pointer to the interface structure containing the called function pointer.
177 * @param enmLinkState The new link state.
178 * @thread EMT
179 */
180static DECLCALLBACK(void) drvIntNetNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
181{
182 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
183 bool fLinkDown;
184 switch (enmLinkState)
185 {
186 case PDMNETWORKLINKSTATE_DOWN:
187 case PDMNETWORKLINKSTATE_DOWN_RESUME:
188 fLinkDown = true;
189 break;
190 default:
191 AssertMsgFailed(("enmLinkState=%d\n", enmLinkState));
192 case PDMNETWORKLINKSTATE_UP:
193 fLinkDown = false;
194 break;
195 }
196 LogFlow(("drvIntNetNotifyLinkChanged: enmLinkState=%d %d->%d\n", enmLinkState, pThis->fLinkDown, fLinkDown));
197 ASMAtomicXchgSize(&pThis->fLinkDown, fLinkDown);
198}
199
200
201/**
202 * More receive buffer has become available.
203 *
204 * This is called when the NIC frees up receive buffers.
205 *
206 * @param pInterface Pointer to the interface structure containing the called function pointer.
207 * @remark This function isn't called by pcnet nor yet.
208 * @thread EMT
209 */
210static DECLCALLBACK(void) drvIntNetNotifyCanReceive(PPDMINETWORKCONNECTOR pInterface)
211{
212 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
213 if (pThis->fOutOfSpace)
214 {
215 LogFlow(("drvIntNetNotifyCanReceive: signaling\n"));
216 RTSemEventSignal(pThis->EventOutOfSpace);
217 }
218}
219
220
221/**
222 * Wait for space to become available up the driver/device chain.
223 *
224 * @returns VINF_SUCCESS if space is available.
225 * @returns VERR_STATE_CHANGED if the state changed.
226 * @returns VBox status code on other errors.
227 * @param pThis Pointer to the instance data.
228 * @param cbFrame The frame size.
229 */
230static int drvIntNetAsyncIoWaitForSpace(PDRVINTNET pThis, size_t cbFrame)
231{
232 LogFlow(("drvIntNetAsyncIoWaitForSpace: cbFrame=%zu\n", cbFrame));
233 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
234 STAM_PROFILE_START(&pData->StatRecvOverflows, b);
235
236 ASMAtomicXchgSize(&pThis->fOutOfSpace, true);
237 int rc;
238 unsigned cYields = 0;
239 for (;;)
240 {
241 /* yield/sleep */
242 if ( !RTThreadYield()
243 || ++cYields % 100 == 0)
244 {
245 /** @todo we need a callback from the device which can wake us up here. */
246 rc = RTSemEventWait(pThis->EventOutOfSpace, 1);
247 if ( VBOX_FAILURE(rc)
248 && rc != VERR_TIMEOUT)
249 break;
250 }
251 if (pThis->enmState != ASYNCSTATE_RUNNING)
252 {
253 rc = VERR_STATE_CHANGED;
254 break;
255 }
256
257 /* retry */
258 size_t cbMax = pThis->pPort->pfnCanReceive(pThis->pPort);
259 if (cbMax >= cbFrame)
260 {
261 rc = VINF_SUCCESS;
262 break;
263 }
264 }
265 ASMAtomicXchgSize(&pThis->fOutOfSpace, false);
266
267 STAM_PROFILE_STOP(&pThis->StatRecvOverflows, b);
268 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
269 LogFlow(("drvIntNetAsyncIoWaitForSpace: returns %Vrc\n", rc));
270 return rc;
271}
272
273
274/**
275 * Executes async I/O (RUNNING mode).
276 *
277 * @returns VERR_STATE_CHANGED if the state changed.
278 * @returns Appropriate VBox status code (error) on fatal error.
279 * @param pThis The driver instance data.
280 */
281static int drvIntNetAsyncIoRun(PDRVINTNET pThis)
282{
283 PPDMDRVINS pDrvIns = pThis->pDrvIns;
284 LogFlow(("drvIntNetAsyncIoRun: pThis=%p\n", pThis));
285
286 /*
287 * The running loop - processing received data and waiting for more to arrive.
288 */
289 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
290 PINTNETBUF pBuf = pThis->pBuf;
291 PINTNETRINGBUF pRingBuf = &pThis->pBuf->Recv;
292 for (;;)
293 {
294 /*
295 * Process the receive buffer.
296 */
297 while (INTNETRingGetReadable(pRingBuf) > 0)
298 {
299 /*
300 * Check the state and then inspect the packet.
301 */
302 if (pThis->enmState != ASYNCSTATE_RUNNING)
303 {
304 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
305 LogFlow(("drvIntNetAsyncIoRun: returns VERR_STATE_CHANGED (state changed - #0)\n"));
306 return VERR_STATE_CHANGED;
307 }
308
309 PINTNETHDR pHdr = (PINTNETHDR)((uintptr_t)pBuf + pRingBuf->offRead);
310 Log2(("pHdr=%p offRead=%#x: %.8Rhxs\n", pHdr, pRingBuf->offRead, pHdr));
311 if ( pHdr->u16Type == INTNETHDR_TYPE_FRAME
312 && !pThis->fLinkDown)
313 {
314 /*
315 * Check if there is room for the frame and pass it up.
316 */
317 size_t cbFrame = pHdr->cbFrame;
318 size_t cbMax = pThis->pPort->pfnCanReceive(pThis->pPort);
319 if (cbMax >= cbFrame)
320 {
321#ifdef LOG_ENABLED
322 uint64_t u64Now = RTTimeProgramNanoTS();
323 LogFlow(("drvIntNetAsyncIoRun: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
324 cbFrame, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
325 pThis->u64LastReceiveTS = u64Now;
326 Log2(("drvIntNetAsyncIoRun: cbFrame=%#x\n"
327 "%.*Vhxd\n",
328 cbFrame, cbFrame, INTNETHdrGetFramePtr(pHdr, pBuf)));
329#endif
330 int rc = pThis->pPort->pfnReceive(pThis->pPort, INTNETHdrGetFramePtr(pHdr, pBuf), cbFrame);
331 AssertRC(rc);
332
333 /* skip to the next frame. */
334 INTNETRingSkipFrame(pBuf, pRingBuf);
335 }
336 else
337 {
338 /*
339 * Wait for sufficient space to become available and then retry.
340 */
341 int rc = drvIntNetAsyncIoWaitForSpace(pThis, cbFrame);
342 if (VBOX_FAILURE(rc))
343 {
344 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
345 LogFlow(("drvIntNetAsyncIoRun: returns %Vrc (wait-for-space)\n", rc));
346 return rc;
347 }
348 }
349 }
350 else
351 {
352 /*
353 * Link down or unknown frame - skip to the next frame.
354 */
355 AssertMsg(pHdr->u16Type == INTNETHDR_TYPE_FRAME, ("Unknown frame type %RX16! offRead=%#x\n",
356 pHdr->u16Type, pRingBuf->offRead));
357 INTNETRingSkipFrame(pBuf, pRingBuf);
358 }
359 } /* while more received data */
360
361 /*
362 * Wait for data, checking the state before we block.
363 */
364 if (pThis->enmState != ASYNCSTATE_RUNNING)
365 {
366 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
367 LogFlow(("drvIntNetAsyncIoRun: returns VINF_SUCCESS (state changed - #1)\n"));
368 return VERR_STATE_CHANGED;
369 }
370 INTNETIFWAITARGS WaitArgs;
371 WaitArgs.hIf = pThis->hIf;
372 WaitArgs.cMillies = 30000; /* don't wait forever, timeout now and then. */
373 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
374 int rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_WAIT, &WaitArgs, sizeof(WaitArgs));
375 if ( VBOX_FAILURE(rc)
376 && rc != VERR_TIMEOUT
377 && rc != VERR_INTERRUPTED)
378 {
379 LogFlow(("drvIntNetAsyncIoRun: returns %Vrc\n", rc));
380 return rc;
381 }
382 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
383 }
384}
385
386
387/**
388 * Asynchronous I/O thread for handling receive.
389 *
390 * @returns VINF_SUCCESS (ignored).
391 * @param ThreadSelf Thread handle.
392 * @param pvUser Pointer to a DRVINTNET structure.
393 */
394static DECLCALLBACK(int) drvIntNetAsyncIoThread(RTTHREAD ThreadSelf, void *pvUser)
395{
396 PDRVINTNET pThis = (PDRVINTNET)pvUser;
397 LogFlow(("drvIntNetAsyncIoThread: pThis=%p\n", pThis));
398 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
399
400 /*
401 * The main loop - acting on state.
402 */
403 for (;;)
404 {
405 ASYNCSTATE enmState = pThis->enmState;
406 switch (enmState)
407 {
408 case ASYNCSTATE_SUSPENDED:
409 {
410 int rc = RTSemEventWait(pThis->EventSuspended, 30000);
411 if ( VBOX_FAILURE(rc)
412 && rc != VERR_TIMEOUT)
413 {
414 LogFlow(("drvIntNetAsyncIoThread: returns %Vrc\n", rc));
415 return rc;
416 }
417 break;
418 }
419
420 case ASYNCSTATE_RUNNING:
421 {
422 int rc = drvIntNetAsyncIoRun(pThis);
423 if ( rc != VERR_STATE_CHANGED
424 && VBOX_FAILURE(rc))
425 {
426 LogFlow(("drvIntNetAsyncIoThread: returns %Vrc\n", rc));
427 return rc;
428 }
429 break;
430 }
431
432 default:
433 AssertMsgFailed(("Invalid state %d\n", enmState));
434 case ASYNCSTATE_TERMINATE:
435 LogFlow(("drvIntNetAsyncIoThread: returns VINF_SUCCESS\n"));
436 return VINF_SUCCESS;
437 }
438 }
439}
440
441
442/**
443 * Queries an interface to the driver.
444 *
445 * @returns Pointer to interface.
446 * @returns NULL if the interface was not supported by the driver.
447 * @param pInterface Pointer to this interface structure.
448 * @param enmInterface The requested interface identification.
449 * @thread Any thread.
450 */
451static DECLCALLBACK(void *) drvIntNetQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
452{
453 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
454 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
455 switch (enmInterface)
456 {
457 case PDMINTERFACE_BASE:
458 return &pDrvIns->IBase;
459 case PDMINTERFACE_NETWORK_CONNECTOR:
460 return &pThis->INetworkConnector;
461 default:
462 return NULL;
463 }
464}
465
466
467/**
468 * Power Off notification.
469 *
470 * @param pDrvIns The driver instance.
471 */
472static DECLCALLBACK(void) drvIntNetPowerOff(PPDMDRVINS pDrvIns)
473{
474 LogFlow(("drvIntNetPowerOff\n"));
475 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
476 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
477}
478
479
480/**
481 * Resume notification.
482 *
483 * @param pDrvIns The driver instance.
484 */
485static DECLCALLBACK(void) drvIntNetResume(PPDMDRVINS pDrvIns)
486{
487 LogFlow(("drvIntNetPowerResume\n"));
488 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
489 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
490 RTSemEventSignal(pThis->EventSuspended);
491}
492
493
494/**
495 * Suspend notification.
496 *
497 * @param pDrvIns The driver instance.
498 */
499static DECLCALLBACK(void) drvIntNetSuspend(PPDMDRVINS pDrvIns)
500{
501 LogFlow(("drvIntNetPowerSuspend\n"));
502 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
503 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
504}
505
506
507/**
508 * Power On notification.
509 *
510 * @param pDrvIns The driver instance.
511 */
512static DECLCALLBACK(void) drvIntNetPowerOn(PPDMDRVINS pDrvIns)
513{
514 LogFlow(("drvIntNetPowerOn\n"));
515 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
516 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
517 RTSemEventSignal(pThis->EventSuspended);
518}
519
520
521/**
522 * Destruct a driver instance.
523 *
524 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
525 * resources can be freed correctly.
526 *
527 * @param pDrvIns The driver instance data.
528 */
529static DECLCALLBACK(void) drvIntNetDestruct(PPDMDRVINS pDrvIns)
530{
531 LogFlow(("drvIntNetDestruct\n"));
532 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
533
534 /*
535 * Indicate to the thread that it's time to quit.
536 */
537 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_TERMINATE);
538 ASMAtomicXchgSize(&pThis->fLinkDown, true);
539 RTSEMEVENT EventOutOfSpace = pThis->EventOutOfSpace;
540 pThis->EventOutOfSpace = NIL_RTSEMEVENT;
541 RTSEMEVENT EventSuspended = pThis->EventSuspended;
542 pThis->EventSuspended = NIL_RTSEMEVENT;
543
544 /*
545 * Close the interface
546 */
547 if (pThis->hIf != INTNET_HANDLE_INVALID)
548 {
549 INTNETIFCLOSEARGS CloseArgs = {0};
550 CloseArgs.hIf = pThis->hIf;
551 pThis->hIf = INTNET_HANDLE_INVALID;
552 int rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_CLOSE, &CloseArgs, sizeof(CloseArgs));
553 AssertRC(rc);
554 }
555
556 /*
557 * Wait for the thread to terminate.
558 */
559 if (pThis->Thread != NIL_RTTHREAD)
560 {
561 if (EventOutOfSpace != NIL_RTSEMEVENT)
562 RTSemEventSignal(EventOutOfSpace);
563 if (EventSuspended != NIL_RTSEMEVENT)
564 RTSemEventSignal(EventSuspended);
565 int rc = RTThreadWait(pThis->Thread, 5000, NULL);
566 AssertRC(rc);
567 pThis->Thread = NIL_RTTHREAD;
568 }
569
570 /*
571 * Destroy the semaphores.
572 */
573 if (EventOutOfSpace != NIL_RTSEMEVENT)
574 RTSemEventDestroy(EventOutOfSpace);
575 if (EventSuspended != NIL_RTSEMEVENT)
576 RTSemEventDestroy(EventSuspended);
577}
578
579
580/**
581 * Construct a TAP network transport driver instance.
582 *
583 * @returns VBox status.
584 * @param pDrvIns The driver instance data.
585 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
586 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
587 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
588 * iInstance it's expected to be used a bit in this function.
589 */
590static DECLCALLBACK(int) drvIntNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
591{
592 PDRVINTNET pThis = PDMINS2DATA(pDrvIns, PDRVINTNET);
593
594 /*
595 * Init the static parts.
596 */
597 pThis->pDrvIns = pDrvIns;
598 pThis->hIf = INTNET_HANDLE_INVALID;
599 pThis->Thread = NIL_RTTHREAD;
600 pThis->EventSuspended = NIL_RTSEMEVENT;
601 pThis->EventOutOfSpace = NIL_RTSEMEVENT;
602 pThis->enmState = ASYNCSTATE_SUSPENDED;
603 /* IBase */
604 pDrvIns->IBase.pfnQueryInterface = drvIntNetQueryInterface;
605 /* INetwork */
606 pThis->INetworkConnector.pfnSend = drvIntNetSend;
607 pThis->INetworkConnector.pfnSetPromiscuousMode = drvIntNetSetPromiscuousMode;
608 pThis->INetworkConnector.pfnNotifyLinkChanged = drvIntNetNotifyLinkChanged;
609 pThis->INetworkConnector.pfnNotifyCanReceive = drvIntNetNotifyCanReceive;
610
611 /*
612 * Validate the config.
613 */
614 if (!CFGMR3AreValuesValid(pCfgHandle, "Network\0ReceiveBufferSize\0SendBufferSize\0RestrictAccess\0"))
615 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
616
617 /*
618 * Check that no-one is attached to us.
619 */
620 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, NULL);
621 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
622 {
623 AssertMsgFailed(("Configuration error: Cannot attach drivers to the TAP driver!\n"));
624 return VERR_PDM_DRVINS_NO_ATTACH;
625 }
626
627 /*
628 * Query the network port interface.
629 */
630 pThis->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
631 if (!pThis->pPort)
632 {
633 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
634 return VERR_PDM_MISSING_INTERFACE_ABOVE;
635 }
636
637 /*
638 * Read the configuration.
639 */
640 INTNETOPENARGS OpenArgs;
641 memset(&OpenArgs, 0, sizeof(OpenArgs));
642 rc = CFGMR3QueryString(pCfgHandle, "Network", OpenArgs.szNetwork, sizeof(OpenArgs.szNetwork));
643 if (VBOX_FAILURE(rc))
644 return PDMDRV_SET_ERROR(pDrvIns, rc,
645 N_("Configuration error: Failed to get the \"Network\" value"));
646 strcpy(pThis->szNetwork, OpenArgs.szNetwork);
647
648 rc = CFGMR3QueryU32(pCfgHandle, "ReceiveBufferSize", &OpenArgs.cbRecv);
649 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
650 OpenArgs.cbRecv = _256K;
651 else if (VBOX_FAILURE(rc))
652 return PDMDRV_SET_ERROR(pDrvIns, rc,
653 N_("Configuration error: Failed to get the \"ReceiveBufferSize\" value"));
654
655 rc = CFGMR3QueryU32(pCfgHandle, "SendBufferSize", &OpenArgs.cbSend);
656 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
657 OpenArgs.cbSend = _4K;
658 else if (VBOX_FAILURE(rc))
659 return PDMDRV_SET_ERROR(pDrvIns, rc,
660 N_("Configuration error: Failed to get the \"SendBufferSize\" value"));
661
662 rc = CFGMR3QueryBool(pCfgHandle, "RestrictAccess", &OpenArgs.fRestrictAccess);
663 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
664 OpenArgs.fRestrictAccess = true;
665 else if (VBOX_FAILURE(rc))
666 return PDMDRV_SET_ERROR(pDrvIns, rc,
667 N_("Configuration error: Failed to get the \"RestrictAccess\" value"));
668
669 /*
670 * Create the event semaphores
671 */
672 rc = RTSemEventCreate(&pThis->EventSuspended);
673 if (VBOX_FAILURE(rc))
674 return rc;
675 rc = RTSemEventCreate(&pThis->EventOutOfSpace);
676 if (VBOX_FAILURE(rc))
677 return rc;
678
679 /*
680 * Create the interface.
681 */
682 OpenArgs.hIf = INTNET_HANDLE_INVALID;
683 rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_OPEN, &OpenArgs, sizeof(OpenArgs));
684 if (VBOX_FAILURE(rc))
685 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
686 N_("Failed to open/create the internal network '%s'"), pThis->szNetwork);
687 AssertRelease(OpenArgs.hIf != INTNET_HANDLE_INVALID);
688 pThis->hIf = OpenArgs.hIf;
689 Log(("IntNet%d: hIf=%RX32 '%s'\n", pDrvIns->iInstance, pThis->hIf, pThis->szNetwork));
690
691 /*
692 * Get default buffer.
693 */
694 INTNETIFGETRING3BUFFERARGS GetRing3BufferArgs = {0};
695 GetRing3BufferArgs.hIf = pThis->hIf;
696 GetRing3BufferArgs.pRing3Buf = NULL;
697 rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_GET_RING3_BUFFER, &GetRing3BufferArgs, sizeof(GetRing3BufferArgs));
698 if (VBOX_FAILURE(rc))
699 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
700 N_("Failed to get ring-3 buffer for the newly created interface to '%s'"), pThis->szNetwork);
701 AssertRelease(VALID_PTR(GetRing3BufferArgs.pRing3Buf));
702 pThis->pBuf = GetRing3BufferArgs.pRing3Buf;
703
704 /*
705 * Create the async I/O thread.
706 */
707 rc = RTThreadCreate(&pThis->Thread, drvIntNetAsyncIoThread, pThis, _128K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET");
708 if (VBOX_FAILURE(rc))
709 {
710 AssertRC(rc);
711 return rc;
712 }
713
714 char szStatName[64];
715 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Bytes/Received", pDrvIns->iInstance);
716 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cbStatRecv, STAMTYPE_COUNTER, szStatName, STAMUNIT_BYTES, "Number of received bytes.");
717 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Bytes/Sent", pDrvIns->iInstance);
718 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cbStatSend, STAMTYPE_COUNTER, szStatName, STAMUNIT_BYTES, "Number of sent bytes.");
719 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Packets/Received", pDrvIns->iInstance);
720 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatRecvs, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of received packets.");
721 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Packets/Sent", pDrvIns->iInstance);
722 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatSends, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of sent packets.");
723 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Packets/Lost", pDrvIns->iInstance);
724 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatLost, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of lost packets.");
725 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/YieldOk", pDrvIns->iInstance);
726 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatYieldsOk, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of times yielding fixed an overflow.");
727 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/YieldNok", pDrvIns->iInstance);
728 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->pBuf->cStatYieldsNok, STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Number of times yielding didn't help fix an overflow.");
729
730#ifdef VBOX_WITH_STATISTICS
731 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Receive", pDrvIns->iInstance);
732 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, szStatName, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.");
733 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/RecvOverflows", pDrvIns->iInstance);
734 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->StatRecvOverflows, STAMTYPE_PROFILE, szStatName, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling packet receive overflows.");
735 RTStrPrintf(szStatName, sizeof(szStatName), "/Net/IntNet%d/Transmit", pDrvIns->iInstance);
736 pDrvIns->pDrvHlp->pfnSTAMRegister(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, szStatName, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.");
737#endif
738
739 LogRel(("IntNet#%u: cbRecv=%u cbSend=%u fRestrictAccess=%d\n", pDrvIns->iInstance, OpenArgs.cbRecv, OpenArgs.cbSend, OpenArgs.fRestrictAccess));
740
741 return rc;
742}
743
744
745/**
746 * Internal networking transport driver registration record.
747 */
748const PDMDRVREG g_DrvIntNet =
749{
750 /* u32Version */
751 PDM_DRVREG_VERSION,
752 /* szDriverName */
753 "IntNet",
754 /* pszDescription */
755 "Internal Networking Transport Driver",
756 /* fFlags */
757 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
758 /* fClass. */
759 PDM_DRVREG_CLASS_NETWORK,
760 /* cMaxInstances */
761 ~0,
762 /* cbInstance */
763 sizeof(DRVINTNET),
764 /* pfnConstruct */
765 drvIntNetConstruct,
766 /* pfnDestruct */
767 drvIntNetDestruct,
768 /* pfnIOCtl */
769 NULL,
770 /* pfnPowerOn */
771 drvIntNetPowerOn,
772 /* pfnReset */
773 NULL,
774 /* pfnSuspend */
775 drvIntNetSuspend,
776 /* pfnResume */
777 drvIntNetResume,
778 /* pfnDetach */
779 NULL,
780 /* pfnPowerOff */
781 drvIntNetPowerOff
782};
783
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