VirtualBox

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

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

A couple of fixes.

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