VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvTAPWin32.cpp@ 95

Last change on this file since 95 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.2 KB
Line 
1/** @file
2 *
3 * VBox network devices:
4 * Linux/Win32 TUN network transport driver
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung 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 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23
24#define ASYNC_NETIO
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#define LOG_GROUP LOG_GROUP_DRV_TUN
30#include <VBox/tapwin32.h>
31#include <VBox/pdm.h>
32#include <VBox/cfgm.h>
33#include <VBox/mm.h>
34#include <VBox/err.h>
35#include <VBox/stam.h>
36
37#include <VBox/log.h>
38#include <iprt/assert.h>
39#include <iprt/file.h>
40#include <iprt/string.h>
41#include <iprt/thread.h>
42#ifdef ASYNC_NETIO
43#include <iprt/asm.h>
44#include <iprt/semaphore.h>
45#endif
46
47#include "Builtins.h"
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/**
53 * Block driver instance data.
54 */
55typedef struct
56{
57 /** The network interface. */
58 PDMINETWORKCONNECTOR INetworkConnector;
59 /** The network interface. */
60 PPDMINETWORKPORT pPort;
61 /** Pointer to the driver instance. */
62 PPDMDRVINS pDrvIns;
63 /** TAP device file handle. */
64 HANDLE hFile;
65
66 HANDLE hEventWrite;
67 HANDLE hEventRead;
68
69 OVERLAPPED overlappedRead;
70 DWORD dwNumberOfBytesRead;
71 uint8_t readBuffer[4096];
72
73#ifdef ASYNC_NETIO
74 /** The thread handle. NIL_RTTHREAD if no thread. */
75 RTTHREAD hThread;
76 /** The event semaphore the thread is waiting on. */
77 HANDLE hHaltAsyncEventSem;
78 /** We are waiting for more receive buffers. */
79 uint32_t volatile fOutOfSpace;
80 /** Event semaphore for blocking on receive. */
81 RTSEMEVENT EventOutOfSpace;
82#endif
83
84#ifdef DEBUG
85 DWORD dwLastReadTime;
86 DWORD dwLastWriteTime;
87#endif
88
89#ifdef VBOX_WITH_STATISTICS
90 /** Number of sent packets. */
91 STAMCOUNTER StatPktSent;
92 /** Number of sent bytes. */
93 STAMCOUNTER StatPktSentBytes;
94 /** Number of received packets. */
95 STAMCOUNTER StatPktRecv;
96 /** Number of received bytes. */
97 STAMCOUNTER StatPktRecvBytes;
98 /** Profiling packet transmit runs. */
99 STAMPROFILEADV StatTransmit;
100 /** Profiling packet receive runs. */
101 STAMPROFILEADV StatReceive;
102# ifdef ASYNC_NETIO
103 STAMPROFILE StatRecvOverflows;
104# endif
105#endif /* VBOX_WITH_STATISTICS */
106} DRVTAP, *PDRVTAP;
107
108/** Converts a pointer to TUN::INetworkConnector to a PRDVTUN. */
109#define PDMINETWORKCONNECTOR_2_DRVTAP(pInterface) ( (PDRVTAP)((uintptr_t)pInterface - RT_OFFSETOF(DRVTAP, INetworkConnector)) )
110
111/**
112 * Send data to the network.
113 *
114 * @returns VBox status code.
115 * @param pInterface Pointer to the interface structure containing the called function pointer.
116 * @param pvBuf Data to send.
117 * @param cb Number of bytes to send.
118 * @thread EMT
119 */
120static DECLCALLBACK(int) drvTAPW32Send(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
121{
122 OVERLAPPED overlapped;
123 DWORD cbBytesWritten;
124 int rc;
125 PDRVTAP pData = PDMINETWORKCONNECTOR_2_DRVTAP(pInterface);
126
127 Log2(("drvTAPW32Send%d: pvBuf=%p cb=%#x\n"
128 "%.*Vhxd\n", pData->pDrvIns->iInstance, pvBuf, cb, cb, pvBuf));
129
130#ifdef DEBUG
131 pData->dwLastReadTime = timeGetTime();
132 Log(("drvTAPW32Send %d bytes at %08x - delta %x\n", cb, pData->dwLastReadTime, pData->dwLastReadTime - pData->dwLastWriteTime));
133#endif
134
135 STAM_COUNTER_INC(&pData->StatPktSent);
136 STAM_COUNTER_ADD(&pData->StatPktSentBytes, cb);
137 STAM_PROFILE_ADV_START(&pData->StatTransmit, a);
138
139 memset(&overlapped, 0, sizeof(overlapped));
140 overlapped.hEvent = pData->hEventWrite;
141
142 rc = VINF_SUCCESS;
143 if (WriteFile(pData->hFile, pvBuf, cb, &cbBytesWritten, &overlapped) == FALSE)
144 {
145 if (GetLastError() == ERROR_IO_PENDING)
146 {
147 Log(("drvTAPW32Send: IO pending!!\n"));
148 rc = WaitForSingleObject(overlapped.hEvent, INFINITE);
149 AssertMsg(rc == WAIT_OBJECT_0, ("WaitForSingleObject failed with %x\n", rc));
150 rc = VINF_SUCCESS;
151 }
152 else
153 {
154 AssertMsgFailed(("WriteFile failed with %d\n", GetLastError()));
155 rc = RTErrConvertFromWin32(GetLastError());
156 }
157 }
158 STAM_PROFILE_ADV_STOP(&pData->StatTransmit, a);
159 AssertRC(rc);
160 return rc;
161}
162
163
164/**
165 * Set promiscuous mode.
166 *
167 * This is called when the promiscuous mode is set. This means that there doesn't have
168 * to be a mode change when it's called.
169 *
170 * @param pInterface Pointer to the interface structure containing the called function pointer.
171 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
172 * @thread EMT
173 */
174static DECLCALLBACK(void) drvTAPW32SetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
175{
176 LogFlow(("drvTAPW32SetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
177 /* nothing to do */
178}
179
180
181/**
182 * Notification on link status changes.
183 *
184 * @param pInterface Pointer to the interface structure containing the called function pointer.
185 * @param enmLinkState The new link state.
186 * @thread EMT
187 */
188static DECLCALLBACK(void) drvTAPW32NotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
189{
190 LogFlow(("drvNATW32NotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
191 /** @todo take action on link down and up. Stop the polling and such like. */
192}
193
194
195/**
196 * More receive buffer has become available.
197 *
198 * This is called when the NIC frees up receive buffers.
199 *
200 * @param pInterface Pointer to the interface structure containing the called function pointer.
201 * @thread EMT
202 */
203static DECLCALLBACK(void) drvTAPW32NotifyCanReceive(PPDMINETWORKCONNECTOR pInterface)
204{
205 PDRVTAP pData = PDMINETWORKCONNECTOR_2_DRVTAP(pInterface);
206
207 LogFlow(("drvTAPW32NotifyCanReceive:\n"));
208 if (ASMAtomicXchgU32(&pData->fOutOfSpace, false))
209 RTSemEventSignal(pData->EventOutOfSpace);
210}
211
212
213#ifndef ASYNC_NETIO
214/**
215 * Poller callback.
216 */
217static DECLCALLBACK(void) drvTAPW32Poller(PPDMDRVINS pDrvIns)
218{
219 DWORD rc = ERROR_SUCCESS;
220 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
221 STAM_PROFILE_ADV_START(&pData->StatReceive, a);
222
223 /* check how much the device/driver can receive now. */
224 size_t cbMax = pData->pPort->pfnCanReceive(pData->pPort);
225
226 while (cbMax)
227 {
228 if (cbMax > 0 && !pData->overlappedRead.hEvent)
229 {
230 BOOL bRet;
231
232 cbMax = RT_MIN(cbMax, sizeof(pData->readBuffer));
233 memset(&pData->overlappedRead, 0, sizeof(pData->overlappedRead));
234 pData->overlappedRead.hEvent = pData->hEventRead;
235 bRet = ReadFile(pData->hFile, pData->readBuffer, cbMax, &pData->dwNumberOfBytesRead, &pData->overlappedRead);
236 if (bRet == FALSE)
237 {
238 rc = GetLastError();
239 AssertMsg(rc == ERROR_SUCCESS || rc == ERROR_IO_PENDING || rc == ERROR_MORE_DATA, ("ReadFileEx failed with rc=%d\n", rc));
240 if (rc != ERROR_IO_PENDING && rc != ERROR_MORE_DATA)
241 break;
242 }
243 }
244 if (cbMax)
245 {
246 DWORD dwNumberOfBytesTransferred = 0;
247
248 if (GetOverlappedResult(pData->hFile, &pData->overlappedRead, &dwNumberOfBytesTransferred, FALSE) == TRUE)
249 {
250 /* push it to the driver. */
251 Log2(("drvTAPW32Poller%d: cbRead=%#x\n"
252 "%.*Vhxd\n", pData->InstanceNr,
253 dwNumberOfBytesTransferred, dwNumberOfBytesTransferred, pData->readBuffer));
254
255 STAM_COUNTER_INC(&pData->StatPktRecv);
256 STAM_COUNTER_ADD(&pData->StatPktRecvBytes, dwNumberOfBytesTransferred);
257
258#ifdef DEBUG
259 pData->dwLastWriteTime = timeGetTime();
260 Log(("drvTAPW32Receive %d bytes at %08x - delta %x\n", dwNumberOfBytesTransferred,
261 pData->dwLastWriteTime, pData->dwLastWriteTime - pData->dwLastReadTime));
262#endif
263
264 rc = pData->pPort->pfnReceive(pData->pPort, pData->readBuffer, dwNumberOfBytesTransferred);
265 AssertRC(rc);
266
267 memset(&pData->overlappedRead, 0, sizeof(pData->overlappedRead));
268 }
269 else
270 {
271 rc = GetLastError();
272 Assert(rc == ERROR_IO_INCOMPLETE);
273
274 /* reset overlapped structure on aborted read operation */
275 if (rc != ERROR_IO_INCOMPLETE)
276 {
277 memset(&pData->overlappedRead, 0, sizeof(pData->overlappedRead));
278 }
279 break;
280 }
281 }
282 cbMax = pData->pPort->pfnCanReceive(pData->pPort);
283 }
284 STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
285}
286#else /* !ASYNC_NETIO */
287/**
288 * Async I/O thread for an interface.
289 */
290static DECLCALLBACK(int) drvTAPW32AsyncIo(RTTHREAD ThreadSelf, void *pvUser)
291{
292 PDRVTAP pData = (PDRVTAP)pvUser;
293 HANDLE haWait[2];
294 DWORD rc = ERROR_SUCCESS, dwNumberOfBytesTransferred;
295
296 Assert(pData);
297 haWait[0] = pData->hEventRead;
298 haWait[1] = pData->hHaltAsyncEventSem;
299
300 rc = RTSemEventCreate(&pData->EventOutOfSpace);
301 AssertRC(rc);
302
303 while(1)
304 {
305 BOOL bRet;
306
307 memset(&pData->overlappedRead, 0, sizeof(pData->overlappedRead));
308 pData->overlappedRead.hEvent = pData->hEventRead;
309 bRet = ReadFile(pData->hFile, pData->readBuffer, sizeof(pData->readBuffer),
310 &dwNumberOfBytesTransferred, &pData->overlappedRead);
311 if (bRet == FALSE)
312 {
313 rc = GetLastError();
314 AssertMsg(rc == ERROR_IO_PENDING || rc == ERROR_MORE_DATA, ("ReadFile failed with rc=%d\n", rc));
315 if (rc != ERROR_IO_PENDING && rc != ERROR_MORE_DATA)
316 break;
317
318 rc = WaitForMultipleObjects(2, &haWait[0], FALSE, INFINITE);
319 AssertMsg(rc == WAIT_OBJECT_0 || rc == WAIT_OBJECT_0+1, ("WaitForSingleObject failed with %x\n", rc));
320
321 if (rc != WAIT_OBJECT_0)
322 break; /* asked to quit or fatal error. */
323
324 rc = GetOverlappedResult(pData->hFile, &pData->overlappedRead, &dwNumberOfBytesTransferred, FALSE);
325 Assert(rc == TRUE);
326
327 /* If GetOverlappedResult() returned with TRUE, the operation was finished successfully */
328 }
329
330 /* Not very nice, but what else can we do? */
331 size_t cbMax = pData->pPort->pfnCanReceive(pData->pPort);
332 if (cbMax < dwNumberOfBytesTransferred)
333 {
334 STAM_PROFILE_START(&pData->StatRecvOverflows, b);
335 while (cbMax < dwNumberOfBytesTransferred)
336 {
337#if 1
338 ASMAtomicXchgU32(&pData->fOutOfSpace, true);
339 RTSemEventWait(pData->EventOutOfSpace, 50);
340#else
341 RTThreadSleep(16); /* @todo right value? */
342#endif
343 /* Check if the VM was terminated */
344 rc = WaitForSingleObject(haWait[1], 0);
345 if (rc == WAIT_OBJECT_0)
346 goto exit_thread;
347
348 cbMax = pData->pPort->pfnCanReceive(pData->pPort);
349 }
350 ASMAtomicXchgU32(&pData->fOutOfSpace, false);
351 STAM_PROFILE_STOP(&pData->StatRecvOverflows, b);
352 Assert(cbMax >= dwNumberOfBytesTransferred);
353 }
354
355 STAM_COUNTER_INC(&pData->StatPktRecv);
356 STAM_COUNTER_ADD(&pData->StatPktRecvBytes, dwNumberOfBytesTransferred);
357#ifdef DEBUG
358 pData->dwLastWriteTime = timeGetTime();
359 Log(("drvTAPW32AsyncIo %d bytes at %08x - delta %x\n", dwNumberOfBytesTransferred,
360 pData->dwLastWriteTime, pData->dwLastWriteTime - pData->dwLastReadTime));
361#endif
362 rc = pData->pPort->pfnReceive(pData->pPort, pData->readBuffer, dwNumberOfBytesTransferred);
363 AssertRC(rc);
364 }
365
366exit_thread:
367 SetEvent(pData->hHaltAsyncEventSem);
368 Log(("drvTAPW32AsyncIo: exit thread!!\n"));
369 return VINF_SUCCESS;
370}
371#endif /* !ASYNC_NETIO */
372
373/**
374 * Queries an interface to the driver.
375 *
376 * @returns Pointer to interface.
377 * @returns NULL if the interface was not supported by the driver.
378 * @param pInterface Pointer to this interface structure.
379 * @param enmInterface The requested interface identification.
380 * @thread Any thread.
381 */
382static DECLCALLBACK(void *) drvTAPW32QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
383{
384 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
385 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
386 switch (enmInterface)
387 {
388 case PDMINTERFACE_BASE:
389 return &pDrvIns->IBase;
390 case PDMINTERFACE_NETWORK_CONNECTOR:
391 return &pData->INetworkConnector;
392 default:
393 return NULL;
394 }
395}
396
397
398/**
399 * Destruct a driver instance.
400 *
401 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
402 * resources can be freed correctly.
403 *
404 * @param pDrvIns The driver instance data.
405 */
406static DECLCALLBACK(void) drvTAPW32Destruct(PPDMDRVINS pDrvIns)
407{
408 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
409 TAP_MEDIASTATUS mediastatus;
410 DWORD dwLength;
411
412 LogFlow(("drvTAPW32Destruct\n"));
413
414#ifdef ASYNC_NETIO
415 /* Ensure that it does not spin in the CanReceive loop */
416 if (ASMAtomicXchgU32(&pData->fOutOfSpace, false))
417 RTSemEventSignal(pData->EventOutOfSpace);
418
419 /* @todo this isn't a safe method to notify the async thread; it might be using the instance data after we've been
420 * destroyed; could wait for it to terminate, but that's not without risks either.
421 */
422 SetEvent(pData->hHaltAsyncEventSem);
423
424 /* Yield or else our async thread will never acquire the event semaphore */
425 RTThreadSleep(16);
426 /* Wait for the async thread to quit; up to half a second */
427 WaitForSingleObject(pData->hHaltAsyncEventSem, 500);
428#endif
429
430 mediastatus.fConnect = FALSE;
431 BOOL ret = DeviceIoControl(pData->hFile, TAP_IOCTL_SET_MEDIA_STATUS,
432 &mediastatus, sizeof(mediastatus), NULL, 0, &dwLength, NULL);
433 Assert(ret);
434
435 CloseHandle(pData->hEventWrite);
436 CancelIo(pData->hFile);
437 CloseHandle(pData->hFile);
438}
439
440
441/**
442 * Construct a TUN network transport driver instance.
443 *
444 * @returns VBox status.
445 * @param pDrvIns The driver instance data.
446 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
447 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
448 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
449 * iInstance it's expected to be used a bit in this function.
450 */
451static DECLCALLBACK(int) drvTAPW32Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
452{
453 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
454
455 /*
456 * Init the static parts.
457 */
458 pData->pDrvIns = pDrvIns;
459 pData->hFile = INVALID_HANDLE_VALUE;
460 /* IBase */
461 pDrvIns->IBase.pfnQueryInterface = drvTAPW32QueryInterface;
462 /* INetwork */
463 pData->INetworkConnector.pfnSend = drvTAPW32Send;
464 pData->INetworkConnector.pfnSetPromiscuousMode = drvTAPW32SetPromiscuousMode;
465 pData->INetworkConnector.pfnNotifyLinkChanged = drvTAPW32NotifyLinkChanged;
466 pData->INetworkConnector.pfnNotifyCanReceive = drvTAPW32NotifyCanReceive;
467
468 /*
469 * Validate the config.
470 */
471 if (!CFGMR3AreValuesValid(pCfgHandle, "Device\0HostInterfaceName\0GUID\0"))
472 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
473
474 /*
475 * Check that no-one is attached to us.
476 */
477 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, NULL);
478 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
479 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_NO_ATTACH,
480 N_("Configuration error: Cannot attach drivers to the TUN driver!"));
481
482 /*
483 * Query the network port interface.
484 */
485 pData->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
486 if (!pData->pPort)
487 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
488 N_("Configuration error: the above device/driver didn't export the network port interface!"));
489
490 /*
491 * Read the configuration.
492 */
493 char *pszHostDriver = NULL;
494 rc = CFGMR3QueryStringAlloc(pCfgHandle, "HostInterfaceName", &pszHostDriver);
495 if (VBOX_FAILURE(rc))
496 return PDMDRV_SET_ERROR(pDrvIns, rc,
497 N_("Configuration error: query for \"HostInterfaceName\" failed."));
498
499 TAP_VERSION version;
500 TAP_MEDIASTATUS mediastatus;
501 DWORD length;
502 char szFullDriverName[256];
503 char szDriverGUID[256] = {0};
504
505 rc = CFGMR3QueryBytes(pCfgHandle, "GUID", szDriverGUID, sizeof(szDriverGUID));
506 if (VBOX_FAILURE(rc))
507 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
508 N_("Configuration error: could not query GUID!"));
509
510 RTStrPrintfEx(NULL, NULL, szFullDriverName, sizeof(szFullDriverName), "\\\\.\\Global\\%s.tap", szDriverGUID);
511
512 pData->hFile = CreateFile(szFullDriverName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
513 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
514
515 if (pData->hFile == INVALID_HANDLE_VALUE)
516 {
517 rc = GetLastError();
518
519 AssertMsgFailed(("Configuration error: TAP device name %s is not valid! (rc=%d)\n", szFullDriverName, rc));
520 if (rc == ERROR_SHARING_VIOLATION)
521 return VERR_PDM_HIF_SHARING_VIOLATION;
522
523 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_HIF_OPEN_FAILED,
524 N_("Failed to open Host Interface Networking device driver"));
525 }
526
527 BOOL ret = DeviceIoControl(pData->hFile, TAP_IOCTL_GET_VERSION, &version, sizeof (version),
528 &version, sizeof(version), &length, NULL);
529 if (ret == FALSE)
530 {
531 CloseHandle(pData->hFile);
532 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
533 }
534
535 mediastatus.fConnect = TRUE;
536 ret = DeviceIoControl(pData->hFile, TAP_IOCTL_SET_MEDIA_STATUS, &mediastatus, sizeof(mediastatus), NULL, 0, &length, NULL);
537 if (ret == FALSE)
538 {
539 CloseHandle(pData->hFile);
540 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
541 }
542
543 Log(("TAP version %d.%d\n", version.major, version.minor));
544 if (pszHostDriver)
545 MMR3HeapFree(pszHostDriver);
546
547 pData->hEventWrite = CreateEvent(NULL, FALSE, FALSE, NULL);
548 pData->hEventRead = CreateEvent(NULL, FALSE, FALSE, NULL);
549 memset(&pData->overlappedRead, 0, sizeof(pData->overlappedRead));
550
551#ifdef ASYNC_NETIO
552 /* Create asynchronous thread */
553 rc = RTThreadCreate(&pData->hThread, drvTAPW32AsyncIo, (void *)pData, 128*1024, RTTHREADTYPE_IO, 0, "TAPWIN32");
554 AssertRC(rc);
555
556 pData->hHaltAsyncEventSem = CreateEvent(NULL, FALSE, FALSE, NULL);
557
558 Assert(pData->hThread != NIL_RTTHREAD && pData->hHaltAsyncEventSem != NULL);
559#else
560 /*
561 * Register poller
562 */
563 rc = pDrvIns->pDrvHlp->pfnPDMPollerRegister(pDrvIns, drvTAPW32Poller);
564 AssertRC(rc);
565#endif
566
567#ifdef VBOX_WITH_STATISTICS
568 /*
569 * Statistics.
570 */
571 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktSent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of sent packets.", "/Drivers/TAP%d/Packets/Sent", pDrvIns->iInstance);
572 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktSentBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Drivers/TAP%d/Bytes/Sent", pDrvIns->iInstance);
573 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of received packets.", "/Drivers/TAP%d/Packets/Received", pDrvIns->iInstance);
574 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktRecvBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Drivers/TAP%d/Bytes/Received", pDrvIns->iInstance);
575 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Drivers/TAP%d/Transmit", pDrvIns->iInstance);
576 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Drivers/TAP%d/Receive", pDrvIns->iInstance);
577# ifdef ASYNC_NETIO
578 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatRecvOverflows,STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling packet receive overflows.", "/Drivers/TAP%d/RecvOverflows", pDrvIns->iInstance);
579# endif
580#endif
581
582 return rc;
583}
584
585
586/**
587 * Host Interface network transport driver registration record.
588 */
589const PDMDRVREG g_DrvHostInterface =
590{
591 /* u32Version */
592 PDM_DRVREG_VERSION,
593 /* szDriverName */
594 "HostInterface",
595 /* pszDescription */
596 "Host Interface Network Transport Driver",
597 /* fFlags */
598 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
599 /* fClass. */
600 PDM_DRVREG_CLASS_NETWORK,
601 /* cMaxInstances */
602 ~0,
603 /* cbInstance */
604 sizeof(DRVTAP),
605 /* pfnConstruct */
606 drvTAPW32Construct,
607 /* pfnDestruct */
608 drvTAPW32Destruct,
609 /* pfnIOCtl */
610 NULL,
611 /* pfnPowerOn */
612 NULL,
613 /* pfnReset */
614 NULL,
615 /* pfnSuspend */
616 NULL,
617 /* pfnResume */
618 NULL,
619 /* pfnDetach */
620 NULL,
621 /* pfnPowerOff */
622 NULL
623};
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