~ubuntu-branches/ubuntu/gutsy/virtualbox-ose/gutsy

« back to all changes in this revision

Viewing changes to src/VBox/Devices/Network/DrvTAPOs2.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-09-08 16:44:58 UTC
  • Revision ID: james.westby@ubuntu.com-20070908164458-wao29470vqtr8ksy
Tags: upstream-1.5.0-dfsg2
ImportĀ upstreamĀ versionĀ 1.5.0-dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** $Id: DrvTAPOs2.cpp 4372 2007-08-24 21:21:51Z 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 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
*   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/asm.h>
 
30
#include <iprt/semaphore.h>
 
31
 
 
32
#include "Builtins.h"
 
33
 
 
34
 
 
35
 
 
36
/*******************************************************************************
 
37
*   Structures and Typedefs                                                    *
 
38
*******************************************************************************/
 
39
 
 
40
/**
 
41
 * Block driver instance data.
 
42
 */
 
43
typedef struct DRVTAPOS2
 
44
{
 
45
    /** The network interface. */
 
46
    PDMINETWORKCONNECTOR    INetworkConnector;
 
47
    /** The network interface. */
 
48
    PPDMINETWORKPORT        pPort;
 
49
    /** Pointer to the driver instance. */
 
50
    PPDMDRVINS              pDrvIns;
 
51
    /** TAP device file handle. */
 
52
    RTFILE                  FileDevice;
 
53
    /** Receiver thread. */
 
54
    PPDMTHREAD              pThread;
 
55
    /** We are waiting for more receive buffers. */
 
56
    uint32_t volatile       fOutOfSpace;
 
57
    /** Event semaphore for blocking on receive. */
 
58
    RTSEMEVENT              EventOutOfSpace;
 
59
 
 
60
#ifdef VBOX_WITH_STATISTICS
 
61
    /** Number of sent packets. */
 
62
    STAMCOUNTER             StatPktSent;
 
63
    /** Number of sent bytes. */
 
64
    STAMCOUNTER             StatPktSentBytes;
 
65
    /** Number of received packets. */
 
66
    STAMCOUNTER             StatPktRecv;
 
67
    /** Number of received bytes. */
 
68
    STAMCOUNTER             StatPktRecvBytes;
 
69
    /** Profiling packet transmit runs. */
 
70
    STAMPROFILE             StatTransmit;
 
71
    /** Profiling packet receive runs. */
 
72
    STAMPROFILEADV          StatReceive;
 
73
    STAMPROFILE             StatRecvOverflows;
 
74
#endif /* VBOX_WITH_STATISTICS */
 
75
 
 
76
#ifdef LOG_ENABLED
 
77
    /** The nano ts of the last transfer. */
 
78
    uint64_t                u64LastTransferTS;
 
79
    /** The nano ts of the last receive. */
 
80
    uint64_t                u64LastReceiveTS;
 
81
#endif
 
82
} DRVTAPOS2, *PDRVTAPOS2;
 
83
 
 
84
 
 
85
/** Converts a pointer to TAP::INetworkConnector to a PRDVTAP. */
 
86
#define PDMINETWORKCONNECTOR_2_DRVTAPOS2(pInterface) ( (PDRVTAPOS2)((uintptr_t)pInterface - RT_OFFSETOF(DRVTAPOS2, INetworkConnector)) )
 
87
 
 
88
 
 
89
/**
 
90
 * Send data to the network.
 
91
 *
 
92
 * @returns VBox status code.
 
93
 * @param   pInterface      Pointer to the interface structure containing the called function pointer.
 
94
 * @param   pvBuf           Data to send.
 
95
 * @param   cb              Number of bytes to send.
 
96
 * @thread  EMT
 
97
 */
 
98
static DECLCALLBACK(int) drvTAPOs2Send(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
 
99
{
 
100
    PDRVTAPOS2 pData = PDMINETWORKCONNECTOR_2_DRVTAPOS2(pInterface);
 
101
    STAM_COUNTER_INC(&pData->StatPktSent);
 
102
    STAM_COUNTER_ADD(&pData->StatPktSentBytes, cb);
 
103
    STAM_PROFILE_START(&pData->StatTransmit, a);
 
104
 
 
105
#ifdef LOG_ENABLED
 
106
    uint64_t u64Now = RTTimeProgramNanoTS();
 
107
    LogFlow(("drvTAPOs2Send: %-4d bytes at %llu ns  deltas: r=%llu t=%llu\n",
 
108
             cb, u64Now, u64Now - pData->u64LastReceiveTS, u64Now - pData->u64LastTransferTS));
 
109
    pData->u64LastTransferTS = u64Now;
 
110
#endif
 
111
    Log2(("drvTAPOs2Send: pvBuf=%p cb=%#x\n"
 
112
          "%.*Vhxd\n",
 
113
          pvBuf, cb, cb, pvBuf));
 
114
 
 
115
    ULONG UnusedParms[10] = { 0,0,0,0, 0,0,0,0, 0,0 };
 
116
    ULONG cbParms = sizeof(UnusedParms);
 
117
    ULONG cbData = cb;
 
118
    int rc = DosDevIOCtl(pData->FileDevice, PROT_CATEGORY, TAP_WRITE_PACKET,
 
119
                         &UnusedParms[0], cbParms, &cbParms,
 
120
                         pvBuf, cbData, &cbData);
 
121
    if (rc)
 
122
        rc = RTErrConvertFromOS2(rc);
 
123
 
 
124
    STAM_PROFILE_STOP(&pData->StatTransmit, a);
 
125
    AssertRC(rc);
 
126
    return rc;
 
127
}
 
128
 
 
129
 
 
130
/**
 
131
 * Set promiscuous mode.
 
132
 *
 
133
 * This is called when the promiscuous mode is set. This means that there doesn't have
 
134
 * to be a mode change when it's called.
 
135
 *
 
136
 * @param   pInterface      Pointer to the interface structure containing the called function pointer.
 
137
 * @param   fPromiscuous    Set if the adaptor is now in promiscuous mode. Clear if it is not.
 
138
 * @thread  EMT
 
139
 */
 
140
static DECLCALLBACK(void) drvTAPOs2SetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
 
141
{
 
142
    LogFlow(("drvTAPOs2SetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
 
143
    /* nothing to do */
 
144
}
 
145
 
 
146
 
 
147
/**
 
148
 * Notification on link status changes.
 
149
 *
 
150
 * @param   pInterface      Pointer to the interface structure containing the called function pointer.
 
151
 * @param   enmLinkState    The new link state.
 
152
 * @thread  EMT
 
153
 */
 
154
static DECLCALLBACK(void) drvTAPOs2NotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
 
155
{
 
156
    LogFlow(("drvNATNotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
 
157
    /** @todo take action on link down and up. Stop the polling and such like. */
 
158
}
 
159
 
 
160
 
 
161
/**
 
162
 * More receive buffer has become available.
 
163
 *
 
164
 * This is called when the NIC frees up receive buffers.
 
165
 *
 
166
 * @param   pInterface      Pointer to the interface structure containing the called function pointer.
 
167
 * @thread  EMT
 
168
 */
 
169
static DECLCALLBACK(void) drvTAPOs2NotifyCanReceive(PPDMINETWORKCONNECTOR pInterface)
 
170
{
 
171
    PDRVTAPOS2 pData = PDMINETWORKCONNECTOR_2_DRVTAPOS2(pInterface);
 
172
 
 
173
    LogFlow(("drvTAPOs2NotifyCanReceive:\n"));
 
174
    /* ensure we wake up only once */
 
175
    if (ASMAtomicXchgU32(&pData->fOutOfSpace, false))
 
176
        RTSemEventSignal(pData->EventOutOfSpace);
 
177
}
 
178
 
 
179
 
 
180
/**
 
181
 * Asynchronous I/O thread for handling receive.
 
182
 *
 
183
 * @returns VINF_SUCCESS (ignored).
 
184
 * @param   pDrvIns         The driver instance.
 
185
 * @param   pThread         The PDM thread structure.
 
186
 */
 
187
static DECLCALLBACK(int) drvTAPOs2AsyncIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
 
188
{
 
189
    PDRVTAPOS2 pData = PDMINS2DATA(pDrvIns, PDRVTAPOS2);
 
190
    LogFlow(("drvTAPOs2AsyncIoThread: pData=%p\n", pData));
 
191
    Assert(pThread->enmState == PDMTHREADSTATE_INITIALIZING);
 
192
    
 
193
 
 
194
    /*
 
195
     * Outer loop.
 
196
     */
 
197
    for (;;)
 
198
    {
 
199
        /*
 
200
         *
 
201
         */
 
202
        PDMR3ThreadSuspend(pThread);
 
203
        if (pThread->enmState != PDMTHREADSTATE_RESUMING)
 
204
            break;
 
205
 
 
206
        {
 
207
        }
 
208
    }
 
209
 
 
210
 
 
211
 
 
212
 
 
213
    STAM_PROFILE_ADV_START(&pData->StatReceive, a);
 
214
 
 
215
    /*
 
216
     * Polling loop.
 
217
     */
 
218
    for (;;)
 
219
    {
 
220
        /*
 
221
         * Read/wait the frame.
 
222
         */
 
223
        char    achBuf[4096];
 
224
        ULONG   cbParm = ;
 
225
        ULONG   cbRead = 0;
 
226
        int     LanNumber;
 
227
 
 
228
        int rc = DosDevIOCtl(pData->FileDevice, PROT_CATEGORY, TAP_CANCEL_READ,
 
229
                             &UnusedParms[0], cbParm, &cbParm,
 
230
                             &achBuf[0], cbRead, &cbRead);
 
231
        if (rc == NO_ERROR)
 
232
        {
 
233
            AssertMsg(cbRead <= 1536, ("cbRead=%d\n", cbRead));
 
234
 
 
235
            /*
 
236
             * Wait for the device to have space for this frame.
 
237
             */
 
238
            size_t cbMax = pData->pPort->pfnCanReceive(pData->pPort);
 
239
            if (cbMax < cbRead)
 
240
            {
 
241
                /** @todo receive overflow handling needs serious improving! */
 
242
                STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
 
243
                STAM_PROFILE_START(&pData->StatRecvOverflows, b);
 
244
                while (   cbMax < cbRead
 
245
                       && pData->enmState != ASYNCSTATE_TERMINATE)
 
246
                {
 
247
                    LogFlow(("drvTAPOs2AsyncIoThread: cbMax=%d cbRead=%d waiting...\n", cbMax, cbRead));
 
248
#if 1
 
249
                    /* We get signalled by the network driver. 50ms is just for sanity */
 
250
                    ASMAtomicXchgU32(&pData->fOutOfSpace, true);
 
251
                    RTSemEventWait(pData->EventOutOfSpace, 50);
 
252
#else
 
253
                    RTThreadSleep(1);
 
254
#endif
 
255
                    cbMax = pData->pPort->pfnCanReceive(pData->pPort);
 
256
                }
 
257
                ASMAtomicXchgU32(&pData->fOutOfSpace, false);
 
258
                STAM_PROFILE_STOP(&pData->StatRecvOverflows, b);
 
259
                STAM_PROFILE_ADV_START(&pData->StatReceive, a);
 
260
                if (pData->enmState == ASYNCSTATE_TERMINATE)
 
261
                    break;
 
262
            }
 
263
 
 
264
            /*
 
265
             * Pass the data up.
 
266
             */
 
267
#ifdef LOG_ENABLED
 
268
            uint64_t u64Now = RTTimeProgramNanoTS();
 
269
            LogFlow(("drvTAPOs2AsyncIoThread: %-4d bytes at %llu ns  deltas: r=%llu t=%llu\n",
 
270
                     cbRead, u64Now, u64Now - pData->u64LastReceiveTS, u64Now - pData->u64LastTransferTS));
 
271
            pData->u64LastReceiveTS = u64Now;
 
272
#endif
 
273
            Log2(("drvTAPOs2AsyncIoThread: cbRead=%#x\n"
 
274
                  "%.*Vhxd\n",
 
275
                  cbRead, cbRead, achBuf));
 
276
            STAM_COUNTER_INC(&pData->StatPktRecv);
 
277
            STAM_COUNTER_ADD(&pData->StatPktRecvBytes, cbRead);
 
278
            rc = pData->pPort->pfnReceive(pData->pPort, achBuf, cbRead);
 
279
            AssertRC(rc);
 
280
        }
 
281
        else
 
282
        {
 
283
            LogFlow(("drvTAPOs2AsyncIoThread: DoDevIOCtl -> %Vrc\n", rc));
 
284
            if (rc == VERR_INVALID_HANDLE)
 
285
                break;
 
286
            RTThreadYield();
 
287
        }
 
288
    }
 
289
 
 
290
    LogFlow(("drvTAPOs2AsyncIoThread: returns %Vrc\n", VINF_SUCCESS));
 
291
    STAM_PROFILE_ADV_STOP(&pData->StatReceive, a);
 
292
    return VINF_SUCCESS;
 
293
}
 
294
 
 
295
 
 
296
/**
 
297
 * Queries an interface to the driver.
 
298
 *
 
299
 * @returns Pointer to interface.
 
300
 * @returns NULL if the interface was not supported by the driver.
 
301
 * @param   pInterface          Pointer to this interface structure.
 
302
 * @param   enmInterface        The requested interface identification.
 
303
 * @thread  Any thread.
 
304
 */
 
305
static DECLCALLBACK(void *) drvTAPOs2QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
 
306
{
 
307
    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
 
308
    PDRVTAPOS2 pData = PDMINS2DATA(pDrvIns, PDRVTAPOS2);
 
309
    switch (enmInterface)
 
310
    {
 
311
        case PDMINTERFACE_BASE:
 
312
            return &pDrvIns->IBase;
 
313
        case PDMINTERFACE_NETWORK_CONNECTOR:
 
314
            return &pData->INetworkConnector;
 
315
        default:
 
316
            return NULL;
 
317
    }
 
318
}
 
319
 
 
320
 
 
321
/**
 
322
 * Destruct a driver instance.
 
323
 *
 
324
 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
 
325
 * resources can be freed correctly.
 
326
 *
 
327
 * @param   pDrvIns     The driver instance data.
 
328
 */
 
329
static DECLCALLBACK(void) drvTAPOs2Destruct(PPDMDRVINS pDrvIns)
 
330
{
 
331
    LogFlow(("drvTAPOs2Destruct\n"));
 
332
    PDRVTAPOS2 pData = PDMINS2DATA(pDrvIns, PDRVTAPOS2);
 
333
 
 
334
    /*
 
335
     * Destroy the event semaphore.
 
336
     */
 
337
    if (pData->EventOutOfSpace != NIL_RTSEMEVENTMULTI)
 
338
    {
 
339
        rc = RTSemEventDestroy(pData->EventOutOfSpace);
 
340
        AssertRC(rc);
 
341
        pData->EventOutOfSpace = NIL_RTSEMEVENTMULTI;
 
342
    }
 
343
}
 
344
 
 
345
 
 
346
/**
 
347
 * Construct a TAP network transport driver instance.
 
348
 *
 
349
 * @returns VBox status.
 
350
 * @param   pDrvIns     The driver instance data.
 
351
 *                      If the registration structure is needed, pDrvIns->pDrvReg points to it.
 
352
 * @param   pCfgHandle  Configuration node handle for the driver. Use this to obtain the configuration
 
353
 *                      of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
 
354
 *                      iInstance it's expected to be used a bit in this function.
 
355
 */
 
356
static DECLCALLBACK(int) drvTAPOs2Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
 
357
{
 
358
    PDRVTAPOS2 pData = PDMINS2DATA(pDrvIns, PDRVTAPOS2);
 
359
 
 
360
    /*
 
361
     * Init the static parts.
 
362
     */
 
363
    pData->pDrvIns                      = pDrvIns;
 
364
    pData->FileDevice                   = NIL_RTFILE;
 
365
    pData->Thread                       = NIL_RTTHREAD;
 
366
    pData->enmState                     = ASYNCSTATE_RUNNING;
 
367
    /* IBase */
 
368
    pDrvIns->IBase.pfnQueryInterface    = drvTAPOs2QueryInterface;
 
369
    /* INetwork */
 
370
    pData->INetworkConnector.pfnSend                = drvTAPOs2Send;
 
371
    pData->INetworkConnector.pfnSetPromiscuousMode  = drvTAPOs2SetPromiscuousMode;
 
372
    pData->INetworkConnector.pfnNotifyLinkChanged   = drvTAPOs2NotifyLinkChanged;
 
373
    pData->INetworkConnector.pfnNotifyCanReceive    = drvTAPOs2NotifyCanReceive;
 
374
 
 
375
    /*
 
376
     * Validate the config.
 
377
     */
 
378
    if (!CFGMR3AreValuesValid(pCfgHandle, "Device\0InitProg\0TermProg\0FileHandle\0"))
 
379
        return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES, "");
 
380
 
 
381
    /*
 
382
     * Check that no-one is attached to us.
 
383
     */
 
384
    int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, NULL);
 
385
    if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
 
386
        return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_NO_ATTACH,
 
387
                                N_("Configuration error: Cannot attach drivers to the TAP driver!"));
 
388
 
 
389
    /*
 
390
     * Query the network port interface.
 
391
     */
 
392
    pData->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
 
393
    if (!pData->pPort)
 
394
        return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
 
395
                                N_("Configuration error: The above device/driver didn't export the network port interface!"));
 
396
 
 
397
    /*
 
398
     * Read the configuration.
 
399
     */
 
400
    int32_t iFile;
 
401
    rc = CFGMR3QueryS32(pCfgHandle, "FileHandle", &iFile);
 
402
    if (VBOX_FAILURE(rc))
 
403
        return PDMDRV_SET_ERROR(pDrvIns, rc,
 
404
                                N_("Configuration error: Query for \"FileHandle\" 32-bit signed integer failed!"));
 
405
    pData->FileDevice = (RTFILE)iFile;
 
406
    if (!RTFileIsValid(pData->FileDevice))
 
407
        return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_HANDLE, RT_SRC_POS,
 
408
                                   N_("The TAP file handle %RTfile is not valid!"), pData->FileDevice);
 
409
 
 
410
    /*
 
411
     * Make sure the descriptor is non-blocking and valid.
 
412
     *
 
413
     * We should actually query if it's a TAP device, but I haven't
 
414
     * found any way to do that.
 
415
     */
 
416
    if (fcntl(pData->FileDevice, F_SETFL, O_NONBLOCK) == -1)
 
417
        return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
 
418
                                   N_("Configuration error: Failed to configure /dev/net/tun. errno=%d"), errno);
 
419
    Log(("drvTAPOs2Contruct: %d (from fd)\n", pData->FileDevice));
 
420
    rc = VINF_SUCCESS;
 
421
 
 
422
    /*
 
423
     * Create the out-of-space semaphore and the async receiver thread. 
 
424
     */
 
425
    rc = RTSemEventCreate(&pData->EventOutOfSpace);
 
426
    AssertRCReturn(rc, rc);
 
427
 
 
428
    rc = PDMDrvHlpThreadCreate(pDrvIns, &pData->pThread, pData, drvTAPOs2AsyncIoThread, drvTAPOs2WakeupThread,
 
429
                               0, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "TAP");
 
430
    AssertRCReturn(rc, rc);
 
431
 
 
432
#ifdef VBOX_WITH_STATISTICS
 
433
    /*
 
434
     * Statistics.
 
435
     */
 
436
    PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktSent,       STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,        "Number of sent packets.",          "/Drivers/TAP%d/Packets/Sent", pDrvIns->iInstance);
 
437
    PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktSentBytes,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,             "Number of sent bytes.",            "/Drivers/TAP%d/Bytes/Sent", pDrvIns->iInstance);
 
438
    PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktRecv,       STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES,        "Number of received packets.",      "/Drivers/TAP%d/Packets/Received", pDrvIns->iInstance);
 
439
    PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPktRecvBytes,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,             "Number of received bytes.",        "/Drivers/TAP%d/Bytes/Received", pDrvIns->iInstance);
 
440
    PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatTransmit,      STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,    "Profiling packet transmit runs.",  "/Drivers/TAP%d/Transmit", pDrvIns->iInstance);
 
441
    PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatReceive,       STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,    "Profiling packet receive runs.",   "/Drivers/TAP%d/Receive", pDrvIns->iInstance);
 
442
    PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatRecvOverflows, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling packet receive overflows.", "/Drivers/TAP%d/RecvOverflows", pDrvIns->iInstance);
 
443
#endif /* VBOX_WITH_STATISTICS */
 
444
 
 
445
    return rc;
 
446
}
 
447
 
 
448
 
 
449
/**
 
450
 * TAP network transport driver registration record.
 
451
 */
 
452
const PDMDRVREG g_DrvHostInterface =
 
453
{
 
454
    /* u32Version */
 
455
    PDM_DRVREG_VERSION,
 
456
    /* szDriverName */
 
457
    "HostInterface",
 
458
    /* pszDescription */
 
459
    "TAP Network Transport Driver",
 
460
    /* fFlags */
 
461
    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
 
462
    /* fClass. */
 
463
    PDM_DRVREG_CLASS_NETWORK,
 
464
    /* cMaxInstances */
 
465
    ~0,
 
466
    /* cbInstance */
 
467
    sizeof(DRVTAPOS2),
 
468
    /* pfnConstruct */
 
469
    drvTAPOs2Construct,
 
470
    /* pfnDestruct */
 
471
    drvTAPOs2Destruct,
 
472
    /* pfnIOCtl */
 
473
    NULL,
 
474
    /* pfnPowerOn */
 
475
    NULL,
 
476
    /* pfnReset */
 
477
    NULL,
 
478
    /* pfnSuspend */
 
479
    NULL,
 
480
    /* pfnResume */
 
481
    NULL,
 
482
    /* pfnDetach */
 
483
    NULL,
 
484
    /* pfnPowerOff */
 
485
    NULL
 
486
};