VirtualBox

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

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

Use pdmdrv.h and pdmdev.h where appropirate.

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