VirtualBox

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

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

Added INetworkConnector callback for sending multiple packets

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