VirtualBox

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

Last change on this file since 507 was 507, checked in by vboxsync, 18 years ago

TAP Update

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