VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvTAPWin32.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: 22.7 KB
Line 
1/** @file
2 *
3 * VBox network devices:
4 * Linux/Win32 TUN 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#define ASYNC_NETIO
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_DRV_TUN
26#include <VBox/pdmdrv.h>
27#include <VBox/stam.h>
28
29#include <VBox/log.h>
30#include <iprt/assert.h>
31#include <iprt/file.h>
32#include <iprt/string.h>
33#include <iprt/thread.h>
34#ifdef ASYNC_NETIO
35#include <iprt/asm.h>
36#include <iprt/semaphore.h>
37#endif
38
39#include <windows.h>
40#include <VBox/tapwin32.h>
41
42#include "Builtins.h"
43
44/*******************************************************************************
45* Structures and Typedefs *
46*******************************************************************************/
47/**
48 * Block driver instance data.
49 */
50typedef struct
51{
52 /** The network interface. */
53 PDMINETWORKCONNECTOR INetworkConnector;
54 /** The network interface. */
55 PPDMINETWORKPORT pPort;
56 /** Pointer to the driver instance. */
57 PPDMDRVINS pDrvIns;
58 /** TAP device file handle. */
59 HANDLE hFile;
60
61 HANDLE hEventWrite;
62 HANDLE hEventRead;
63
64 OVERLAPPED overlappedRead;
65 DWORD dwNumberOfBytesRead;
66 uint8_t readBuffer[4096];
67
68 TAP_VERSION tapVersion;
69
70#ifdef ASYNC_NETIO
71 /** The thread handle. NIL_RTTHREAD if no thread. */
72 RTTHREAD hThread;
73 /** The event semaphore the thread is waiting on. */
74 HANDLE hHaltAsyncEventSem;
75 /** We are waiting for more receive buffers. */
76 uint32_t volatile fOutOfSpace;
77 /** Event semaphore for blocking on receive. */
78 RTSEMEVENT EventOutOfSpace;
79#endif
80
81#ifdef DEBUG
82 DWORD dwLastReadTime;
83 DWORD dwLastWriteTime;
84#endif
85
86#ifdef VBOX_WITH_STATISTICS
87 /** Number of sent packets. */
88 STAMCOUNTER StatPktSent;
89 /** Number of sent bytes. */
90 STAMCOUNTER StatPktSentBytes;
91 /** Number of received packets. */
92 STAMCOUNTER StatPktRecv;
93 /** Number of received bytes. */
94 STAMCOUNTER StatPktRecvBytes;
95 /** Profiling packet transmit runs. */
96 STAMPROFILEADV StatTransmit;
97 /** Profiling packet receive runs. */
98 STAMPROFILEADV StatReceive;
99# ifdef ASYNC_NETIO
100 STAMPROFILE StatRecvOverflows;
101# endif
102#endif /* VBOX_WITH_STATISTICS */
103} DRVTAP, *PDRVTAP;
104
105/** Converts a pointer to TUN::INetworkConnector to a PRDVTUN. */
106#define PDMINETWORKCONNECTOR_2_DRVTAP(pInterface) ( (PDRVTAP)((uintptr_t)pInterface - RT_OFFSETOF(DRVTAP, INetworkConnector)) )
107
108/**
109 * Send data to the network.
110 *
111 * @returns VBox status code.
112 * @param pInterface Pointer to the interface structure containing the called function pointer.
113 * @param pvBuf Data to send.
114 * @param cb Number of bytes to send.
115 * @thread EMT
116 */
117static DECLCALLBACK(int) drvTAPW32Send(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
118{
119 OVERLAPPED overlapped;
120 DWORD cbBytesWritten;
121 int rc;
122 PDRVTAP pData = PDMINETWORKCONNECTOR_2_DRVTAP(pInterface);
123
124 Log2(("drvTAPW32Send%d: pvBuf=%p cb=%#x\n"
125 "%.*Vhxd\n", pData->pDrvIns->iInstance, pvBuf, cb, cb, pvBuf));
126
127#ifdef DEBUG
128 pData->dwLastReadTime = timeGetTime();
129 Log(("drvTAPW32Send %d bytes at %08x - delta %x\n", cb, pData->dwLastReadTime, pData->dwLastReadTime - pData->dwLastWriteTime));
130#endif
131
132 STAM_COUNTER_INC(&pData->StatPktSent);
133 STAM_COUNTER_ADD(&pData->StatPktSentBytes, cb);
134 STAM_PROFILE_ADV_START(&pData->StatTransmit, a);
135
136 memset(&overlapped, 0, sizeof(overlapped));
137 overlapped.hEvent = pData->hEventWrite;
138
139 rc = VINF_SUCCESS;
140 if (WriteFile(pData->hFile, pvBuf, cb, &cbBytesWritten, &overlapped) == FALSE)
141 {
142 if (GetLastError() == ERROR_IO_PENDING)
143 {
144 Log(("drvTAPW32Send: IO pending!!\n"));
145 rc = WaitForSingleObject(overlapped.hEvent, INFINITE);
146 AssertMsg(rc == WAIT_OBJECT_0, ("WaitForSingleObject failed with %x\n", rc));
147 rc = VINF_SUCCESS;
148 }
149 else
150 {
151 AssertMsgFailed(("WriteFile failed with %d\n", GetLastError()));
152 rc = RTErrConvertFromWin32(GetLastError());
153 }
154 }
155 STAM_PROFILE_ADV_STOP(&pData->StatTransmit, a);
156 AssertRC(rc);
157 return rc;
158}
159
160
161/**
162 * Set promiscuous mode.
163 *
164 * This is called when the promiscuous mode is set. This means that there doesn't have
165 * to be a mode change when it's called.
166 *
167 * @param pInterface Pointer to the interface structure containing the called function pointer.
168 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
169 * @thread EMT
170 */
171static DECLCALLBACK(void) drvTAPW32SetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
172{
173 LogFlow(("drvTAPW32SetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
174 /* nothing to do */
175}
176
177
178/**
179 * Notification on link status changes.
180 *
181 * @param pInterface Pointer to the interface structure containing the called function pointer.
182 * @param enmLinkState The new link state.
183 * @thread EMT
184 */
185static DECLCALLBACK(void) drvTAPW32NotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
186{
187 LogFlow(("drvNATW32NotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
188 /** @todo take action on link down and up. Stop the polling and such like. */
189}
190
191
192/**
193 * More receive buffer has become available.
194 *
195 * This is called when the NIC frees up receive buffers.
196 *
197 * @param pInterface Pointer to the interface structure containing the called function pointer.
198 * @thread EMT
199 */
200static DECLCALLBACK(void) drvTAPW32NotifyCanReceive(PPDMINETWORKCONNECTOR pInterface)
201{
202 PDRVTAP pData = PDMINETWORKCONNECTOR_2_DRVTAP(pInterface);
203
204 LogFlow(("drvTAPW32NotifyCanReceive:\n"));
205 if (ASMAtomicXchgU32(&pData->fOutOfSpace, false))
206 RTSemEventSignal(pData->EventOutOfSpace);
207}
208
209
210#ifndef ASYNC_NETIO
211/**
212 * Poller callback.
213 */
214static DECLCALLBACK(void) drvTAPW32Poller(PPDMDRVINS pDrvIns)
215{
216 DWORD rc = ERROR_SUCCESS;
217 PDRVTAP pData = PDMINS2DATA(pDrvIns, PDRVTAP);
218 STAM_PROFILE_ADV_START(&pData->StatReceive, a);
219
220 /* check how much the device/driver can receive now. */
221 size_t cbMax = pData->pPort->pfnCanReceive(pData->pPort);
222
223 while (cbMax)
224 {
225 if (cbMax > 0 && !pData->overlappedRead.hEvent)
226 {
227 BOOL bRet;
228
229 cbMax = RT_MIN(cbMax, sizeof(pData->readBuffer));
230 memset(&pData->overlappedRead, 0, sizeof(pData->overlappedRead));
231 pData->overlappedRead.hEvent = pData->hEventRead;
232 bRet = ReadFile(pData->hFile, pData->readBuffer, cbMax, &pData->dwNumberOfBytesRead, &pData->overlappedRead);
233 if (bRet == FALSE)
234 {
235 rc = GetLastError();
236 AssertMsg(rc == ERROR_SUCCESS || rc == ERROR_IO_PENDING || rc == ERROR_MORE_DATA, ("ReadFileEx failed with rc=%d\n", rc));
237 if (rc != ERROR_IO_PENDING && rc != ERROR_MORE_DATA)
238 break;
239 }
240 }
241 if (cbMax)
242 {
243 DWORD dwNumberOfBytesTransferred = 0;
244
245 if (GetOverlappedResult(pData->hFile, &pData->overlappedRead, &dwNumberOfBytesTransferred, FALSE) == TRUE)
246 {
247 /* push it to the driver. */
248 Log2(("drvTAPW32Poller%d: cbRead=%#x\n"
249 "%.*Vhxd\n", pData->InstanceNr,
250 dwNumberOfBytesTransferred, dwNumberOfBytesTransferred, pData->readBuffer));
251
252 STAM_COUNTER_INC(&pData->StatPktRecv);
253 STAM_COUNTER_ADD(&pData->StatPktRecvBytes, dwNumberOfBytesTransferred);
254
255#ifdef DEBUG
256 pData->dwLastWriteTime = timeGetTime();
257 Log(("drvTAPW32Receive %d bytes at %08x - delta %x\n", dwNumberOfBytesTransferred,
258 pData->dwLastWriteTime, pData->dwLastWriteTime - pData->dwLastReadTime));
259#endif
260
261 rc = pData->pPort->pfnReceive(pData->pPort, pData->readBuffer, dwNumberOfBytesTransferred);
262 AssertRC(rc);
263
264 memset(&pData->overlappedRead, 0, sizeof(pData->overlappedRead));
265 }
266 else
267 {
268 rc = GetLastError();
269 Assert(rc == ERROR_IO_INCOMPLETE);
270
271 /* reset overlapped structure on aborted read operation */
272 if (rc != ERROR_IO_INCOMPLETE)
273 {
274 memset(&pData->overlappedRead, 0, sizeof(pData->overlappedRead));
275 }
276 break;
277 }
278 }
279 cbMax = pData->pPort->pfnCanReceive(pData->pPort);
280 }
281 STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
282}
283#else /* !ASYNC_NETIO */
284/**
285 * Async I/O thread for an interface.
286 */
287static DECLCALLBACK(int) drvTAPW32AsyncIo(RTTHREAD ThreadSelf, void *pvUser)
288{
289 PDRVTAP pData = (PDRVTAP)pvUser;
290 HANDLE haWait[2];
291 DWORD rc = ERROR_SUCCESS, dwNumberOfBytesTransferred;
292
293 Assert(pData);
294 haWait[0] = pData->hEventRead;
295 haWait[1] = pData->hHaltAsyncEventSem;
296
297 rc = RTSemEventCreate(&pData->EventOutOfSpace);
298 AssertRC(rc);
299
300 while(1)
301 {
302 BOOL bRet;
303
304 memset(&pData->overlappedRead, 0, sizeof(pData->overlappedRead));
305 pData->overlappedRead.hEvent = pData->hEventRead;
306 bRet = ReadFile(pData->hFile, pData->readBuffer, sizeof(pData->readBuffer),
307 &dwNumberOfBytesTransferred, &pData->overlappedRead);
308 if (bRet == FALSE)
309 {
310 rc = GetLastError();
311 AssertMsg(rc == ERROR_IO_PENDING || rc == ERROR_MORE_DATA, ("ReadFile failed with rc=%d\n", rc));
312 if (rc != ERROR_IO_PENDING && rc != ERROR_MORE_DATA)
313 break;
314
315 rc = WaitForMultipleObjects(2, &haWait[0], FALSE, INFINITE);
316 AssertMsg(rc == WAIT_OBJECT_0 || rc == WAIT_OBJECT_0+1, ("WaitForSingleObject failed with %x\n", rc));
317
318 if (rc != WAIT_OBJECT_0)
319 break; /* asked to quit or fatal error. */
320
321 rc = GetOverlappedResult(pData->hFile, &pData->overlappedRead, &dwNumberOfBytesTransferred, FALSE);
322 Assert(rc == TRUE);
323
324 /* If GetOverlappedResult() returned with TRUE, the operation was finished successfully */
325 }
326
327 /* Not very nice, but what else can we do? */
328 size_t cbMax = pData->pPort->pfnCanReceive(pData->pPort);
329 if (cbMax < dwNumberOfBytesTransferred)
330 {
331 STAM_PROFILE_START(&pData->StatRecvOverflows, b);
332 while (cbMax < dwNumberOfBytesTransferred)
333 {
334#if 1
335 ASMAtomicXchgU32(&pData->fOutOfSpace, true);
336 RTSemEventWait(pData->EventOutOfSpace, 50);
337#else
338 RTThreadSleep(16); /* @todo right value? */
339#endif
340 /* Check if the VM was terminated */
341 rc = WaitForSingleObject(haWait[1], 0);
342 if (rc == WAIT_OBJECT_0)
343 {
344 STAM_PROFILE_STOP(&pData->StatRecvOverflows, b);
345 goto exit_thread;
346 }
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 /** @todo this isn't a safe method to notify the async thread; it might be using the instance
416 * data after we've been destroyed; could wait for it to terminate, but that's not
417 * without risks either.
418 */
419 SetEvent(pData->hHaltAsyncEventSem);
420
421 /* Ensure that it does not spin in the CanReceive loop. Do it _after_ we set set the
422 * hHaltAsyncEventSem to ensure that we don't go into the loop again immediately. */
423 if (ASMAtomicXchgU32(&pData->fOutOfSpace, false))
424 RTSemEventSignal(pData->EventOutOfSpace);
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_MEDIASTATUS mediastatus;
502 DWORD length;
503 char szFullDriverName[256];
504 char szDriverGUID[256] = {0};
505
506 rc = CFGMR3QueryBytes(pCfgHandle, "GUID", szDriverGUID, sizeof(szDriverGUID));
507 if (VBOX_FAILURE(rc))
508 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
509 N_("Configuration error: could not query GUID!"));
510
511 RTStrPrintfEx(NULL, NULL, szFullDriverName, sizeof(szFullDriverName), "\\\\.\\Global\\%s.tap", szDriverGUID);
512
513 pData->hFile = CreateFile(szFullDriverName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
514 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
515
516 if (pData->hFile == INVALID_HANDLE_VALUE)
517 {
518 rc = GetLastError();
519
520 AssertMsgFailed(("Configuration error: TAP device name %s is not valid! (rc=%d)\n", szFullDriverName, rc));
521 if (rc == ERROR_SHARING_VIOLATION)
522 return VERR_PDM_HIF_SHARING_VIOLATION;
523
524 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_HIF_OPEN_FAILED,
525 N_("Failed to open Host Interface Networking device driver"));
526 }
527
528 BOOL ret = DeviceIoControl(pData->hFile, TAP_IOCTL_GET_VERSION, &pData->tapVersion, sizeof (pData->tapVersion),
529 &pData->tapVersion, sizeof(pData->tapVersion), &length, NULL);
530 if (ret == FALSE)
531 {
532 CloseHandle(pData->hFile);
533 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_HIF_INVALID_VERSION,
534 N_("Failed to get the Host Interface Networking device driver version."));;
535 }
536 LogRel(("TAP version %d.%d\n", pData->tapVersion.major, pData->tapVersion.minor));
537
538 /* Must be at least version 8.1 */
539 if ( pData->tapVersion.major != 8
540 || pData->tapVersion.minor < 1)
541 {
542 CloseHandle(pData->hFile);
543 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_HIF_INVALID_VERSION,
544 N_("Invalid Host Interface Networking device driver version."));;
545 }
546
547 mediastatus.fConnect = TRUE;
548 ret = DeviceIoControl(pData->hFile, TAP_IOCTL_SET_MEDIA_STATUS, &mediastatus, sizeof(mediastatus), NULL, 0, &length, NULL);
549 if (ret == FALSE)
550 {
551 CloseHandle(pData->hFile);
552 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
553 }
554
555 if (pszHostDriver)
556 MMR3HeapFree(pszHostDriver);
557
558 pData->hEventWrite = CreateEvent(NULL, FALSE, FALSE, NULL);
559 pData->hEventRead = CreateEvent(NULL, FALSE, FALSE, NULL);
560 memset(&pData->overlappedRead, 0, sizeof(pData->overlappedRead));
561
562#ifdef ASYNC_NETIO
563 pData->hHaltAsyncEventSem = CreateEvent(NULL, FALSE, FALSE, NULL);
564
565 /* Create asynchronous thread */
566 rc = RTThreadCreate(&pData->hThread, drvTAPW32AsyncIo, (void *)pData, 128*1024, RTTHREADTYPE_IO, 0, "TAPWIN32");
567 AssertRC(rc);
568
569 Assert(pData->hThread != NIL_RTTHREAD && pData->hHaltAsyncEventSem != NULL);
570#else
571 /*
572 * Register poller
573 */
574 rc = pDrvIns->pDrvHlp->pfnPDMPollerRegister(pDrvIns, drvTAPW32Poller);
575 AssertRC(rc);
576#endif
577
578#ifdef VBOX_WITH_STATISTICS
579 /*
580 * Statistics.
581 */
582 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktSent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of sent packets.", "/Drivers/TAP%d/Packets/Sent", pDrvIns->iInstance);
583 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktSentBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Drivers/TAP%d/Bytes/Sent", pDrvIns->iInstance);
584 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of received packets.", "/Drivers/TAP%d/Packets/Received", pDrvIns->iInstance);
585 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktRecvBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Drivers/TAP%d/Bytes/Received", pDrvIns->iInstance);
586 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Drivers/TAP%d/Transmit", pDrvIns->iInstance);
587 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Drivers/TAP%d/Receive", pDrvIns->iInstance);
588# ifdef ASYNC_NETIO
589 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatRecvOverflows,STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling packet receive overflows.", "/Drivers/TAP%d/RecvOverflows", pDrvIns->iInstance);
590# endif
591#endif
592
593 return rc;
594}
595
596
597/**
598 * Host Interface network transport driver registration record.
599 */
600const PDMDRVREG g_DrvHostInterface =
601{
602 /* u32Version */
603 PDM_DRVREG_VERSION,
604 /* szDriverName */
605 "HostInterface",
606 /* pszDescription */
607 "Host Interface Network Transport Driver",
608 /* fFlags */
609 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
610 /* fClass. */
611 PDM_DRVREG_CLASS_NETWORK,
612 /* cMaxInstances */
613 ~0,
614 /* cbInstance */
615 sizeof(DRVTAP),
616 /* pfnConstruct */
617 drvTAPW32Construct,
618 /* pfnDestruct */
619 drvTAPW32Destruct,
620 /* pfnIOCtl */
621 NULL,
622 /* pfnPowerOn */
623 NULL,
624 /* pfnReset */
625 NULL,
626 /* pfnSuspend */
627 NULL,
628 /* pfnResume */
629 NULL,
630 /* pfnDetach */
631 NULL,
632 /* pfnPowerOff */
633 NULL
634};
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