VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvTAP.cpp@ 28258

Last change on this file since 28258 was 28258, checked in by vboxsync, 15 years ago

PDM critsects for drivers. Fixed critsect cleanup in failure path. Started on new transmit locking scheme (required for intnet buffer serialization).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.9 KB
Line 
1/* $Id: DrvTAP.cpp 28258 2010-04-13 14:51:16Z vboxsync $ */
2/** @file
3 * DrvTAP - Universial TAP network transport driver.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_DRV_TUN
26#include <VBox/log.h>
27#include <VBox/pdmdrv.h>
28#include <VBox/pdmnetifs.h>
29#include <VBox/pdmnetinline.h>
30
31#include <iprt/asm.h>
32#include <iprt/assert.h>
33#include <iprt/ctype.h>
34#include <iprt/file.h>
35#include <iprt/mem.h>
36#include <iprt/path.h>
37#include <iprt/semaphore.h>
38#include <iprt/string.h>
39#include <iprt/thread.h>
40#include <iprt/uuid.h>
41#ifdef RT_OS_SOLARIS
42# include <iprt/process.h>
43# include <iprt/env.h>
44# ifdef VBOX_WITH_CROSSBOW
45# include <iprt/mem.h>
46# endif
47#endif
48
49#include <sys/ioctl.h>
50#include <sys/poll.h>
51#ifdef RT_OS_SOLARIS
52# include <sys/stat.h>
53# include <sys/ethernet.h>
54# include <sys/sockio.h>
55# include <netinet/in.h>
56# include <netinet/in_systm.h>
57# include <netinet/ip.h>
58# include <netinet/ip_icmp.h>
59# include <netinet/udp.h>
60# include <netinet/tcp.h>
61# include <net/if.h>
62# include <stropts.h>
63# include <fcntl.h>
64# include <stdlib.h>
65# include <stdio.h>
66# ifdef VBOX_WITH_CROSSBOW
67# include "solaris/vbox-libdlpi.h"
68# endif
69#else
70# include <sys/fcntl.h>
71#endif
72#include <errno.h>
73#include <unistd.h>
74
75#ifdef RT_OS_L4
76# include <l4/vboxserver/file.h>
77#endif
78
79#include "Builtins.h"
80
81
82/*******************************************************************************
83* Structures and Typedefs *
84*******************************************************************************/
85/**
86 * TAP driver instance data.
87 *
88 * @implements PDMINETWORKUP
89 */
90typedef struct DRVTAP
91{
92 /** The network interface. */
93 PDMINETWORKUP INetworkUp;
94 /** The network interface. */
95 PPDMINETWORKDOWN pIAboveNet;
96 /** Pointer to the driver instance. */
97 PPDMDRVINS pDrvIns;
98 /** TAP device file handle. */
99 RTFILE FileDevice;
100 /** The configured TAP device name. */
101 char *pszDeviceName;
102#ifdef RT_OS_SOLARIS
103# ifdef VBOX_WITH_CROSSBOW
104 /** Crossbow: MAC address of the device. */
105 RTMAC MacAddress;
106 /** Crossbow: Handle of the NIC. */
107 dlpi_handle_t pDeviceHandle;
108# else
109 /** IP device file handle (/dev/udp). */
110 RTFILE IPFileDevice;
111# endif
112 /** Whether device name is obtained from setup application. */
113 bool fStatic;
114#endif
115 /** TAP setup application. */
116 char *pszSetupApplication;
117 /** TAP terminate application. */
118 char *pszTerminateApplication;
119 /** The write end of the control pipe. */
120 RTFILE PipeWrite;
121 /** The read end of the control pipe. */
122 RTFILE PipeRead;
123 /** Reader thread. */
124 PPDMTHREAD pThread;
125
126#ifdef VBOX_WITH_STATISTICS
127 /** Number of sent packets. */
128 STAMCOUNTER StatPktSent;
129 /** Number of sent bytes. */
130 STAMCOUNTER StatPktSentBytes;
131 /** Number of received packets. */
132 STAMCOUNTER StatPktRecv;
133 /** Number of received bytes. */
134 STAMCOUNTER StatPktRecvBytes;
135 /** Profiling packet transmit runs. */
136 STAMPROFILE StatTransmit;
137 /** Profiling packet receive runs. */
138 STAMPROFILEADV StatReceive;
139#endif /* VBOX_WITH_STATISTICS */
140
141#ifdef LOG_ENABLED
142 /** The nano ts of the last transfer. */
143 uint64_t u64LastTransferTS;
144 /** The nano ts of the last receive. */
145 uint64_t u64LastReceiveTS;
146#endif
147} DRVTAP, *PDRVTAP;
148
149
150/** Converts a pointer to TAP::INetworkUp to a PRDVTAP. */
151#define PDMINETWORKUP_2_DRVTAP(pInterface) ( (PDRVTAP)((uintptr_t)pInterface - RT_OFFSETOF(DRVTAP, INetworkUp)) )
152
153
154/*******************************************************************************
155* Internal Functions *
156*******************************************************************************/
157#ifdef RT_OS_SOLARIS
158# ifdef VBOX_WITH_CROSSBOW
159static int SolarisOpenVNIC(PDRVTAP pThis);
160static int SolarisDLPIErr2VBoxErr(int rc);
161# else
162static int SolarisTAPAttach(PDRVTAP pThis);
163# endif
164#endif
165
166
167/**
168 * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
169 */
170static DECLCALLBACK(int) drvTAPNetworkUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
171 PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf)
172{
173 PDRVTAP pThis = PDMINETWORKUP_2_DRVTAP(pInterface);
174
175 /*
176 * Allocate a scatter / gather buffer descriptor that is immediately
177 * followed by the buffer space of its single segment. The GSO context
178 * comes after that again.
179 */
180 PPDMSCATTERGATHER pSgBuf = (PPDMSCATTERGATHER)RTMemAlloc( RT_ALIGN_Z(sizeof(*pSgBuf), 16)
181 + RT_ALIGN_Z(cbMin, 16)
182 + (pGso ? RT_ALIGN_Z(sizeof(*pGso), 16) : 0));
183 if (!pSgBuf)
184 return VERR_NO_MEMORY;
185
186 /*
187 * Initialize the S/G buffer and return.
188 */
189 pSgBuf->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
190 pSgBuf->cbUsed = 0;
191 pSgBuf->cbAvailable = RT_ALIGN_Z(cbMin, 16);
192 pSgBuf->pvAllocator = NULL;
193 if (!pGso)
194 pSgBuf->pvUser = NULL;
195 else
196 {
197 pSgBuf->pvUser = (uint8_t *)(pSgBuf + 1) + pSgBuf->cbAvailable;
198 *(PPDMNETWORKGSO)pSgBuf->pvUser = *pGso;
199 }
200 pSgBuf->cSegs = 1;
201 pSgBuf->aSegs[0].cbSeg = pSgBuf->cbAvailable;
202 pSgBuf->aSegs[0].pvSeg = pSgBuf + 1;
203
204#if 0 /* poison */
205 memset(pSgBuf->aSegs[0].pvSeg, 'F', pSgBuf->aSegs[0].cbSeg);
206#endif
207 *ppSgBuf = pSgBuf;
208 return VINF_SUCCESS;
209}
210
211
212/**
213 * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
214 */
215static DECLCALLBACK(int) drvTAPNetworkUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
216{
217 PDRVTAP pThis = PDMINETWORKUP_2_DRVTAP(pInterface);
218 if (pSgBuf)
219 {
220 Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
221 pSgBuf->fFlags = 0;
222 RTMemFree(pSgBuf);
223 }
224 return VINF_SUCCESS;
225}
226
227
228/**
229 * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
230 */
231static DECLCALLBACK(int) drvTAPNetworkUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
232{
233 PDRVTAP pThis = PDMINETWORKUP_2_DRVTAP(pInterface);
234 STAM_COUNTER_INC(&pThis->StatPktSent);
235 STAM_COUNTER_ADD(&pThis->StatPktSentBytes, pSgBuf->cbUsed);
236 STAM_PROFILE_START(&pThis->StatTransmit, a);
237
238 AssertPtr(pSgBuf);
239 Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
240
241 int rc;
242 if (!pSgBuf->pvUser)
243 {
244#ifdef LOG_ENABLED
245 uint64_t u64Now = RTTimeProgramNanoTS();
246 LogFlow(("drvTAPSend: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
247 pSgBuf->cbUsed, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
248 pThis->u64LastTransferTS = u64Now;
249#endif
250 Log2(("drvTAPSend: pSgBuf->aSegs[0].pvSeg=%p pSgBuf->cbUsed=%#x\n"
251 "%.*Rhxd\n",
252 pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, pSgBuf->cbUsed, pSgBuf->aSegs[0].pvSeg));
253
254 rc = RTFileWrite(pThis->FileDevice, pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, NULL);
255 }
256 else
257 {
258 uint8_t abHdrScratch[256];
259 uint8_t const *pbFrame = (uint8_t const *)pSgBuf->aSegs[0].pvSeg;
260 PCPDMNETWORKGSO pGso = (PCPDMNETWORKGSO)pSgBuf->pvUser;
261 uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, pSgBuf->cbUsed); Assert(cSegs > 1);
262 for (size_t iSeg = 0; iSeg < cSegs; iSeg++)
263 {
264 uint32_t cbSegFrame;
265 void *pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)pbFrame, pSgBuf->cbUsed, abHdrScratch,
266 iSeg, cSegs, &cbSegFrame);
267 rc = RTFileWrite(pThis->FileDevice, pvSegFrame, cbSegFrame, NULL);
268 if (RT_FAILURE(rc))
269 break;
270 }
271 }
272
273 pSgBuf->fFlags = 0;
274 RTMemFree(pSgBuf);
275
276 STAM_PROFILE_STOP(&pThis->StatTransmit, a);
277 AssertRC(rc);
278 if (RT_FAILURE(rc))
279 rc = rc == VERR_NO_MEMORY ? VERR_NET_NO_BUFFER_SPACE : VERR_NET_DOWN;
280 return rc;
281}
282
283
284/**
285 * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
286 */
287static DECLCALLBACK(void) drvTAPNetworkUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
288{
289 LogFlow(("drvTAPNetworkUp_SetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
290 /* nothing to do */
291}
292
293
294/**
295 * Notification on link status changes.
296 *
297 * @param pInterface Pointer to the interface structure containing the called function pointer.
298 * @param enmLinkState The new link state.
299 * @thread EMT
300 */
301static DECLCALLBACK(void) drvTAPNetworkUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
302{
303 LogFlow(("drvTAPNetworkUp_NotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
304 /** @todo take action on link down and up. Stop the polling and such like. */
305}
306
307
308/**
309 * Asynchronous I/O thread for handling receive.
310 *
311 * @returns VINF_SUCCESS (ignored).
312 * @param Thread Thread handle.
313 * @param pvUser Pointer to a DRVTAP structure.
314 */
315static DECLCALLBACK(int) drvTAPAsyncIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
316{
317 PDRVTAP pThis = PDMINS_2_DATA(pDrvIns, PDRVTAP);
318 LogFlow(("drvTAPAsyncIoThread: pThis=%p\n", pThis));
319
320 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
321 return VINF_SUCCESS;
322
323 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
324
325 /*
326 * Polling loop.
327 */
328 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
329 {
330 /*
331 * Wait for something to become available.
332 */
333 struct pollfd aFDs[2];
334 aFDs[0].fd = pThis->FileDevice;
335 aFDs[0].events = POLLIN | POLLPRI;
336 aFDs[0].revents = 0;
337 aFDs[1].fd = pThis->PipeRead;
338 aFDs[1].events = POLLIN | POLLPRI | POLLERR | POLLHUP;
339 aFDs[1].revents = 0;
340 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
341 errno=0;
342 int rc = poll(&aFDs[0], RT_ELEMENTS(aFDs), -1 /* infinite */);
343
344 /* this might have changed in the meantime */
345 if (pThread->enmState != PDMTHREADSTATE_RUNNING)
346 break;
347
348 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
349 if ( rc > 0
350 && (aFDs[0].revents & (POLLIN | POLLPRI))
351 && !aFDs[1].revents)
352 {
353 /*
354 * Read the frame.
355 */
356 char achBuf[16384];
357 size_t cbRead = 0;
358#ifdef VBOX_WITH_CROSSBOW
359 cbRead = sizeof(achBuf);
360 rc = g_pfnLibDlpiRecv(pThis->pDeviceHandle, NULL, NULL, achBuf, &cbRead, -1, NULL);
361 rc = RT_LIKELY(rc == DLPI_SUCCESS) ? VINF_SUCCESS : SolarisDLPIErr2VBoxErr(rc);
362#else
363 /** @note At least on Linux we will never receive more than one network packet
364 * after poll() returned successfully. I don't know why but a second
365 * RTFileRead() operation will return with VERR_TRY_AGAIN in any case. */
366 rc = RTFileRead(pThis->FileDevice, achBuf, sizeof(achBuf), &cbRead);
367#endif
368 if (RT_SUCCESS(rc))
369 {
370 /*
371 * Wait for the device to have space for this frame.
372 * Most guests use frame-sized receive buffers, hence non-zero cbMax
373 * automatically means there is enough room for entire frame. Some
374 * guests (eg. Solaris) use large chains of small receive buffers
375 * (each 128 or so bytes large). We will still start receiving as soon
376 * as cbMax is non-zero because:
377 * - it would be quite expensive for pfnCanReceive to accurately
378 * determine free receive buffer space
379 * - if we were waiting for enough free buffers, there is a risk
380 * of deadlocking because the guest could be waiting for a receive
381 * overflow error to allocate more receive buffers
382 */
383 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
384 int rc1 = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, RT_INDEFINITE_WAIT);
385 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
386
387 /*
388 * A return code != VINF_SUCCESS means that we were woken up during a VM
389 * state transistion. Drop the packet and wait for the next one.
390 */
391 if (RT_FAILURE(rc1))
392 continue;
393
394 /*
395 * Pass the data up.
396 */
397#ifdef LOG_ENABLED
398 uint64_t u64Now = RTTimeProgramNanoTS();
399 LogFlow(("drvTAPAsyncIoThread: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
400 cbRead, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
401 pThis->u64LastReceiveTS = u64Now;
402#endif
403 Log2(("drvTAPAsyncIoThread: cbRead=%#x\n" "%.*Rhxd\n", cbRead, cbRead, achBuf));
404 STAM_COUNTER_INC(&pThis->StatPktRecv);
405 STAM_COUNTER_ADD(&pThis->StatPktRecvBytes, cbRead);
406 rc1 = pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, achBuf, cbRead);
407 AssertRC(rc1);
408 }
409 else
410 {
411 LogFlow(("drvTAPAsyncIoThread: RTFileRead -> %Rrc\n", rc));
412 if (rc == VERR_INVALID_HANDLE)
413 break;
414 RTThreadYield();
415 }
416 }
417 else if ( rc > 0
418 && aFDs[1].revents)
419 {
420 LogFlow(("drvTAPAsyncIoThread: Control message: enmState=%d revents=%#x\n", pThread->enmState, aFDs[1].revents));
421 if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL))
422 break;
423
424 /* drain the pipe */
425 char ch;
426 size_t cbRead;
427 RTFileRead(pThis->PipeRead, &ch, 1, &cbRead);
428 }
429 else
430 {
431 /*
432 * poll() failed for some reason. Yield to avoid eating too much CPU.
433 *
434 * EINTR errors have been seen frequently. They should be harmless, even
435 * if they are not supposed to occur in our setup.
436 */
437 if (errno == EINTR)
438 Log(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, errno, strerror(errno)));
439 else
440 AssertMsgFailed(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, errno, strerror(errno)));
441 RTThreadYield();
442 }
443 }
444
445
446 LogFlow(("drvTAPAsyncIoThread: returns %Rrc\n", VINF_SUCCESS));
447 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
448 return VINF_SUCCESS;
449}
450
451
452/**
453 * Unblock the send thread so it can respond to a state change.
454 *
455 * @returns VBox status code.
456 * @param pDevIns The pcnet device instance.
457 * @param pThread The send thread.
458 */
459static DECLCALLBACK(int) drvTapAsyncIoWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
460{
461 PDRVTAP pThis = PDMINS_2_DATA(pDrvIns, PDRVTAP);
462
463 int rc = RTFileWrite(pThis->PipeWrite, "", 1, NULL);
464 AssertRC(rc);
465
466 return VINF_SUCCESS;
467}
468
469
470#if defined(RT_OS_SOLARIS)
471/**
472 * Calls OS-specific TAP setup application/script.
473 *
474 * @returns VBox error code.
475 * @param pThis The instance data.
476 */
477static int drvTAPSetupApplication(PDRVTAP pThis)
478{
479 char szCommand[4096];
480
481#ifdef VBOX_WITH_CROSSBOW
482 /* Convert MAC address bytes to string (required by Solaris' dladm). */
483 char *pszHex = "0123456789abcdef";
484 uint8_t *pMacAddr8 = pThis->MacAddress.au8;
485 char szMacAddress[3 * sizeof(RTMAC)];
486 for (unsigned int i = 0; i < sizeof(RTMAC); i++)
487 {
488 szMacAddress[3 * i] = pszHex[((*pMacAddr8 >> 4) & 0x0f)];
489 szMacAddress[3 * i + 1] = pszHex[(*pMacAddr8 & 0x0f)];
490 szMacAddress[3 * i + 2] = ':';
491 *pMacAddr8++;
492 }
493 szMacAddress[sizeof(szMacAddress) - 1] = 0;
494
495 RTStrPrintf(szCommand, sizeof(szCommand), "%s %s %s", pThis->pszSetupApplication,
496 szMacAddress, pThis->fStatic ? pThis->pszDeviceName : "");
497#else
498 RTStrPrintf(szCommand, sizeof(szCommand), "%s %s", pThis->pszSetupApplication,
499 pThis->fStatic ? pThis->pszDeviceName : "");
500#endif
501
502 /* Pipe open the setup application. */
503 Log2(("Starting TAP setup application: %s\n", szCommand));
504 FILE* pfSetupHandle = popen(szCommand, "r");
505 if (pfSetupHandle == 0)
506 {
507 LogRel(("TAP#%d: Failed to run TAP setup application: %s\n", pThis->pDrvIns->iInstance,
508 pThis->pszSetupApplication, strerror(errno)));
509 return VERR_HOSTIF_INIT_FAILED;
510 }
511 if (!pThis->fStatic)
512 {
513 /* Obtain device name from setup application. */
514 char acBuffer[64];
515 size_t cBufSize;
516 fgets(acBuffer, sizeof(acBuffer), pfSetupHandle);
517 cBufSize = strlen(acBuffer);
518 /* The script must return the name of the interface followed by a carriage return as the
519 first line of its output. We need a null-terminated string. */
520 if ((cBufSize < 2) || (acBuffer[cBufSize - 1] != '\n'))
521 {
522 pclose(pfSetupHandle);
523 LogRel(("The TAP interface setup script did not return the name of a TAP device.\n"));
524 return VERR_HOSTIF_INIT_FAILED;
525 }
526 /* Overwrite the terminating newline character. */
527 acBuffer[cBufSize - 1] = 0;
528 RTStrAPrintf(&pThis->pszDeviceName, "%s", acBuffer);
529 }
530 int rc = pclose(pfSetupHandle);
531 if (!WIFEXITED(rc))
532 {
533 LogRel(("The TAP interface setup script terminated abnormally.\n"));
534 return VERR_HOSTIF_INIT_FAILED;
535 }
536 if (WEXITSTATUS(rc) != 0)
537 {
538 LogRel(("The TAP interface setup script returned a non-zero exit code.\n"));
539 return VERR_HOSTIF_INIT_FAILED;
540 }
541 return VINF_SUCCESS;
542}
543
544
545/**
546 * Calls OS-specific TAP terminate application/script.
547 *
548 * @returns VBox error code.
549 * @param pThis The instance data.
550 */
551static int drvTAPTerminateApplication(PDRVTAP pThis)
552{
553 char *pszArgs[3];
554 pszArgs[0] = pThis->pszTerminateApplication;
555 pszArgs[1] = pThis->pszDeviceName;
556 pszArgs[2] = NULL;
557
558 Log2(("Starting TAP terminate application: %s %s\n", pThis->pszTerminateApplication, pThis->pszDeviceName));
559 RTPROCESS pid = NIL_RTPROCESS;
560 int rc = RTProcCreate(pszArgs[0], pszArgs, RTENV_DEFAULT, 0, &pid);
561 if (RT_SUCCESS(rc))
562 {
563 RTPROCSTATUS Status;
564 rc = RTProcWait(pid, 0, &Status);
565 if (RT_SUCCESS(rc))
566 {
567 if ( Status.iStatus == 0
568 && Status.enmReason == RTPROCEXITREASON_NORMAL)
569 return VINF_SUCCESS;
570
571 LogRel(("TAP#%d: Error running TAP terminate application: %s\n", pThis->pDrvIns->iInstance, pThis->pszTerminateApplication));
572 }
573 else
574 LogRel(("TAP#%d: RTProcWait failed for: %s\n", pThis->pDrvIns->iInstance, pThis->pszTerminateApplication));
575 }
576 else
577 {
578 /* Bad. RTProcCreate() failed! */
579 LogRel(("TAP#%d: Failed to fork() process for running TAP terminate application: %s\n", pThis->pDrvIns->iInstance,
580 pThis->pszTerminateApplication, strerror(errno)));
581 }
582 return VERR_HOSTIF_TERM_FAILED;
583}
584
585#endif /* RT_OS_SOLARIS */
586
587
588#ifdef RT_OS_SOLARIS
589# ifdef VBOX_WITH_CROSSBOW
590/**
591 * Crossbow: Open & configure the virtual NIC.
592 *
593 * @returns VBox error code.
594 * @param pThis The instance data.
595 */
596static int SolarisOpenVNIC(PDRVTAP pThis)
597{
598 /*
599 * Open & bind the NIC using the datalink provider routine.
600 */
601 int rc = g_pfnLibDlpiOpen(pThis->pszDeviceName, &pThis->pDeviceHandle, DLPI_RAW);
602 if (rc != DLPI_SUCCESS)
603 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
604 N_("Failed to open VNIC \"%s\" in raw mode"), pThis->pszDeviceName);
605
606 dlpi_info_t vnicInfo;
607 rc = g_pfnLibDlpiInfo(pThis->pDeviceHandle, &vnicInfo, 0);
608 if (rc == DLPI_SUCCESS)
609 {
610 if (vnicInfo.di_mactype == DL_ETHER)
611 {
612 rc = g_pfnLibDlpiBind(pThis->pDeviceHandle, DLPI_ANY_SAP, NULL);
613 if (rc == DLPI_SUCCESS)
614 {
615 rc = g_pfnLibDlpiSetPhysAddr(pThis->pDeviceHandle, DL_CURR_PHYS_ADDR, &pThis->MacAddress, ETHERADDRL);
616 if (rc == DLPI_SUCCESS)
617 {
618 rc = g_pfnLibDlpiPromiscon(pThis->pDeviceHandle, DL_PROMISC_SAP);
619 if (rc == DLPI_SUCCESS)
620 {
621 /* Need to use DL_PROMIS_PHYS (not multicast) as we cannot be sure what the guest needs. */
622 rc = g_pfnLibDlpiPromiscon(pThis->pDeviceHandle, DL_PROMISC_PHYS);
623 if (rc == DLPI_SUCCESS)
624 {
625 pThis->FileDevice = g_pfnLibDlpiFd(pThis->pDeviceHandle);
626 if (pThis->FileDevice >= 0)
627 {
628 Log(("SolarisOpenVNIC: %s -> %d\n", pThis->pszDeviceName, pThis->FileDevice));
629 return VINF_SUCCESS;
630 }
631
632 rc = PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
633 N_("Failed to obtain file descriptor for VNIC"));
634 }
635 else
636 rc = PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
637 N_("Failed to set appropriate promiscous mode"));
638 }
639 else
640 rc = PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
641 N_("Failed to activate promiscous mode for VNIC"));
642 }
643 else
644 rc = PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
645 N_("Failed to set physical address for VNIC"));
646 }
647 else
648 rc = PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
649 N_("Failed to bind VNIC"));
650 }
651 else
652 rc = PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
653 N_("VNIC type is not ethernet"));
654 }
655 else
656 rc = PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
657 N_("Failed to obtain VNIC info"));
658 g_pfnLibDlpiClose(pThis->pDeviceHandle);
659 return rc;
660}
661
662
663/**
664 * Crossbow: Converts a Solaris DLPI error code to a VBox error code.
665 *
666 * @returns corresponding VBox error code.
667 * @param rc DLPI error code (DLPI_* defines).
668 */
669static int SolarisDLPIErr2VBoxErr(int rc)
670{
671 switch (rc)
672 {
673 case DLPI_SUCCESS: return VINF_SUCCESS;
674 case DLPI_EINVAL: return VERR_INVALID_PARAMETER;
675 case DLPI_ELINKNAMEINVAL: return VERR_INVALID_NAME;
676 case DLPI_EINHANDLE: return VERR_INVALID_HANDLE;
677 case DLPI_ETIMEDOUT: return VERR_TIMEOUT;
678 case DLPI_FAILURE: return VERR_GENERAL_FAILURE;
679
680 case DLPI_EVERNOTSUP:
681 case DLPI_EMODENOTSUP:
682 case DLPI_ERAWNOTSUP:
683 /* case DLPI_ENOTENOTSUP: */
684 case DLPI_EUNAVAILSAP: return VERR_NOT_SUPPORTED;
685
686 /* Define VBox error codes for these, if really needed. */
687 case DLPI_ENOLINK:
688 case DLPI_EBADLINK:
689 /* case DLPI_ENOTEIDINVAL: */
690 case DLPI_EBADMSG:
691 case DLPI_ENOTSTYLE2: return VERR_GENERAL_FAILURE;
692 }
693
694 AssertMsgFailed(("SolarisDLPIErr2VBoxErr: Unhandled error %d\n", rc));
695 return VERR_UNRESOLVED_ERROR;
696}
697
698# else /* VBOX_WITH_CROSSBOW */
699
700/** From net/if_tun.h, installed by Universal TUN/TAP driver */
701# define TUNNEWPPA (('T'<<16) | 0x0001)
702/** Whether to enable ARP for TAP. */
703# define VBOX_SOLARIS_TAP_ARP 1
704
705/**
706 * Creates/Attaches TAP device to IP.
707 *
708 * @returns VBox error code.
709 * @param pThis The instance data.
710 */
711static DECLCALLBACK(int) SolarisTAPAttach(PDRVTAP pThis)
712{
713 LogFlow(("SolarisTapAttach: pThis=%p\n", pThis));
714
715
716 int IPFileDes = open("/dev/udp", O_RDWR, 0);
717 if (IPFileDes < 0)
718 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
719 N_("Failed to open /dev/udp. errno=%d"), errno);
720
721 int TapFileDes = open("/dev/tap", O_RDWR, 0);
722 if (TapFileDes < 0)
723 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
724 N_("Failed to open /dev/tap for TAP. errno=%d"), errno);
725
726 /* Use the PPA from the ifname if possible (e.g "tap2", then use 2 as PPA) */
727 int iPPA = -1;
728 if (pThis->pszDeviceName)
729 {
730 size_t cch = strlen(pThis->pszDeviceName);
731 if (cch > 1 && RT_C_IS_DIGIT(pThis->pszDeviceName[cch - 1]) != 0)
732 iPPA = pThis->pszDeviceName[cch - 1] - '0';
733 }
734
735 struct strioctl ioIF;
736 ioIF.ic_cmd = TUNNEWPPA;
737 ioIF.ic_len = sizeof(iPPA);
738 ioIF.ic_dp = (char *)(&iPPA);
739 ioIF.ic_timout = 0;
740 iPPA = ioctl(TapFileDes, I_STR, &ioIF);
741 if (iPPA < 0)
742 {
743 close(TapFileDes);
744 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
745 N_("Failed to get new interface. errno=%d"), errno);
746 }
747
748 int InterfaceFD = open("/dev/tap", O_RDWR, 0);
749 if (!InterfaceFD)
750 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
751 N_("Failed to open interface /dev/tap. errno=%d"), errno);
752
753 if (ioctl(InterfaceFD, I_PUSH, "ip") == -1)
754 {
755 close(InterfaceFD);
756 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
757 N_("Failed to push IP. errno=%d"), errno);
758 }
759
760 struct lifreq ifReq;
761 memset(&ifReq, 0, sizeof(ifReq));
762 if (ioctl(InterfaceFD, SIOCGLIFFLAGS, &ifReq) == -1)
763 LogRel(("TAP#%d: Failed to get interface flags.\n", pThis->pDrvIns->iInstance));
764
765 ifReq.lifr_ppa = iPPA;
766 RTStrPrintf (ifReq.lifr_name, sizeof(ifReq.lifr_name), pThis->pszDeviceName);
767
768 if (ioctl(InterfaceFD, SIOCSLIFNAME, &ifReq) == -1)
769 LogRel(("TAP#%d: Failed to set PPA. errno=%d\n", pThis->pDrvIns->iInstance, errno));
770
771 if (ioctl(InterfaceFD, SIOCGLIFFLAGS, &ifReq) == -1)
772 LogRel(("TAP#%d: Failed to get interface flags after setting PPA. errno=%d\n", pThis->pDrvIns->iInstance, errno));
773
774#ifdef VBOX_SOLARIS_TAP_ARP
775 /* Interface */
776 if (ioctl(InterfaceFD, I_PUSH, "arp") == -1)
777 LogRel(("TAP#%d: Failed to push ARP to Interface FD. errno=%d\n", pThis->pDrvIns->iInstance, errno));
778
779 /* IP */
780 if (ioctl(IPFileDes, I_POP, NULL) == -1)
781 LogRel(("TAP#%d: Failed I_POP from IP FD. errno=%d\n", pThis->pDrvIns->iInstance, errno));
782
783 if (ioctl(IPFileDes, I_PUSH, "arp") == -1)
784 LogRel(("TAP#%d: Failed to push ARP to IP FD. errno=%d\n", pThis->pDrvIns->iInstance, errno));
785
786 /* ARP */
787 int ARPFileDes = open("/dev/tap", O_RDWR, 0);
788 if (ARPFileDes < 0)
789 LogRel(("TAP#%d: Failed to open for /dev/tap for ARP. errno=%d", pThis->pDrvIns->iInstance, errno));
790
791 if (ioctl(ARPFileDes, I_PUSH, "arp") == -1)
792 LogRel(("TAP#%d: Failed to push ARP to ARP FD. errno=%d\n", pThis->pDrvIns->iInstance, errno));
793
794 ioIF.ic_cmd = SIOCSLIFNAME;
795 ioIF.ic_timout = 0;
796 ioIF.ic_len = sizeof(ifReq);
797 ioIF.ic_dp = (char *)&ifReq;
798 if (ioctl(ARPFileDes, I_STR, &ioIF) == -1)
799 LogRel(("TAP#%d: Failed to set interface name to ARP.\n", pThis->pDrvIns->iInstance));
800#endif
801
802 /* We must use I_LINK and not I_PLINK as I_PLINK makes the link persistent.
803 * Then we would not be able unlink the interface if we reuse it.
804 * Even 'unplumb' won't work after that.
805 */
806 int IPMuxID = ioctl(IPFileDes, I_LINK, InterfaceFD);
807 if (IPMuxID == -1)
808 {
809 close(InterfaceFD);
810#ifdef VBOX_SOLARIS_TAP_ARP
811 close(ARPFileDes);
812#endif
813 LogRel(("TAP#%d: Cannot link TAP device to IP.\n", pThis->pDrvIns->iInstance));
814 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
815 N_("Failed to link TAP device to IP. Check TAP interface name. errno=%d"), errno);
816 }
817
818#ifdef VBOX_SOLARIS_TAP_ARP
819 int ARPMuxID = ioctl(IPFileDes, I_LINK, ARPFileDes);
820 if (ARPMuxID == -1)
821 LogRel(("TAP#%d: Failed to link TAP device to ARP\n", pThis->pDrvIns->iInstance));
822
823 close(ARPFileDes);
824#endif
825 close(InterfaceFD);
826
827 /* Reuse ifReq */
828 memset(&ifReq, 0, sizeof(ifReq));
829 RTStrPrintf (ifReq.lifr_name, sizeof(ifReq.lifr_name), pThis->pszDeviceName);
830 ifReq.lifr_ip_muxid = IPMuxID;
831#ifdef VBOX_SOLARIS_TAP_ARP
832 ifReq.lifr_arp_muxid = ARPMuxID;
833#endif
834
835 if (ioctl(IPFileDes, SIOCSLIFMUXID, &ifReq) == -1)
836 {
837#ifdef VBOX_SOLARIS_TAP_ARP
838 ioctl(IPFileDes, I_PUNLINK, ARPMuxID);
839#endif
840 ioctl(IPFileDes, I_PUNLINK, IPMuxID);
841 close(IPFileDes);
842 LogRel(("TAP#%d: Failed to set Mux ID.\n", pThis->pDrvIns->iInstance));
843 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
844 N_("Failed to set Mux ID. Check TAP interface name. errno=%d"), errno);
845 }
846
847 pThis->FileDevice = (RTFILE)TapFileDes;
848 pThis->IPFileDevice = (RTFILE)IPFileDes;
849
850 return VINF_SUCCESS;
851}
852
853# endif /* VBOX_WITH_CROSSBOW */
854#endif /* RT_OS_SOLARIS */
855
856/* -=-=-=-=- PDMIBASE -=-=-=-=- */
857
858/**
859 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
860 */
861static DECLCALLBACK(void *) drvTAPQueryInterface(PPDMIBASE pInterface, const char *pszIID)
862{
863 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
864 PDRVTAP pThis = PDMINS_2_DATA(pDrvIns, PDRVTAP);
865
866 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
867 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUp);
868 return NULL;
869}
870
871/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
872
873/**
874 * Destruct a driver instance.
875 *
876 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
877 * resources can be freed correctly.
878 *
879 * @param pDrvIns The driver instance data.
880 */
881static DECLCALLBACK(void) drvTAPDestruct(PPDMDRVINS pDrvIns)
882{
883 LogFlow(("drvTAPDestruct\n"));
884 PDRVTAP pThis = PDMINS_2_DATA(pDrvIns, PDRVTAP);
885 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
886
887 /*
888 * Terminate the control pipe.
889 */
890 if (pThis->PipeWrite != NIL_RTFILE)
891 {
892 int rc = RTFileClose(pThis->PipeWrite);
893 AssertRC(rc);
894 pThis->PipeWrite = NIL_RTFILE;
895 }
896 if (pThis->PipeRead != NIL_RTFILE)
897 {
898 int rc = RTFileClose(pThis->PipeRead);
899 AssertRC(rc);
900 pThis->PipeRead = NIL_RTFILE;
901 }
902
903#ifdef RT_OS_SOLARIS
904 /** @todo r=bird: This *does* need checking against ConsoleImpl2.cpp if used on non-solaris systems. */
905 if (pThis->FileDevice != NIL_RTFILE)
906 {
907 int rc = RTFileClose(pThis->FileDevice);
908 AssertRC(rc);
909 pThis->FileDevice = NIL_RTFILE;
910 }
911
912# ifndef VBOX_WITH_CROSSBOW
913 if (pThis->IPFileDevice != NIL_RTFILE)
914 {
915 int rc = RTFileClose(pThis->IPFileDevice);
916 AssertRC(rc);
917 pThis->IPFileDevice = NIL_RTFILE;
918 }
919# endif
920
921 /*
922 * Call TerminateApplication after closing the device otherwise
923 * TerminateApplication would not be able to unplumb it.
924 */
925 if (pThis->pszTerminateApplication)
926 drvTAPTerminateApplication(pThis);
927
928#endif /* RT_OS_SOLARIS */
929
930#ifdef RT_OS_SOLARIS
931 if (!pThis->fStatic)
932 RTStrFree(pThis->pszDeviceName); /* allocated by drvTAPSetupApplication */
933 else
934 MMR3HeapFree(pThis->pszDeviceName);
935#else
936 MMR3HeapFree(pThis->pszDeviceName);
937#endif
938 MMR3HeapFree(pThis->pszSetupApplication);
939 MMR3HeapFree(pThis->pszTerminateApplication);
940
941#ifdef VBOX_WITH_STATISTICS
942 /*
943 * Deregister statistics.
944 */
945 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktSent);
946 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktSentBytes);
947 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktRecv);
948 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktRecvBytes);
949 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatTransmit);
950 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceive);
951#endif /* VBOX_WITH_STATISTICS */
952}
953
954
955/**
956 * Construct a TAP network transport driver instance.
957 *
958 * @copydoc FNPDMDRVCONSTRUCT
959 */
960static DECLCALLBACK(int) drvTAPConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
961{
962 PDRVTAP pThis = PDMINS_2_DATA(pDrvIns, PDRVTAP);
963 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
964
965 /*
966 * Init the static parts.
967 */
968 pThis->pDrvIns = pDrvIns;
969 pThis->FileDevice = NIL_RTFILE;
970 pThis->pszDeviceName = NULL;
971#ifdef RT_OS_SOLARIS
972# ifdef VBOX_WITH_CROSSBOW
973 pThis->pDeviceHandle = NULL;
974# else
975 pThis->IPFileDevice = NIL_RTFILE;
976# endif
977 pThis->fStatic = true;
978#endif
979 pThis->pszSetupApplication = NULL;
980 pThis->pszTerminateApplication = NULL;
981
982 /* IBase */
983 pDrvIns->IBase.pfnQueryInterface = drvTAPQueryInterface;
984 /* INetwork */
985 pThis->INetworkUp.pfnSendBuf = drvTAPNetworkUp_SendBuf;
986 pThis->INetworkUp.pfnAllocBuf = drvTAPNetworkUp_AllocBuf;
987 pThis->INetworkUp.pfnFreeBuf = drvTAPNetworkUp_FreeBuf;
988 pThis->INetworkUp.pfnSetPromiscuousMode = drvTAPNetworkUp_SetPromiscuousMode;
989 pThis->INetworkUp.pfnNotifyLinkChanged = drvTAPNetworkUp_NotifyLinkChanged;
990
991 /*
992 * Validate the config.
993 */
994 if (!CFGMR3AreValuesValid(pCfg, "Device\0InitProg\0TermProg\0FileHandle\0TAPSetupApplication\0TAPTerminateApplication\0MAC"))
995 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES, "");
996
997 /*
998 * Check that no-one is attached to us.
999 */
1000 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
1001 ("Configuration error: Not possible to attach anything to this driver!\n"),
1002 VERR_PDM_DRVINS_NO_ATTACH);
1003
1004 /*
1005 * Query the network port interface.
1006 */
1007 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
1008 if (!pThis->pIAboveNet)
1009 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
1010 N_("Configuration error: The above device/driver didn't export the network port interface"));
1011
1012 /*
1013 * Read the configuration.
1014 */
1015 int rc;
1016#if defined(RT_OS_SOLARIS) /** @todo Other platforms' TAP code should be moved here from ConsoleImpl & VBoxBFE. */
1017 rc = CFGMR3QueryStringAlloc(pCfg, "TAPSetupApplication", &pThis->pszSetupApplication);
1018 if (RT_SUCCESS(rc))
1019 {
1020 if (!RTPathExists(pThis->pszSetupApplication))
1021 return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
1022 N_("Invalid TAP setup program path: %s"), pThis->pszSetupApplication);
1023 }
1024 else if (rc != VERR_CFGM_VALUE_NOT_FOUND)
1025 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Configuration error: failed to query \"TAPTerminateApplication\""));
1026
1027 rc = CFGMR3QueryStringAlloc(pCfg, "TAPTerminateApplication", &pThis->pszTerminateApplication);
1028 if (RT_SUCCESS(rc))
1029 {
1030 if (!RTPathExists(pThis->pszTerminateApplication))
1031 return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
1032 N_("Invalid TAP terminate program path: %s"), pThis->pszTerminateApplication);
1033 }
1034 else if (rc != VERR_CFGM_VALUE_NOT_FOUND)
1035 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Configuration error: failed to query \"TAPTerminateApplication\""));
1036
1037# ifdef VBOX_WITH_CROSSBOW
1038 rc = CFGMR3QueryBytes(pCfg, "MAC", &pThis->MacAddress, sizeof(pThis->MacAddress));
1039 if (RT_FAILURE(rc))
1040 return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Configuration error: Failed to query \"MAC\""));
1041# endif
1042
1043 rc = CFGMR3QueryStringAlloc(pCfg, "Device", &pThis->pszDeviceName);
1044 if (RT_FAILURE(rc))
1045 pThis->fStatic = false;
1046
1047 /* Obtain the device name from the setup application (if none was specified). */
1048 if (pThis->pszSetupApplication)
1049 {
1050 rc = drvTAPSetupApplication(pThis);
1051 if (RT_FAILURE(rc))
1052 return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
1053 N_("Error running TAP setup application. rc=%d"), rc);
1054 }
1055
1056 /*
1057 * Do the setup.
1058 */
1059# ifdef VBOX_WITH_CROSSBOW
1060 if (!VBoxLibDlpiFound())
1061 {
1062 return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS,
1063 N_("Failed to load library %s required for host interface networking."), LIB_DLPI);
1064 }
1065 rc = SolarisOpenVNIC(pThis);
1066# else
1067 rc = SolarisTAPAttach(pThis);
1068# endif
1069 if (RT_FAILURE(rc))
1070 return rc;
1071
1072#else /* !RT_OS_SOLARIS */
1073
1074 int32_t iFile;
1075 rc = CFGMR3QueryS32(pCfg, "FileHandle", &iFile);
1076 if (RT_FAILURE(rc))
1077 return PDMDRV_SET_ERROR(pDrvIns, rc,
1078 N_("Configuration error: Query for \"FileHandle\" 32-bit signed integer failed"));
1079 pThis->FileDevice = (RTFILE)iFile;
1080 if (!RTFileIsValid(pThis->FileDevice))
1081 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_HANDLE, RT_SRC_POS,
1082 N_("The TAP file handle %RTfile is not valid"), pThis->FileDevice);
1083#endif /* !RT_OS_SOLARIS */
1084
1085 /*
1086 * Make sure the descriptor is non-blocking and valid.
1087 *
1088 * We should actually query if it's a TAP device, but I haven't
1089 * found any way to do that.
1090 */
1091 if (fcntl(pThis->FileDevice, F_SETFL, O_NONBLOCK) == -1)
1092 return PDMDrvHlpVMSetError(pDrvIns, VERR_HOSTIF_IOCTL, RT_SRC_POS,
1093 N_("Configuration error: Failed to configure /dev/net/tun. errno=%d"), errno);
1094 /** @todo determine device name. This can be done by reading the link /proc/<pid>/fd/<fd> */
1095 Log(("drvTAPContruct: %d (from fd)\n", pThis->FileDevice));
1096 rc = VINF_SUCCESS;
1097
1098 /*
1099 * Create the control pipe.
1100 */
1101 int fds[2];
1102#ifdef RT_OS_L4
1103 /* XXX We need to tell the library which interface we are using */
1104 fds[0] = vboxrtLinuxFd2VBoxFd(VBOXRT_FT_TAP, 0);
1105#endif
1106 if (pipe(&fds[0]) != 0) /** @todo RTPipeCreate() or something... */
1107 {
1108 rc = RTErrConvertFromErrno(errno);
1109 AssertRC(rc);
1110 return rc;
1111 }
1112 pThis->PipeRead = fds[0];
1113 pThis->PipeWrite = fds[1];
1114
1115 /*
1116 * Create the async I/O thread.
1117 */
1118 rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pThread, pThis, drvTAPAsyncIoThread, drvTapAsyncIoWakeup, 128 * _1K, RTTHREADTYPE_IO, "TAP");
1119 AssertRCReturn(rc, rc);
1120
1121#ifdef VBOX_WITH_STATISTICS
1122 /*
1123 * Statistics.
1124 */
1125 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of sent packets.", "/Drivers/TAP%d/Packets/Sent", pDrvIns->iInstance);
1126 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSentBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Drivers/TAP%d/Bytes/Sent", pDrvIns->iInstance);
1127 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of received packets.", "/Drivers/TAP%d/Packets/Received", pDrvIns->iInstance);
1128 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecvBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Drivers/TAP%d/Bytes/Received", pDrvIns->iInstance);
1129 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Drivers/TAP%d/Transmit", pDrvIns->iInstance);
1130 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Drivers/TAP%d/Receive", pDrvIns->iInstance);
1131#endif /* VBOX_WITH_STATISTICS */
1132
1133 return rc;
1134}
1135
1136
1137/**
1138 * TAP network transport driver registration record.
1139 */
1140const PDMDRVREG g_DrvHostInterface =
1141{
1142 /* u32Version */
1143 PDM_DRVREG_VERSION,
1144 /* szName */
1145 "HostInterface",
1146 /* szRCMod */
1147 "",
1148 /* szR0Mod */
1149 "",
1150 /* pszDescription */
1151 "TAP Network Transport Driver",
1152 /* fFlags */
1153 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1154 /* fClass. */
1155 PDM_DRVREG_CLASS_NETWORK,
1156 /* cMaxInstances */
1157 ~0,
1158 /* cbInstance */
1159 sizeof(DRVTAP),
1160 /* pfnConstruct */
1161 drvTAPConstruct,
1162 /* pfnDestruct */
1163 drvTAPDestruct,
1164 /* pfnRelocate */
1165 NULL,
1166 /* pfnIOCtl */
1167 NULL,
1168 /* pfnPowerOn */
1169 NULL,
1170 /* pfnReset */
1171 NULL,
1172 /* pfnSuspend */
1173 NULL, /** @todo Do power on, suspend and resume handlers! */
1174 /* pfnResume */
1175 NULL,
1176 /* pfnAttach */
1177 NULL,
1178 /* pfnDetach */
1179 NULL,
1180 /* pfnPowerOff */
1181 NULL,
1182 /* pfnSoftReset */
1183 NULL,
1184 /* u32EndVersion */
1185 PDM_DRVREG_VERSION
1186};
1187
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