VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvTAPOs2.cpp@ 7974

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

net: moved the wait/notify mechanism for receive buffers into the device

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.2 KB
Line 
1/** $Id: DrvTAPOs2.cpp 7831 2008-04-09 12:31:12Z vboxsync $ */
2/** @file
3 * VBox network devices: OS/2 TAP network transport driver.
4 */
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 (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_TUN
23#include <VBox/pdmdrv.h>
24
25#include <iprt/assert.h>
26#include <iprt/file.h>
27#include <iprt/string.h>
28#include <iprt/thread.h>
29#include <iprt/alloca.h>
30#include <iprt/asm.h>
31#include <iprt/semaphore.h>
32
33#include "Builtins.h"
34
35#define INCL_BASE
36#include <os2.h>
37#include "DrvTAPOs2.h"
38
39
40
41/*******************************************************************************
42* Structures and Typedefs *
43*******************************************************************************/
44
45/**
46 * Block driver instance data.
47 */
48typedef struct DRVTAPOS2
49{
50 /** The network interface. */
51 PDMINETWORKCONNECTOR INetworkConnector;
52 /** The network interface. */
53 PPDMINETWORKPORT pPort;
54 /** Pointer to the driver instance. */
55 PPDMDRVINS pDrvIns;
56 /** TAP device file handle. */
57 RTFILE hDevice;
58 /** Out LAN number. */
59 int32_t iLan;
60 /** The LAN number we're connected to. -1 if not connected. */
61 int32_t iConnectedTo;
62 /** Receiver thread. */
63 PPDMTHREAD pThread;
64 /** Set if the link is down.
65 * When the link is down all incoming packets will be dropped. */
66 bool volatile fLinkDown;
67 /** The log and thread name. */
68 char szName[16];
69 /** The \DEV\TAP$ device name. */
70 char szDevice[32];
71
72#ifdef VBOX_WITH_STATISTICS
73 /** Number of sent packets. */
74 STAMCOUNTER StatPktSent;
75 /** Number of sent bytes. */
76 STAMCOUNTER StatPktSentBytes;
77 /** Number of received packets. */
78 STAMCOUNTER StatPktRecv;
79 /** Number of received bytes. */
80 STAMCOUNTER StatPktRecvBytes;
81 /** Profiling packet transmit runs. */
82 STAMPROFILE StatTransmit;
83 /** Profiling packet receive runs. */
84 STAMPROFILEADV StatReceive;
85#endif /* VBOX_WITH_STATISTICS */
86
87#ifdef LOG_ENABLED
88 /** The nano ts of the last transfer. */
89 uint64_t u64LastTransferTS;
90 /** The nano ts of the last receive. */
91 uint64_t u64LastReceiveTS;
92#endif
93} DRVTAPOS2, *PDRVTAPOS2;
94
95
96/** Converts a pointer to TAP::INetworkConnector to a PRDVTAP. */
97#define PDMINETWORKCONNECTOR_2_DRVTAPOS2(pInterface) ( (PDRVTAPOS2)((uintptr_t)pInterface - RT_OFFSETOF(DRVTAPOS2, INetworkConnector)) )
98
99
100/**
101 * Send data to the network.
102 *
103 * @returns VBox status code.
104 * @param pInterface Pointer to the interface structure containing the called function pointer.
105 * @param pvBuf Data to send.
106 * @param cb Number of bytes to send.
107 * @thread EMT
108 */
109static DECLCALLBACK(int) drvTAPOs2Send(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
110{
111 PDRVTAPOS2 pThis = PDMINETWORKCONNECTOR_2_DRVTAPOS2(pInterface);
112 STAM_COUNTER_INC(&pThis->StatPktSent);
113 STAM_COUNTER_ADD(&pThis->StatPktSentBytes, cb);
114 STAM_PROFILE_START(&pThis->StatTransmit, a);
115
116 /*
117 * If the pvBuf is a high address, we'll have to copy it onto a
118 * stack buffer of the tap driver will trap.
119 */
120 if ((uintptr_t)pvBuf >= _1M*512)
121 {
122 void *pvBufCopy = alloca(cb);
123 memcpy(pvBufCopy, pvBuf, cb);
124 pvBuf = pvBufCopy;
125 }
126
127#ifdef LOG_ENABLED
128 uint64_t u64Now = RTTimeProgramNanoTS();
129 LogFlow(("%s: Send: %-4d bytes at %RU64 ns deltas: recv=%RU64 xmit=%RU64\n", pThis->szName,
130 cb, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
131 pThis->u64LastTransferTS = u64Now;
132 Log2(("%s Send: pvBuf=%p cb=%#zx\n"
133 "%.*Vhxd\n",
134 pThis->szName, pvBuf, cb, cb, pvBuf));
135#endif
136
137 ULONG Parm[2] = { ~0UL, ~0UL }; /* mysterious output */
138 ULONG cbParm = sizeof(Parm);
139 ULONG cbData = cb;
140 int rc = DosDevIOCtl(pThis->hDevice, PROT_CATEGORY, TAP_WRITE_PACKET,
141 &Parm[0], cbParm, &cbParm,
142 (void *)pvBuf, cbData, &cbData);
143 if (RT_UNLIKELY(rc || Parm[0]))
144 {
145 static unsigned cComplaints = 0;
146 if (cComplaints++ < 256)
147 LogRel(("%s: send failed. rc=%d Parm={%ld,%ld} cb=%d\n",
148 pThis->szName, rc, Parm[0], Parm[1], cb));
149 if (rc)
150 rc = RTErrConvertFromOS2(rc);
151 else
152 rc = VERR_IO_GEN_FAILURE;
153 }
154 Log3(("%s: Send completed %d ns\n", pThis->szName, RTTimeProgramNanoTS() - pThis->u64LastTransferTS));
155
156 STAM_PROFILE_STOP(&pThis->StatTransmit, a);
157 AssertRC(rc);
158 return rc;
159}
160
161
162/**
163 * Set promiscuous mode.
164 *
165 * This is called when the promiscuous mode is set. This means that there doesn't have
166 * to be a mode change when it's called.
167 *
168 * @param pInterface Pointer to the interface structure containing the called function pointer.
169 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
170 * @thread EMT
171 */
172static DECLCALLBACK(void) drvTAPOs2SetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
173{
174 PDRVTAPOS2 pThis = PDMINETWORKCONNECTOR_2_DRVTAPOS2(pInterface);
175 LogFlow(("%s: SetPromiscuousMode: fPromiscuous=%d\n", pThis->szName, fPromiscuous));
176 NOREF(pThis);
177 /** @todo is it always in promiscuous mode? */
178}
179
180
181/**
182 * Notification on link status changes.
183 *
184 * @param pInterface Pointer to the interface structure containing the called function pointer.
185 * @param enmLinkState The new link state.
186 * @thread EMT
187 */
188static DECLCALLBACK(void) drvTAPOs2NotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
189{
190 PDRVTAPOS2 pThis = PDMINETWORKCONNECTOR_2_DRVTAPOS2(pInterface);
191 bool fLinkDown;
192 switch (enmLinkState)
193 {
194 case PDMNETWORKLINKSTATE_DOWN:
195 case PDMNETWORKLINKSTATE_DOWN_RESUME:
196 fLinkDown = true;
197 break;
198 default:
199 AssertMsgFailed(("enmLinkState=%d\n", enmLinkState));
200 case PDMNETWORKLINKSTATE_UP:
201 fLinkDown = false;
202 break;
203 }
204 LogFlow(("%s: NotifyLinkChanged: enmLinkState=%d %d->%d\n", pThis->szName, pThis->fLinkDown, fLinkDown));
205 ASMAtomicXchgBool(&pThis->fLinkDown, fLinkDown);
206}
207
208
209/**
210 * Receiver thread.
211 *
212 * @returns VBox status code. Returning failure will naturally terminate the thread.
213 * @param pDrvIns The pcnet device instance.
214 * @param pThread The thread.
215 */
216static DECLCALLBACK(int) drvTAPOs2ReceiveThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
217{
218 PDRVTAPOS2 pThis = PDMINS2DATA(pDrvIns, PDRVTAPOS2);
219
220 /*
221 * No initialization work to do, just return immediately.
222 */
223 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
224 return VINF_SUCCESS;
225 Assert(pThread->enmState == PDMTHREADSTATE_RUNNING);
226
227 /*
228 * Loop while the thread is running, quit immediately when
229 * we're supposed to suspend or terminate.
230 */
231 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
232 {
233 /*
234 * Read a frame, this will block for a while if nothing to read.
235 */
236 char abBuf[4096];
237 ULONG Parm[2] = { ~0UL, ~0UL }; /* mysterious output */
238 ULONG cbParm = sizeof(Parm); /* this one is actually ignored... */
239 ULONG cbBuf = sizeof(abBuf);
240
241 int rc = DosDevIOCtl(pThis->hDevice, PROT_CATEGORY, TAP_READ_PACKET,
242 &Parm[0], cbParm, &cbParm,
243 &abBuf[0], cbBuf, &cbBuf);
244 if (pThread->enmState != PDMTHREADSTATE_RUNNING)
245 break;
246 const size_t cbRead = Parm[1];
247 if ( !rc
248 && !Parm[0]
249 && cbRead > 0 /* cbRead */)
250 {
251 AssertMsg(cbRead <= 1536, ("cbRead=%d\n", cbRead));
252
253 /*
254 * Wait for the device to have some room.
255 */
256 rc = pThis->pPort->pfnWaitReceiveAvail(pThis->pPort, RT_INDEFINITE_WAIT);
257 if (RT_FAILURE(rc))
258 break;
259
260 /*
261 * Pass the data up.
262 */
263#ifdef LOG_ENABLED
264 uint64_t u64Now = RTTimeProgramNanoTS();
265 LogFlow(("%s: ReceiveThread: %-4d bytes at %RU64 ns deltas: recv=%RU64 xmit=%RU64\n", pThis->szName,
266 cbRead, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
267 pThis->u64LastReceiveTS = u64Now;
268#endif
269 Log2(("%s: ReceiveThread: cbRead=%#x\n"
270 "%.*Vhxd\n",
271 pThis->szName, cbRead, cbRead, abBuf));
272 STAM_COUNTER_INC(&pThis->StatPktRecv);
273 STAM_COUNTER_ADD(&pThis->StatPktRecvBytes, cbRead);
274 rc = pThis->pPort->pfnReceive(pThis->pPort, abBuf, cbRead);
275 AssertRC(rc);
276 }
277 /* we'll be returning ~1 per second with no data; rc=0 Parm[0] = 1, Parm[1] = 0. */
278 else if (rc)
279 {
280 LogFlow(("%s: ReceiveThread: DoDevIOCtl -> %s Parm={%ld, %ld}\n",
281 pThis->szName, rc, Parm[0], Parm[1]));
282 rc = RTErrConvertFromOS2(rc);
283 if (rc == VERR_INVALID_HANDLE)
284 return rc;
285 RTThreadYield();
286 }
287 }
288
289 /* The thread is being suspended or terminated. */
290 return VINF_SUCCESS;
291}
292
293
294/**
295 * Unblock the send thread so it can respond to a state change.
296 *
297 * @returns VBox status code.
298 * @param pDrvIns The pcnet device instance.
299 * @param pThread The send thread.
300 */
301static DECLCALLBACK(int) drvTAPOs2WakeupReceiveThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
302{
303 PDRVTAPOS2 pThis = PDMINS2DATA(pDrvIns, PDRVTAPOS2);
304 LogFlow(("%s: WakeupReceiveThread\n", pThis->szName));
305
306 /* cancel any pending reads */
307 ULONG Parm[2] = { ~0UL, ~0UL }; /* mysterious output */
308 ULONG cbParm = sizeof(Parm);
309 ULONG Data = pThis->iLan; /* right? */
310 ULONG cbData = sizeof(Data);
311 int orc = DosDevIOCtl(pThis->hDevice, PROT_CATEGORY, TAP_CANCEL_READ,
312 &Parm[0], cbParm, &cbParm,
313 &Data, cbData, &cbData);
314 AssertMsg(orc == 0, ("%d\n", orc)); NOREF(orc);
315
316 return VINF_SUCCESS;
317}
318
319
320/**
321 * Queries an interface to the driver.
322 *
323 * @returns Pointer to interface.
324 * @returns NULL if the interface was not supported by the driver.
325 * @param pInterface Pointer to this interface structure.
326 * @param enmInterface The requested interface identification.
327 * @thread Any thread.
328 */
329static DECLCALLBACK(void *) drvTAPOs2QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
330{
331 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
332 PDRVTAPOS2 pThis = PDMINS2DATA(pDrvIns, PDRVTAPOS2);
333 switch (enmInterface)
334 {
335 case PDMINTERFACE_BASE:
336 return &pDrvIns->IBase;
337 case PDMINTERFACE_NETWORK_CONNECTOR:
338 return &pThis->INetworkConnector;
339 default:
340 return NULL;
341 }
342}
343
344
345/**
346 * Destruct a driver instance.
347 *
348 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
349 * resources can be freed correctly.
350 *
351 * @param pDrvIns The driver instance data.
352 */
353static DECLCALLBACK(void) drvTAPOs2Destruct(PPDMDRVINS pDrvIns)
354{
355 PDRVTAPOS2 pThis = PDMINS2DATA(pDrvIns, PDRVTAPOS2);
356 LogFlow(("%s: Destruct\n", pThis->szName));
357
358 /* PDM will destroy the thread for us, it's suspended right now. */
359
360 /*
361 * Disconnect from the lan if we made a connection and close it.
362 */
363 if (pThis->iConnectedTo != -1)
364 {
365 ULONG Parm[2] = { ~0UL, ~0UL }; /* mysterious output */
366 ULONG cbParm = sizeof(Parm);
367 ULONG Data = pThis->iConnectedTo;
368 ULONG cbData = sizeof(Data);
369 int orc = DosDevIOCtl(pThis->hDevice, PROT_CATEGORY, TAP_DISCONNECT_NIC,
370 &Parm, cbParm, &cbParm,
371 &Data, cbData, &cbData);
372 if ( orc
373 || Parm[0])
374 LogRel(("%s: Failed to disconnect %d from %d! orc=%d Parm={%ld,%ld}\n",
375 pThis->szName, pThis->iLan, pThis->iConnectedTo, orc, Parm[0], Parm[1]));
376 pThis->iConnectedTo = -1;
377 }
378
379 if (pThis->hDevice != NIL_RTFILE)
380 {
381 int rc = RTFileClose(pThis->hDevice);
382 AssertRC(rc);
383 pThis->hDevice = NIL_RTFILE;
384 }
385}
386
387
388/**
389 * Construct a TAP network transport driver instance.
390 *
391 * @returns VBox status.
392 * @param pDrvIns The driver instance data.
393 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
394 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
395 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
396 * iInstance it's expected to be used a bit in this function.
397 */
398static DECLCALLBACK(int) drvTAPOs2Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
399{
400 PDRVTAPOS2 pThis = PDMINS2DATA(pDrvIns, PDRVTAPOS2);
401
402 /*
403 * Init the static parts.
404 */
405 pThis->pDrvIns = pDrvIns;
406 pThis->hDevice = NIL_RTFILE;
407 pThis->iLan = -1;
408 pThis->iConnectedTo = -1;
409 pThis->pThread = NULL;
410 RTStrPrintf(pThis->szName, sizeof(pThis->szName), "TAP%d", pDrvIns->iInstance);
411 /* IBase */
412 pDrvIns->IBase.pfnQueryInterface = drvTAPOs2QueryInterface;
413 /* INetwork */
414 pThis->INetworkConnector.pfnSend = drvTAPOs2Send;
415 pThis->INetworkConnector.pfnSetPromiscuousMode = drvTAPOs2SetPromiscuousMode;
416 pThis->INetworkConnector.pfnNotifyLinkChanged = drvTAPOs2NotifyLinkChanged;
417
418 /*
419 * Validate the config.
420 */
421 if (!CFGMR3AreValuesValid(pCfgHandle, "Device\0ConnectTo\0"))
422 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES, "");
423
424 /*
425 * Check that no-one is attached to us.
426 */
427 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, NULL);
428 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
429 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_NO_ATTACH,
430 N_("Configuration error: Cannot attach drivers to the TAP driver"));
431
432 /*
433 * Query the network port interface.
434 */
435 pThis->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
436 if (!pThis->pPort)
437 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
438 N_("Configuration error: The above device/driver didn't export the network port interface"));
439
440 /*
441 * Read the configuration.
442 */
443 rc = CFGMR3QueryString(pCfgHandle, "Device", &pThis->szDevice[0], sizeof(pThis->szDevice));
444 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
445 strcpy(pThis->szDevice, "\\DEV\\TAP$");
446 else if (VBOX_FAILURE(rc))
447 return PDMDRV_SET_ERROR(pDrvIns, rc,
448 N_("Configuration error: Query for \"Device\" failed"));
449
450 int32_t iConnectTo;
451 rc = CFGMR3QueryS32(pCfgHandle, "ConnectTo", &iConnectTo);
452 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
453 iConnectTo = -1;
454 else if (VBOX_FAILURE(rc))
455 return PDMDRV_SET_ERROR(pDrvIns, rc,
456 N_("Configuration error: Query for \"ConnectTo\" failed"));
457
458 /*
459 * Open the device.
460 * Keep in mind that the destructor is always called!
461 */
462 rc = RTFileOpen(&pThis->hDevice, pThis->szDevice, RTFILE_O_DENY_NONE | RTFILE_O_READ);
463 if (VBOX_FAILURE(rc))
464 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
465 N_("Failed to open tap device '%s'"), pThis->szDevice);
466
467 ULONG Parm[2] = { ~0UL, ~0UL }; /* mysterious output */
468 ULONG cbParm = sizeof(Parm);
469 ULONG Data = ~0UL;
470 ULONG cbData = sizeof(Data);
471 int orc = DosDevIOCtl(pThis->hDevice, PROT_CATEGORY, TAP_GET_LAN_NUMBER,
472 &Parm, cbParm, &cbParm,
473 &Data, cbData, &cbData);
474 if (orc)
475 rc = RTErrConvertFromOS2(orc);
476 else if (Parm[0])
477 rc = VERR_GENERAL_FAILURE;
478 if (VBOX_FAILURE(rc))
479 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
480 N_("Failed to query LanNumber! orc=%d Parm={%ld,%ld}"),
481 orc, Parm[0], Parm[1]);
482 pThis->iLan = (int32_t)Data;
483 Log(("%s: iLan=%d Parm[1]=%ld\n", pThis->szName, pThis->iLan, Parm[1]));
484
485 /*
486 * Connect it requested.
487 */
488 if (iConnectTo != -1)
489 {
490 if (iConnectTo == pThis->iLan)
491 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
492 N_("Cannot connect to ourself (%d)"), iConnectTo);
493
494 Parm[0] = Parm[1] = ~0UL; /* mysterious output */
495 cbParm = sizeof(Parm);
496 Data = iConnectTo;
497 cbData = sizeof(Data);
498 int orc = DosDevIOCtl(pThis->hDevice, PROT_CATEGORY, TAP_CONNECT_NIC,
499 &Parm, cbParm, &cbParm,
500 &Data, cbData, &cbData);
501 if (orc)
502 rc = RTErrConvertFromOS2(orc);
503 else if (Parm[0])
504 rc = VERR_GENERAL_FAILURE;
505 if (VBOX_FAILURE(rc))
506 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
507 N_("Failed to connect %d to %d! orc=%d Parm={%ld,%ld}"),
508 pThis->iLan, iConnectTo, orc, Parm[0], Parm[1]);
509 Log(("%s: Connected to %d\n", pThis->szName, iConnectTo));
510 pThis->iConnectedTo = iConnectTo;
511 }
512
513 /*
514 * Log the config.
515 */
516 Parm[0] = Parm[1] = ~0UL; /* mysterious output */
517 PDMMAC Mac;
518 cbParm = sizeof(Parm);
519 cbData = sizeof(Mac);
520 orc = DosDevIOCtl(pThis->hDevice, PROT_CATEGORY, TAP_READ_MAC_ADDRESS,
521 &Parm[0], cbParm, &cbParm,
522 &Mac, cbData, &cbData);
523 if ( !orc
524 && !Parm[0]
525 /*&& !Parm[1]?*/)
526 LogRel(("%s: iLan=%d iConnectedTo=%d Mac=%02x:%02x:%02x:%02x:%02x:%02x\n",
527 pThis->szName, pThis->iLan, pThis->iConnectedTo,
528 Mac.au8[0], Mac.au8[1], Mac.au8[2], Mac.au8[3], Mac.au8[4], Mac.au8[5]));
529 else
530 LogRel(("%s: iLan=%d iConnectedTo Mac=failed - orc=%d Parm={%ld,%ld}\n",
531 pThis->szName, pThis->iLan, pThis->iConnectedTo, Parm[0], Parm[1]));
532
533 rc = PDMDrvHlpPDMThreadCreate(pDrvIns, &pThis->pThread, pThis, drvTAPOs2ReceiveThread, drvTAPOs2WakeupReceiveThread,
534 0, RTTHREADTYPE_IO, pThis->szName);
535 AssertRCReturn(rc, rc);
536
537#ifdef VBOX_WITH_STATISTICS
538 /*
539 * Statistics.
540 */
541 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of sent packets.", "/Drivers/TAP%d/Packets/Sent", pDrvIns->iInstance);
542 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSentBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Drivers/TAP%d/Bytes/Sent", pDrvIns->iInstance);
543 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of received packets.", "/Drivers/TAP%d/Packets/Received", pDrvIns->iInstance);
544 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecvBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Drivers/TAP%d/Bytes/Received", pDrvIns->iInstance);
545 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Drivers/TAP%d/Transmit", pDrvIns->iInstance);
546 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Drivers/TAP%d/Receive", pDrvIns->iInstance);
547#endif /* VBOX_WITH_STATISTICS */
548
549 return rc;
550}
551
552
553/**
554 * TAP network transport driver registration record.
555 */
556const PDMDRVREG g_DrvHostInterface =
557{
558 /* u32Version */
559 PDM_DRVREG_VERSION,
560 /* szDriverName */
561 "HostInterface",
562 /* pszDescription */
563 "TAP Network Transport Driver",
564 /* fFlags */
565 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
566 /* fClass. */
567 PDM_DRVREG_CLASS_NETWORK,
568 /* cMaxInstances */
569 ~0,
570 /* cbInstance */
571 sizeof(DRVTAPOS2),
572 /* pfnConstruct */
573 drvTAPOs2Construct,
574 /* pfnDestruct */
575 drvTAPOs2Destruct,
576 /* pfnIOCtl */
577 NULL,
578 /* pfnPowerOn */
579 NULL,
580 /* pfnReset */
581 NULL,
582 /* pfnSuspend */
583 NULL,
584 /* pfnResume */
585 NULL,
586 /* pfnDetach */
587 NULL,
588 /* pfnPowerOff */
589 NULL
590};
591
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette