VirtualBox

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

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

no "\n", ".", nor "!" at end of an error message

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