VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvTAP.cpp@ 7799

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

TAP: remove the obsolete polling stuff

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.1 KB
Line 
1/** $Id: DrvTAP.cpp 7799 2008-04-08 12:54:55Z vboxsync $ */
2/** @file
3 * Universial TAP network transport driver.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_TUN
23#include <VBox/log.h>
24#include <VBox/pdmdrv.h>
25
26#include <iprt/assert.h>
27#include <iprt/file.h>
28#include <iprt/string.h>
29#include <iprt/path.h>
30#include <iprt/thread.h>
31#include <iprt/asm.h>
32#include <iprt/semaphore.h>
33#ifdef RT_OS_SOLARIS
34# include <iprt/process.h>
35# include <iprt/env.h>
36# ifdef VBOX_WITH_CROSSBOW
37# include <iprt/mem.h>
38# endif
39#endif
40
41#include <sys/ioctl.h>
42#include <sys/poll.h>
43#ifdef RT_OS_SOLARIS
44# include <sys/stat.h>
45# include <sys/ethernet.h>
46# include <sys/sockio.h>
47# include <netinet/in.h>
48# include <netinet/in_systm.h>
49# include <netinet/ip.h>
50# include <netinet/ip_icmp.h>
51# include <netinet/udp.h>
52# include <netinet/tcp.h>
53# include <net/if.h>
54# include <stropts.h>
55# include <fcntl.h>
56# include <ctype.h>
57# include <stdlib.h>
58# include <stdio.h>
59# ifdef VBOX_WITH_CROSSBOW
60# include <libdlpi.h>
61# endif
62#else
63# include <sys/fcntl.h>
64#endif
65#include <errno.h>
66#include <unistd.h>
67
68#ifdef RT_OS_L4
69# include <l4/vboxserver/file.h>
70#endif
71
72#include "Builtins.h"
73
74
75/*******************************************************************************
76* Structures and Typedefs *
77*******************************************************************************/
78/**
79 * Block driver instance data.
80 */
81typedef struct DRVTAP
82{
83 /** The network interface. */
84 PDMINETWORKCONNECTOR INetworkConnector;
85 /** The network interface. */
86 PPDMINETWORKPORT pPort;
87 /** Pointer to the driver instance. */
88 PPDMDRVINS pDrvIns;
89 /** TAP device file handle. */
90 RTFILE FileDevice;
91 /** The configured TAP device name. */
92 char *pszDeviceName;
93#ifdef RT_OS_SOLARIS
94# ifdef VBOX_WITH_CROSSBOW
95 /** Crossbow: MAC address of the device. */
96 PDMMAC MacAddress;
97 /** Crossbow: Handle of the NIC. */
98 dlpi_handle_t pDeviceHandle;
99# else
100 /** IP device file handle (/dev/udp). */
101 RTFILE IPFileDevice;
102# endif
103 /** Whether device name is obtained from setup application. */
104 bool fStatic;
105#endif
106 /** TAP setup application. */
107 char *pszSetupApplication;
108 /** TAP terminate application. */
109 char *pszTerminateApplication;
110 /** The write end of the control pipe. */
111 RTFILE PipeWrite;
112 /** The read end of the control pipe. */
113 RTFILE PipeRead;
114 /** Reader thread. */
115 PPDMTHREAD pThread;
116 /** We are waiting for more receive buffers. */
117 bool volatile fMaybeOutOfSpace;
118 /** Event semaphore for blocking on receive. */
119 RTSEMEVENT EventOutOfSpace;
120
121#ifdef VBOX_WITH_STATISTICS
122 /** Number of sent packets. */
123 STAMCOUNTER StatPktSent;
124 /** Number of sent bytes. */
125 STAMCOUNTER StatPktSentBytes;
126 /** Number of received packets. */
127 STAMCOUNTER StatPktRecv;
128 /** Number of received bytes. */
129 STAMCOUNTER StatPktRecvBytes;
130 /** Profiling packet transmit runs. */
131 STAMPROFILE StatTransmit;
132 /** Profiling packet receive runs. */
133 STAMPROFILEADV StatReceive;
134 /** Profiling receive descriptor overflows. */
135 STAMPROFILE StatRecvOverflows;
136#endif /* VBOX_WITH_STATISTICS */
137
138#ifdef LOG_ENABLED
139 /** The nano ts of the last transfer. */
140 uint64_t u64LastTransferTS;
141 /** The nano ts of the last receive. */
142 uint64_t u64LastReceiveTS;
143#endif
144} DRVTAP, *PDRVTAP;
145
146
147/** Converts a pointer to TAP::INetworkConnector to a PRDVTAP. */
148#define PDMINETWORKCONNECTOR_2_DRVTAP(pInterface) ( (PDRVTAP)((uintptr_t)pInterface - RT_OFFSETOF(DRVTAP, INetworkConnector)) )
149
150
151/*******************************************************************************
152* Internal Functions *
153*******************************************************************************/
154#ifdef RT_OS_SOLARIS
155# ifdef VBOX_WITH_CROSSBOW
156static int SolarisOpenVNIC(PDRVTAP pData);
157static int SolarisDLPIErr2VBoxErr(int rc);
158# else
159static int SolarisTAPAttach(PDRVTAP pData);
160# endif
161#endif
162
163
164/**
165 * Send data to the network.
166 *
167 * @returns VBox status code.
168 * @param pInterface Pointer to the interface structure containing the called function pointer.
169 * @param pvBuf Data to send.
170 * @param cb Number of bytes to send.
171 * @thread EMT
172 */
173static DECLCALLBACK(int) drvTAPSend(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
174{
175 PDRVTAP pData = PDMINETWORKCONNECTOR_2_DRVTAP(pInterface);
176 STAM_COUNTER_INC(&pData->StatPktSent);
177 STAM_COUNTER_ADD(&pData->StatPktSentBytes, cb);
178 STAM_PROFILE_START(&pData->StatTransmit, a);
179
180#ifdef LOG_ENABLED
181 uint64_t u64Now = RTTimeProgramNanoTS();
182 LogFlow(("drvTAPSend: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
183 cb, u64Now, u64Now - pData->u64LastReceiveTS, u64Now - pData->u64LastTransferTS));
184 pData->u64LastTransferTS = u64Now;
185#endif
186 Log2(("drvTAPSend: pvBuf=%p cb=%#x\n"
187 "%.*Vhxd\n",
188 pvBuf, cb, cb, pvBuf));
189
190 int rc = RTFileWrite(pData->FileDevice, pvBuf, cb, NULL);
191
192 STAM_PROFILE_STOP(&pData->StatTransmit, a);
193 AssertRC(rc);
194 return rc;
195}
196
197
198/**
199 * Set promiscuous mode.
200 *
201 * This is called when the promiscuous mode is set. This means that there doesn't have
202 * to be a mode change when it's called.
203 *
204 * @param pInterface Pointer to the interface structure containing the called function pointer.
205 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
206 * @thread EMT
207 */
208static DECLCALLBACK(void) drvTAPSetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
209{
210 LogFlow(("drvTAPSetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
211 /* nothing to do */
212}
213
214
215/**
216 * Notification on link status changes.
217 *
218 * @param pInterface Pointer to the interface structure containing the called function pointer.
219 * @param enmLinkState The new link state.
220 * @thread EMT
221 */
222static DECLCALLBACK(void) drvTAPNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
223{
224 LogFlow(("drvNATNotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
225 /** @todo take action on link down and up. Stop the polling and such like. */
226}
227
228
229/**
230 * More receive buffer has become available.
231 *
232 * This is called when the NIC frees up receive buffers.
233 *
234 * @param pInterface Pointer to the interface structure containing the called function pointer.
235 * @thread EMT
236 */
237static DECLCALLBACK(void) drvTAPNotifyCanReceive(PPDMINETWORKCONNECTOR pInterface)
238{
239 PDRVTAP pData = PDMINETWORKCONNECTOR_2_DRVTAP(pInterface);
240
241 LogFlow(("drvTAPNotifyCanReceive:\n"));
242 /** @todo r=bird: A better solution would be to ditch the NotifyCanReceive callback and
243 * instead change the CanReceive to do all the work. That is, CanReceive
244 * will not return until there are receive buffers available. This will
245 * reduce the amount of code duplication, and would permit pcnet to avoid
246 * queuing unnecessary ring-3 tasks.
247 */
248 if (pData->fMaybeOutOfSpace)
249 RTSemEventSignal(pData->EventOutOfSpace);
250}
251
252
253/**
254 * Asynchronous I/O thread for handling receive.
255 *
256 * @returns VINF_SUCCESS (ignored).
257 * @param Thread Thread handle.
258 * @param pvUser Pointer to a DRVTAP structure.
259 */
260static DECLCALLBACK(int) drvTAPAsyncIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
261{
262 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
263 LogFlow(("drvTAPAsyncIoThread: pData=%p\n", pData));
264
265 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
266 return VINF_SUCCESS;
267
268 STAM_PROFILE_ADV_START(&pData->StatReceive, a);
269
270 int rc = RTSemEventCreate(&pData->EventOutOfSpace);
271 AssertRC(rc);
272
273 /*
274 * Polling loop.
275 */
276 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
277 {
278 /*
279 * Wait for something to become available.
280 */
281 struct pollfd aFDs[2];
282 aFDs[0].fd = pData->FileDevice;
283 aFDs[0].events = POLLIN | POLLPRI;
284 aFDs[0].revents = 0;
285 aFDs[1].fd = pData->PipeRead;
286 aFDs[1].events = POLLIN | POLLPRI | POLLERR | POLLHUP;
287 aFDs[1].revents = 0;
288 STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
289 errno=0;
290 rc = poll(&aFDs[0], ELEMENTS(aFDs), -1 /* infinite */);
291
292 /* this might have changed in the meantime */
293 if (pThread->enmState != PDMTHREADSTATE_RUNNING)
294 break;
295
296 STAM_PROFILE_ADV_START(&pData->StatReceive, a);
297 if ( rc > 0
298 && (aFDs[0].revents & (POLLIN | POLLPRI))
299 && !aFDs[1].revents)
300 {
301 /*
302 * Read the frame.
303 */
304 char achBuf[4096];
305 size_t cbRead = 0;
306#ifdef VBOX_WITH_CROSSBOW
307 cbRead = sizeof(achBuf);
308 rc = dlpi_recv(pData->pDeviceHandle, NULL, NULL, achBuf, &cbRead, -1, NULL);
309 rc = RT_LIKELY(rc == DLPI_SUCCESS) ? VINF_SUCCESS : SolarisDLPIErr2VBoxErr(rc);
310#else
311 /** @note At least on Linux we will never receive more than one network packet
312 * after poll() returned successfully. I don't know why but a second
313 * RTFileRead() operation will return with VERR_TRY_AGAIN in any case. */
314 rc = RTFileRead(pData->FileDevice, achBuf, sizeof(achBuf), &cbRead);
315#endif
316 if (VBOX_SUCCESS(rc))
317 {
318 AssertMsg(cbRead <= 1536, ("cbRead=%d\n", cbRead));
319
320 /*
321 * Wait for the device to have space for this frame.
322 * Most guests use frame-sized receive buffers, hence non-zero cbMax
323 * automatically means there is enough room for entire frame. Some
324 * guests (eg. Solaris) use large chains of small receive buffers
325 * (each 128 or so bytes large). We will still start receiving as soon
326 * as cbMax is non-zero because:
327 * - it would be quite expensive for pfnCanReceive to accurately
328 * determine free receive buffer space
329 * - if we were waiting for enough free buffers, there is a risk
330 * of deadlocking because the guest could be waiting for a receive
331 * overflow error to allocate more receive buffers
332 */
333 ASMAtomicXchgBool(&pData->fMaybeOutOfSpace, true);
334 size_t cbMax = pData->pPort->pfnCanReceive(pData->pPort);
335 if (cbMax == 0)
336 {
337 /** @todo receive overflow handling needs serious improving! */
338 STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
339 STAM_PROFILE_START(&pData->StatRecvOverflows, b);
340 while ( cbMax == 0
341 && pThread->enmState == PDMTHREADSTATE_RUNNING)
342 {
343 LogFlow(("drvTAPAsyncIoThread: cbMax=%d cbRead=%d waiting...\n", cbMax, cbRead));
344 /* We get signalled by the network driver. 50ms is just for sanity */
345 RTSemEventWait(pData->EventOutOfSpace, 50);
346 cbMax = pData->pPort->pfnCanReceive(pData->pPort);
347 }
348 STAM_PROFILE_STOP(&pData->StatRecvOverflows, b);
349 STAM_PROFILE_ADV_START(&pData->StatReceive, a);
350 }
351 ASMAtomicXchgBool(&pData->fMaybeOutOfSpace, false);
352 if (pThread->enmState != PDMTHREADSTATE_RUNNING)
353 break;
354
355 /*
356 * Pass the data up.
357 */
358#ifdef LOG_ENABLED
359 uint64_t u64Now = RTTimeProgramNanoTS();
360 LogFlow(("drvTAPAsyncIoThread: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
361 cbRead, u64Now, u64Now - pData->u64LastReceiveTS, u64Now - pData->u64LastTransferTS));
362 pData->u64LastReceiveTS = u64Now;
363#endif
364 Log2(("drvTAPAsyncIoThread: cbRead=%#x\n" "%.*Vhxd\n", cbRead, cbRead, achBuf));
365 STAM_COUNTER_INC(&pData->StatPktRecv);
366 STAM_COUNTER_ADD(&pData->StatPktRecvBytes, cbRead);
367 rc = pData->pPort->pfnReceive(pData->pPort, achBuf, cbRead);
368 AssertRC(rc);
369 }
370 else
371 {
372 LogFlow(("drvTAPAsyncIoThread: RTFileRead -> %Vrc\n", rc));
373 if (rc == VERR_INVALID_HANDLE)
374 break;
375 RTThreadYield();
376 }
377 }
378 else if ( rc > 0
379 && aFDs[1].revents)
380 {
381 LogFlow(("drvTAPAsyncIoThread: Control message: enmState=%d revents=%#x\n", pThread->enmState, aFDs[1].revents));
382 if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL))
383 break;
384
385 /* drain the pipe */
386 char ch;
387 size_t cbRead;
388 RTFileRead(pData->PipeRead, &ch, 1, &cbRead);
389 }
390 else
391 {
392 /*
393 * poll() failed for some reason. Yield to avoid eating too much CPU.
394 *
395 * EINTR errors have been seen frequently. They should be harmless, even
396 * if they are not supposed to occur in our setup.
397 */
398 if (errno == EINTR)
399 Log(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, errno, strerror(errno)));
400 else
401 AssertMsgFailed(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, errno, strerror(errno)));
402 RTThreadYield();
403 }
404 }
405
406
407 rc = RTSemEventDestroy(pData->EventOutOfSpace);
408 AssertRC(rc);
409 pData->EventOutOfSpace = NIL_RTSEMEVENT;
410
411 LogFlow(("drvTAPAsyncIoThread: returns %Vrc\n", VINF_SUCCESS));
412 STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
413 return VINF_SUCCESS;
414}
415
416
417/**
418 * Unblock the send thread so it can respond to a state change.
419 *
420 * @returns VBox status code.
421 * @param pDevIns The pcnet device instance.
422 * @param pThread The send thread.
423 */
424static DECLCALLBACK(int) drvTapAsyncIoWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
425{
426 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
427
428 /* Ensure that it does not spin in the CanReceive loop.
429 (May assert in IPRT if we're really unlucky.) */
430 if (pData->fMaybeOutOfSpace)
431 RTSemEventSignal(pData->EventOutOfSpace);
432
433 int rc = RTFileWrite(pData->PipeWrite, "", 1, NULL);
434 AssertRC(rc);
435
436 return VINF_SUCCESS;
437}
438
439
440#if defined(RT_OS_SOLARIS)
441/**
442 * Calls OS-specific TAP setup application/script.
443 *
444 * @returns VBox error code.
445 * @param pData The instance data.
446 */
447static int drvTAPSetupApplication(PDRVTAP pData)
448{
449 char szCommand[4096];
450
451#ifdef VBOX_WITH_CROSSBOW
452 /* Convert MAC address bytes to string (required by Solaris' dladm). */
453 char *pszHex = "0123456789abcdef";
454 uint8_t *pMacAddr8 = pData->MacAddress.au8;
455 char szMacAddress[3 * sizeof(PDMMAC)];
456 for (unsigned int i = 0; i < sizeof(PDMMAC); i++)
457 {
458 szMacAddress[3 * i] = pszHex[((*pMacAddr8 >> 4) & 0x0f)];
459 szMacAddress[3 * i + 1] = pszHex[(*pMacAddr8 & 0x0f)];
460 szMacAddress[3 * i + 2] = ':';
461 *pMacAddr8++;
462 }
463 szMacAddress[sizeof(szMacAddress) - 1] = 0;
464
465 RTStrPrintf(szCommand, sizeof(szCommand), "%s %s %s", pData->pszSetupApplication,
466 szMacAddress, pData->fStatic ? pData->pszDeviceName : "");
467#else
468 RTStrPrintf(szCommand, sizeof(szCommand), "%s %s", pData->pszSetupApplication,
469 pData->fStatic ? pData->pszDeviceName : "");
470#endif
471
472 /* Pipe open the setup application. */
473 Log2(("Starting TAP setup application: %s\n", szCommand));
474 FILE* pfSetupHandle = popen(szCommand, "r");
475 if (pfSetupHandle == 0)
476 {
477 LogRel(("TAP#%d: Failed to run TAP setup application: %s\n", pData->pDrvIns->iInstance,
478 pData->pszSetupApplication, strerror(errno)));
479 return VERR_HOSTIF_INIT_FAILED;
480 }
481 if (!pData->fStatic)
482 {
483 /* Obtain device name from setup application. */
484 char acBuffer[64];
485 size_t cBufSize;
486 fgets(acBuffer, sizeof(acBuffer), pfSetupHandle);
487 cBufSize = strlen(acBuffer);
488 /* The script must return the name of the interface followed by a carriage return as the
489 first line of its output. We need a null-terminated string. */
490 if ((cBufSize < 2) || (acBuffer[cBufSize - 1] != '\n'))
491 {
492 pclose(pfSetupHandle);
493 LogRel(("The TAP interface setup script did not return the name of a TAP device.\n"));
494 return VERR_HOSTIF_INIT_FAILED;
495 }
496 /* Overwrite the terminating newline character. */
497 acBuffer[cBufSize - 1] = 0;
498 RTStrAPrintf(&pData->pszDeviceName, "%s", acBuffer);
499 }
500 int rc = pclose(pfSetupHandle);
501 if (!WIFEXITED(rc))
502 {
503 LogRel(("The TAP interface setup script terminated abnormally.\n"));
504 return VERR_HOSTIF_INIT_FAILED;
505 }
506 if (WEXITSTATUS(rc) != 0)
507 {
508 LogRel(("The TAP interface setup script returned a non-zero exit code.\n"));
509 return VERR_HOSTIF_INIT_FAILED;
510 }
511 return VINF_SUCCESS;
512}
513
514
515/**
516 * Calls OS-specific TAP terminate application/script.
517 *
518 * @returns VBox error code.
519 * @param pData The instance data.
520 */
521static int drvTAPTerminateApplication(PDRVTAP pData)
522{
523 char *pszArgs[3];
524 pszArgs[0] = pData->pszTerminateApplication;
525 pszArgs[1] = pData->pszDeviceName;
526 pszArgs[2] = NULL;
527
528 Log2(("Starting TAP terminate application: %s %s\n", pData->pszTerminateApplication, pData->pszDeviceName));
529 RTPROCESS pid = NIL_RTPROCESS;
530 int rc = RTProcCreate(pszArgs[0], pszArgs, RTENV_DEFAULT, 0, &pid);
531 if (RT_SUCCESS(rc))
532 {
533 RTPROCSTATUS Status;
534 rc = RTProcWait(pid, 0, &Status);
535 if (RT_SUCCESS(rc))
536 {
537 if ( Status.iStatus == 0
538 && Status.enmReason == RTPROCEXITREASON_NORMAL)
539 return VINF_SUCCESS;
540
541 LogRel(("TAP#%d: Error running TAP terminate application: %s\n", pData->pDrvIns->iInstance, pData->pszTerminateApplication));
542 }
543 else
544 LogRel(("TAP#%d: RTProcWait failed for: %s\n", pData->pDrvIns->iInstance, pData->pszTerminateApplication));
545 }
546 else
547 {
548 /* Bad. RTProcCreate() failed! */
549 LogRel(("TAP#%d: Failed to fork() process for running TAP terminate application: %s\n", pData->pDrvIns->iInstance,
550 pData->pszTerminateApplication, strerror(errno)));
551 }
552 return VERR_HOSTIF_TERM_FAILED;
553}
554
555#endif /* RT_OS_SOLARIS */
556
557
558#ifdef RT_OS_SOLARIS
559# ifdef VBOX_WITH_CROSSBOW
560/**
561 * Crossbow: Open & configure the virtual NIC.
562 *
563 * @returns VBox error code.
564 * @param pData The instance data.
565 */
566static int SolarisOpenVNIC(PDRVTAP pData)
567{
568 /*
569 * Open & bind the NIC using the datalink provider routine.
570 */
571 int rc = dlpi_open(pData->pszDeviceName, &pData->pDeviceHandle, DLPI_RAW);
572 if (rc != DLPI_SUCCESS)
573 return PDMDrvHlpVMSetError(pData->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
574 N_("Failed to open VNIC \"%s\" in raw mode"), pData->pszDeviceName);
575
576 dlpi_info_t vnicInfo;
577 rc = dlpi_info(pData->pDeviceHandle, &vnicInfo, 0);
578 if (rc == DLPI_SUCCESS)
579 {
580 if (vnicInfo.di_mactype == DL_ETHER)
581 {
582 rc = dlpi_bind(pData->pDeviceHandle, DLPI_ANY_SAP, NULL);
583 if (rc == DLPI_SUCCESS)
584 {
585 rc = dlpi_set_physaddr(pData->pDeviceHandle, DL_CURR_PHYS_ADDR, &pData->MacAddress, ETHERADDRL);
586 if (rc == DLPI_SUCCESS)
587 {
588 rc = dlpi_promiscon(pData->pDeviceHandle, DL_PROMISC_SAP);
589 if (rc == DLPI_SUCCESS)
590 {
591 /* Need to use DL_PROMIS_PHYS (not multicast) as we cannot be sure what the guest needs. */
592 rc = dlpi_promiscon(pData->pDeviceHandle, DL_PROMISC_PHYS);
593 if (rc == DLPI_SUCCESS)
594 {
595 pData->FileDevice = dlpi_fd(pData->pDeviceHandle);
596 if (pData->FileDevice >= 0)
597 {
598 Log(("SolarisOpenVNIC: %s -> %d\n", pData->pszDeviceName, pData->FileDevice));
599 return VINF_SUCCESS;
600 }
601
602 rc = PDMDrvHlpVMSetError(pData->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
603 N_("Failed to obtain file descriptor for VNIC"));
604 }
605 else
606 rc = PDMDrvHlpVMSetError(pData->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
607 N_("Failed to set appropriate promiscous mode"));
608 }
609 else
610 rc = PDMDrvHlpVMSetError(pData->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
611 N_("Failed to activate promiscous mode for VNIC"));
612 }
613 else
614 rc = PDMDrvHlpVMSetError(pData->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
615 N_("Failed to set physical address for VNIC"));
616 }
617 else
618 rc = PDMDrvHlpVMSetError(pData->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
619 N_("Failed to bind VNIC"));
620 }
621 else
622 rc = PDMDrvHlpVMSetError(pData->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
623 N_("VNIC type is not ethernet"));
624 }
625 else
626 rc = PDMDrvHlpVMSetError(pData->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
627 N_("Failed to obtain VNIC info"));
628 dlpi_close(pData->pDeviceHandle);
629 return rc;
630}
631
632
633/**
634 * Crossbow: Converts a Solaris DLPI error code to a VBox error code.
635 *
636 * @returns corresponding VBox error code.
637 * @param rc DLPI error code (DLPI_* defines).
638 */
639static int SolarisDLPIErr2VBoxErr(int rc)
640{
641 switch (rc)
642 {
643 case DLPI_SUCCESS: return VINF_SUCCESS;
644 case DLPI_EINVAL: return VERR_INVALID_PARAMETER;
645 case DLPI_ELINKNAMEINVAL: return VERR_INVALID_NAME;
646 case DLPI_EINHANDLE: return VERR_INVALID_HANDLE;
647 case DLPI_ETIMEDOUT: return VERR_TIMEOUT;
648 case DLPI_FAILURE: return VERR_GENERAL_FAILURE;
649
650 case DLPI_EVERNOTSUP:
651 case DLPI_EMODENOTSUP:
652 case DLPI_ERAWNOTSUP:
653 /* case DLPI_ENOTENOTSUP: */
654 case DLPI_EUNAVAILSAP: return VERR_NOT_SUPPORTED;
655
656 /* Define VBox error codes for these, if really needed. */
657 case DLPI_ENOLINK:
658 case DLPI_EBADLINK:
659 /* case DLPI_ENOTEIDINVAL: */
660 case DLPI_EBADMSG:
661 case DLPI_ENOTSTYLE2: return VERR_GENERAL_FAILURE;
662 }
663
664 AssertMsgFailed(("SolarisDLPIErr2VBoxErr: Unhandled error %d\n", rc));
665 return VERR_UNRESOLVED_ERROR;
666}
667
668# else /* VBOX_WITH_CROSSBOW */
669
670/** From net/if_tun.h, installed by Universal TUN/TAP driver */
671# define TUNNEWPPA (('T'<<16) | 0x0001)
672/** Whether to enable ARP for TAP. */
673# define VBOX_SOLARIS_TAP_ARP 1
674
675/**
676 * Creates/Attaches TAP device to IP.
677 *
678 * @returns VBox error code.
679 * @param pData The instance data.
680 */
681static DECLCALLBACK(int) SolarisTAPAttach(PDRVTAP pData)
682{
683 LogFlow(("SolarisTapAttach: pData=%p\n", pData));
684
685
686 int IPFileDes = open("/dev/udp", O_RDWR, 0);
687 if (IPFileDes < 0)
688 return PDMDrvHlpVMSetError(pData->pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
689 N_("Failed to open /dev/udp. errno=%d"), errno);
690
691 int TapFileDes = open("/dev/tap", O_RDWR, 0);
692 if (TapFileDes < 0)
693 return PDMDrvHlpVMSetError(pData->pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
694 N_("Failed to open /dev/tap for TAP. errno=%d"), errno);
695
696 /* Use the PPA from the ifname if possible (e.g "tap2", then use 2 as PPA) */
697 int iPPA = -1;
698 if (pData->pszDeviceName)
699 {
700 size_t cch = strlen(pData->pszDeviceName);
701 if (cch > 1 && isdigit(pData->pszDeviceName[cch - 1]) != 0)
702 iPPA = pData->pszDeviceName[cch - 1] - '0';
703 }
704
705 struct strioctl ioIF;
706 ioIF.ic_cmd = TUNNEWPPA;
707 ioIF.ic_len = sizeof(iPPA);
708 ioIF.ic_dp = (char *)(&iPPA);
709 ioIF.ic_timout = 0;
710 iPPA = ioctl(TapFileDes, I_STR, &ioIF);
711 if (iPPA < 0)
712 {
713 close(TapFileDes);
714 return PDMDrvHlpVMSetError(pData->pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
715 N_("Failed to get new interface. errno=%d"), errno);
716 }
717
718 int InterfaceFD = open("/dev/tap", O_RDWR, 0);
719 if (!InterfaceFD)
720 return PDMDrvHlpVMSetError(pData->pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
721 N_("Failed to open interface /dev/tap. errno=%d"), errno);
722
723 if (ioctl(InterfaceFD, I_PUSH, "ip") == -1)
724 {
725 close(InterfaceFD);
726 return PDMDrvHlpVMSetError(pData->pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
727 N_("Failed to push IP. errno=%d"), errno);
728 }
729
730 struct lifreq ifReq;
731 memset(&ifReq, 0, sizeof(ifReq));
732 if (ioctl(InterfaceFD, SIOCGLIFFLAGS, &ifReq) == -1)
733 LogRel(("TAP#%d: Failed to get interface flags.\n", pData->pDrvIns->iInstance));
734
735 ifReq.lifr_ppa = iPPA;
736 RTStrPrintf (ifReq.lifr_name, sizeof(ifReq.lifr_name), pData->pszDeviceName);
737
738 if (ioctl(InterfaceFD, SIOCSLIFNAME, &ifReq) == -1)
739 LogRel(("TAP#%d: Failed to set PPA. errno=%d\n", pData->pDrvIns->iInstance, errno));
740
741 if (ioctl(InterfaceFD, SIOCGLIFFLAGS, &ifReq) == -1)
742 LogRel(("TAP#%d: Failed to get interface flags after setting PPA. errno=%d\n", pData->pDrvIns->iInstance, errno));
743
744#ifdef VBOX_SOLARIS_TAP_ARP
745 /* Interface */
746 if (ioctl(InterfaceFD, I_PUSH, "arp") == -1)
747 LogRel(("TAP#%d: Failed to push ARP to Interface FD. errno=%d\n", pData->pDrvIns->iInstance, errno));
748
749 /* IP */
750 if (ioctl(IPFileDes, I_POP, NULL) == -1)
751 LogRel(("TAP#%d: Failed I_POP from IP FD. errno=%d\n", pData->pDrvIns->iInstance, errno));
752
753 if (ioctl(IPFileDes, I_PUSH, "arp") == -1)
754 LogRel(("TAP#%d: Failed to push ARP to IP FD. errno=%d\n", pData->pDrvIns->iInstance, errno));
755
756 /* ARP */
757 int ARPFileDes = open("/dev/tap", O_RDWR, 0);
758 if (ARPFileDes < 0)
759 LogRel(("TAP#%d: Failed to open for /dev/tap for ARP. errno=%d", pData->pDrvIns->iInstance, errno));
760
761 if (ioctl(ARPFileDes, I_PUSH, "arp") == -1)
762 LogRel(("TAP#%d: Failed to push ARP to ARP FD. errno=%d\n", pData->pDrvIns->iInstance, errno));
763
764 ioIF.ic_cmd = SIOCSLIFNAME;
765 ioIF.ic_timout = 0;
766 ioIF.ic_len = sizeof(ifReq);
767 ioIF.ic_dp = (char *)&ifReq;
768 if (ioctl(ARPFileDes, I_STR, &ioIF) == -1)
769 LogRel(("TAP#%d: Failed to set interface name to ARP.\n", pData->pDrvIns->iInstance));
770#endif
771
772 /* We must use I_LINK and not I_PLINK as I_PLINK makes the link persistent.
773 * Then we would not be able unlink the interface if we reuse it.
774 * Even 'unplumb' won't work after that.
775 */
776 int IPMuxID = ioctl(IPFileDes, I_LINK, InterfaceFD);
777 if (IPMuxID == -1)
778 {
779 close(InterfaceFD);
780#ifdef VBOX_SOLARIS_TAP_ARP
781 close(ARPFileDes);
782#endif
783 LogRel(("TAP#%d: Cannot link TAP device to IP.\n", pData->pDrvIns->iInstance));
784 return PDMDrvHlpVMSetError(pData->pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
785 N_("Failed to link TAP device to IP. Check TAP interface name. errno=%d"), errno);
786 }
787
788#ifdef VBOX_SOLARIS_TAP_ARP
789 int ARPMuxID = ioctl(IPFileDes, I_LINK, ARPFileDes);
790 if (ARPMuxID == -1)
791 LogRel(("TAP#%d: Failed to link TAP device to ARP\n", pData->pDrvIns->iInstance));
792
793 close(ARPFileDes);
794#endif
795 close(InterfaceFD);
796
797 /* Reuse ifReq */
798 memset(&ifReq, 0, sizeof(ifReq));
799 RTStrPrintf (ifReq.lifr_name, sizeof(ifReq.lifr_name), pData->pszDeviceName);
800 ifReq.lifr_ip_muxid = IPMuxID;
801#ifdef VBOX_SOLARIS_TAP_ARP
802 ifReq.lifr_arp_muxid = ARPMuxID;
803#endif
804
805 if (ioctl(IPFileDes, SIOCSLIFMUXID, &ifReq) == -1)
806 {
807#ifdef VBOX_SOLARIS_TAP_ARP
808 ioctl(IPFileDes, I_PUNLINK, ARPMuxID);
809#endif
810 ioctl(IPFileDes, I_PUNLINK, IPMuxID);
811 close(IPFileDes);
812 LogRel(("TAP#%d: Failed to set Mux ID.\n", pData->pDrvIns->iInstance));
813 return PDMDrvHlpVMSetError(pData->pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
814 N_("Failed to set Mux ID. Check TAP interface name. errno=%d"), errno);
815 }
816
817 pData->FileDevice = (RTFILE)TapFileDes;
818 pData->IPFileDevice = (RTFILE)IPFileDes;
819
820 return VINF_SUCCESS;
821}
822
823# endif /* VBOX_WITH_CROSSBOW */
824#endif /* RT_OS_SOLARIS */
825
826
827/**
828 * Queries an interface to the driver.
829 *
830 * @returns Pointer to interface.
831 * @returns NULL if the interface was not supported by the driver.
832 * @param pInterface Pointer to this interface structure.
833 * @param enmInterface The requested interface identification.
834 * @thread Any thread.
835 */
836static DECLCALLBACK(void *) drvTAPQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
837{
838 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
839 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
840 switch (enmInterface)
841 {
842 case PDMINTERFACE_BASE:
843 return &pDrvIns->IBase;
844 case PDMINTERFACE_NETWORK_CONNECTOR:
845 return &pData->INetworkConnector;
846 default:
847 return NULL;
848 }
849}
850
851
852/**
853 * Destruct a driver instance.
854 *
855 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
856 * resources can be freed correctly.
857 *
858 * @param pDrvIns The driver instance data.
859 */
860static DECLCALLBACK(void) drvTAPDestruct(PPDMDRVINS pDrvIns)
861{
862 LogFlow(("drvTAPDestruct\n"));
863 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
864
865 /*
866 * Terminate the control pipe.
867 */
868 if (pData->PipeWrite != NIL_RTFILE)
869 {
870 int rc = RTFileClose(pData->PipeWrite);
871 AssertRC(rc);
872 pData->PipeWrite = NIL_RTFILE;
873 }
874 if (pData->PipeRead != NIL_RTFILE)
875 {
876 int rc = RTFileClose(pData->PipeRead);
877 AssertRC(rc);
878 pData->PipeRead = NIL_RTFILE;
879 }
880
881#ifdef RT_OS_SOLARIS
882 /** @todo r=bird: This *does* need checking against ConsoleImpl2.cpp if used on non-solaris systems. */
883 if (pData->FileDevice != NIL_RTFILE)
884 {
885 int rc = RTFileClose(pData->FileDevice);
886 AssertRC(rc);
887 pData->FileDevice = NIL_RTFILE;
888 }
889
890# ifndef VBOX_WITH_CROSSBOW
891 if (pData->IPFileDevice != NIL_RTFILE)
892 {
893 int rc = RTFileClose(pData->IPFileDevice);
894 AssertRC(rc);
895 pData->IPFileDevice = NIL_RTFILE;
896 }
897# endif
898
899 /*
900 * Call TerminateApplication after closing the device otherwise
901 * TerminateApplication would not be able to unplumb it.
902 */
903 if (pData->pszTerminateApplication)
904 drvTAPTerminateApplication(pData);
905
906#endif /* RT_OS_SOLARIS */
907
908#ifdef RT_OS_SOLARIS
909 if (!pData->fStatic)
910 RTStrFree(pData->pszDeviceName); /* allocated by drvTAPSetupApplication */
911 else
912 MMR3HeapFree(pData->pszDeviceName);
913#else
914 MMR3HeapFree(pData->pszDeviceName);
915#endif
916 MMR3HeapFree(pData->pszSetupApplication);
917 MMR3HeapFree(pData->pszTerminateApplication);
918}
919
920
921/**
922 * Construct a TAP network transport driver instance.
923 *
924 * @returns VBox status.
925 * @param pDrvIns The driver instance data.
926 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
927 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
928 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
929 * iInstance it's expected to be used a bit in this function.
930 */
931static DECLCALLBACK(int) drvTAPConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
932{
933 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
934
935 /*
936 * Init the static parts.
937 */
938 pData->pDrvIns = pDrvIns;
939 pData->FileDevice = NIL_RTFILE;
940 pData->pszDeviceName = NULL;
941#ifdef RT_OS_SOLARIS
942# ifdef VBOX_WITH_CROSSBOW
943 pData->pDeviceHandle = NULL;
944# else
945 pData->IPFileDevice = NIL_RTFILE;
946# endif
947 pData->fStatic = true;
948#endif
949 pData->pszSetupApplication = NULL;
950 pData->pszTerminateApplication = NULL;
951
952 /* IBase */
953 pDrvIns->IBase.pfnQueryInterface = drvTAPQueryInterface;
954 /* INetwork */
955 pData->INetworkConnector.pfnSend = drvTAPSend;
956 pData->INetworkConnector.pfnSetPromiscuousMode = drvTAPSetPromiscuousMode;
957 pData->INetworkConnector.pfnNotifyLinkChanged = drvTAPNotifyLinkChanged;
958 pData->INetworkConnector.pfnNotifyCanReceive = drvTAPNotifyCanReceive;
959
960 /*
961 * Validate the config.
962 */
963 if (!CFGMR3AreValuesValid(pCfgHandle, "Device\0InitProg\0TermProg\0FileHandle\0TAPSetupApplication\0TAPTerminateApplication\0MAC"))
964 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES, "");
965
966 /*
967 * Check that no-one is attached to us.
968 */
969 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, NULL);
970 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
971 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_NO_ATTACH,
972 N_("Configuration error: Cannot attach drivers to the TAP driver"));
973
974 /*
975 * Query the network port interface.
976 */
977 pData->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
978 if (!pData->pPort)
979 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
980 N_("Configuration error: The above device/driver didn't export the network port interface"));
981
982 /*
983 * Read the configuration.
984 */
985#if defined(RT_OS_SOLARIS) /** @todo Other platforms' TAP code should be moved here from ConsoleImpl & VBoxBFE. */
986 rc = CFGMR3QueryStringAlloc(pCfgHandle, "TAPSetupApplication", &pData->pszSetupApplication);
987 if (VBOX_SUCCESS(rc))
988 {
989 if (!RTPathExists(pData->pszSetupApplication))
990 return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
991 N_("Invalid TAP setup program path: %s"), pData->pszSetupApplication);
992 }
993 else if (rc != VERR_CFGM_VALUE_NOT_FOUND)
994 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Configuration error: failed to query \"TAPTerminateApplication\""));
995
996 rc = CFGMR3QueryStringAlloc(pCfgHandle, "TAPTerminateApplication", &pData->pszTerminateApplication);
997 if (VBOX_SUCCESS(rc))
998 {
999 if (!RTPathExists(pData->pszTerminateApplication))
1000 return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
1001 N_("Invalid TAP terminate program path: %s"), pData->pszTerminateApplication);
1002 }
1003 else if (rc != VERR_CFGM_VALUE_NOT_FOUND)
1004 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Configuration error: failed to query \"TAPTerminateApplication\""));
1005
1006# ifdef VBOX_WITH_CROSSBOW
1007 rc = CFGMR3QueryBytes(pCfgHandle, "MAC", &pData->MacAddress, sizeof(pData->MacAddress));
1008 if (VBOX_FAILURE(rc))
1009 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Configuration error: Failed to query \"MAC\""));
1010# endif
1011
1012 rc = CFGMR3QueryStringAlloc(pCfgHandle, "Device", &pData->pszDeviceName);
1013 if (VBOX_FAILURE(rc))
1014 pData->fStatic = false;
1015
1016 /* Obtain the device name from the setup application (if none was specified). */
1017 if (pData->pszSetupApplication)
1018 {
1019 rc = drvTAPSetupApplication(pData);
1020 if (VBOX_FAILURE(rc))
1021 return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
1022 N_("Error running TAP setup application. rc=%d"), rc);
1023 }
1024
1025 /*
1026 * Do the setup.
1027 */
1028# ifdef VBOX_WITH_CROSSBOW
1029 rc = SolarisOpenVNIC(pData);
1030# else
1031 rc = SolarisTAPAttach(pData);
1032# endif
1033 if (VBOX_FAILURE(rc))
1034 return rc;
1035
1036#else /* !RT_OS_SOLARIS */
1037
1038 int32_t iFile;
1039 rc = CFGMR3QueryS32(pCfgHandle, "FileHandle", &iFile);
1040 if (VBOX_FAILURE(rc))
1041 return PDMDRV_SET_ERROR(pDrvIns, rc,
1042 N_("Configuration error: Query for \"FileHandle\" 32-bit signed integer failed"));
1043 pData->FileDevice = (RTFILE)iFile;
1044 if (!RTFileIsValid(pData->FileDevice))
1045 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_HANDLE, RT_SRC_POS,
1046 N_("The TAP file handle %RTfile is not valid"), pData->FileDevice);
1047#endif /* !RT_OS_SOLARIS */
1048
1049 /*
1050 * Make sure the descriptor is non-blocking and valid.
1051 *
1052 * We should actually query if it's a TAP device, but I haven't
1053 * found any way to do that.
1054 */
1055 if (fcntl(pData->FileDevice, F_SETFL, O_NONBLOCK) == -1)
1056 return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
1057 N_("Configuration error: Failed to configure /dev/net/tun. errno=%d"), errno);
1058 /** @todo determine device name. This can be done by reading the link /proc/<pid>/fd/<fd> */
1059 Log(("drvTAPContruct: %d (from fd)\n", pData->FileDevice));
1060 rc = VINF_SUCCESS;
1061
1062 /*
1063 * Create the control pipe.
1064 */
1065 int fds[2];
1066#ifdef RT_OS_L4
1067 /* XXX We need to tell the library which interface we are using */
1068 fds[0] = vboxrtLinuxFd2VBoxFd(VBOXRT_FT_TAP, 0);
1069#endif
1070 if (pipe(&fds[0]) != 0) /** @todo RTPipeCreate() or something... */
1071 {
1072 int rc = RTErrConvertFromErrno(errno);
1073 AssertRC(rc);
1074 return rc;
1075 }
1076 pData->PipeRead = fds[0];
1077 pData->PipeWrite = fds[1];
1078
1079 /*
1080 * Create the async I/O thread.
1081 */
1082 rc = PDMDrvHlpPDMThreadCreate(pDrvIns, &pData->pThread, pData, drvTAPAsyncIoThread, drvTapAsyncIoWakeup, 128 * _1K, RTTHREADTYPE_IO, "TAP");
1083 AssertRCReturn(rc, rc);
1084
1085#ifdef VBOX_WITH_STATISTICS
1086 /*
1087 * Statistics.
1088 */
1089 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktSent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of sent packets.", "/Drivers/TAP%d/Packets/Sent", pDrvIns->iInstance);
1090 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktSentBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Drivers/TAP%d/Bytes/Sent", pDrvIns->iInstance);
1091 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of received packets.", "/Drivers/TAP%d/Packets/Received", pDrvIns->iInstance);
1092 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktRecvBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Drivers/TAP%d/Bytes/Received", pDrvIns->iInstance);
1093 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Drivers/TAP%d/Transmit", pDrvIns->iInstance);
1094 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Drivers/TAP%d/Receive", pDrvIns->iInstance);
1095 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatRecvOverflows, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling packet receive overflows.", "/Drivers/TAP%d/RecvOverflows", pDrvIns->iInstance);
1096#endif /* VBOX_WITH_STATISTICS */
1097
1098 return rc;
1099}
1100
1101
1102/**
1103 * TAP network transport driver registration record.
1104 */
1105const PDMDRVREG g_DrvHostInterface =
1106{
1107 /* u32Version */
1108 PDM_DRVREG_VERSION,
1109 /* szDriverName */
1110 "HostInterface",
1111 /* pszDescription */
1112 "TAP Network Transport Driver",
1113 /* fFlags */
1114 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1115 /* fClass. */
1116 PDM_DRVREG_CLASS_NETWORK,
1117 /* cMaxInstances */
1118 ~0,
1119 /* cbInstance */
1120 sizeof(DRVTAP),
1121 /* pfnConstruct */
1122 drvTAPConstruct,
1123 /* pfnDestruct */
1124 drvTAPDestruct,
1125 /* pfnIOCtl */
1126 NULL,
1127 /* pfnPowerOn */
1128 NULL,
1129 /* pfnReset */
1130 NULL,
1131 /* pfnSuspend */
1132 NULL, /** @todo Do power on, suspend and resume handlers! */
1133 /* pfnResume */
1134 NULL,
1135 /* pfnDetach */
1136 NULL,
1137 /* pfnPowerOff */
1138 NULL
1139};
1140
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette