VirtualBox

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

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

forward port of the TAPWin32 destruct fix

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