VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvIntNet.cpp@ 25985

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

pdmifs.h: the final batch of refactored interface ID code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.1 KB
Line 
1/* $Id: DrvIntNet.cpp 25985 2010-01-23 00:51:04Z vboxsync $ */
2/** @file
3 * DrvIntNet - Internal network transport driver.
4 */
5
6/*
7 * Copyright (C) 2006-2007 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_INTNET
26#include <VBox/pdmdrv.h>
27#include <VBox/cfgm.h>
28#include <VBox/intnet.h>
29#include <VBox/vmm.h>
30#include <VBox/err.h>
31
32#include <VBox/log.h>
33#include <iprt/asm.h>
34#include <iprt/assert.h>
35#include <iprt/ctype.h>
36#include <iprt/net.h>
37#include <iprt/semaphore.h>
38#include <iprt/string.h>
39#include <iprt/time.h>
40#include <iprt/thread.h>
41#include <iprt/uuid.h>
42
43#include "../Builtins.h"
44
45
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49/**
50 * The state of the asynchronous thread.
51 */
52typedef enum ASYNCSTATE
53{
54 /** The thread is suspended. */
55 ASYNCSTATE_SUSPENDED = 1,
56 /** The thread is running. */
57 ASYNCSTATE_RUNNING,
58 /** The thread must (/has) terminate. */
59 ASYNCSTATE_TERMINATE,
60 /** The usual 32-bit type blowup. */
61 ASYNCSTATE_32BIT_HACK = 0x7fffffff
62} ASYNCSTATE;
63
64/**
65 * Block driver instance data.
66 *
67 * @implements PDMINETWORKCONNECTOR
68 */
69typedef struct DRVINTNET
70{
71 /** The network interface. */
72 PDMINETWORKCONNECTOR INetworkConnector;
73 /** The network interface. */
74 PPDMINETWORKPORT pPort;
75 /** The network config interface.
76 * Can (in theory at least) be NULL. */
77 PPDMINETWORKCONFIG pConfigIf;
78 /** Pointer to the driver instance. */
79 PPDMDRVINS pDrvIns;
80 /** Interface handle. */
81 INTNETIFHANDLE hIf;
82 /** Pointer to the communication buffer. */
83 PINTNETBUF pBuf;
84 /** The thread state. */
85 ASYNCSTATE volatile enmState;
86 /** Reader thread. */
87 RTTHREAD Thread;
88 /** Event semaphore the Thread waits on while the VM is suspended. */
89 RTSEMEVENT EventSuspended;
90 /** Set if the link is down.
91 * When the link is down all incoming packets will be dropped. */
92 bool volatile fLinkDown;
93 /** Set if data transmission should start immediately and deactivate
94 * as late as possible. */
95 bool fActivateEarlyDeactivateLate;
96
97#ifdef LOG_ENABLED
98 /** The nano ts of the last transfer. */
99 uint64_t u64LastTransferTS;
100 /** The nano ts of the last receive. */
101 uint64_t u64LastReceiveTS;
102#endif
103
104#ifdef VBOX_WITH_STATISTICS
105 /** Profiling packet transmit runs. */
106 STAMPROFILE StatTransmit;
107 /** Profiling packet receive runs. */
108 STAMPROFILEADV StatReceive;
109#endif /* VBOX_WITH_STATISTICS */
110
111 /** The network name. */
112 char szNetwork[INTNET_MAX_NETWORK_NAME];
113} DRVINTNET, *PDRVINTNET;
114
115
116/** Converts a pointer to DRVINTNET::INetworkConnector to a PDRVINTNET. */
117#define PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface) ( (PDRVINTNET)((uintptr_t)pInterface - RT_OFFSETOF(DRVINTNET, INetworkConnector)) )
118
119
120/**
121 * Updates the MAC address on the kernel side.
122 *
123 * @returns VBox status code.
124 * @param pThis The driver instance.
125 */
126static int drvIntNetUpdateMacAddress(PDRVINTNET pThis)
127{
128 if (!pThis->pConfigIf)
129 return VINF_SUCCESS;
130
131 INTNETIFSETMACADDRESSREQ SetMacAddressReq;
132 SetMacAddressReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
133 SetMacAddressReq.Hdr.cbReq = sizeof(SetMacAddressReq);
134 SetMacAddressReq.pSession = NIL_RTR0PTR;
135 SetMacAddressReq.hIf = pThis->hIf;
136 int rc = pThis->pConfigIf->pfnGetMac(pThis->pConfigIf, &SetMacAddressReq.Mac);
137 if (RT_SUCCESS(rc))
138 rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvIns, VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS,
139 &SetMacAddressReq, sizeof(SetMacAddressReq));
140
141 Log(("drvIntNetUpdateMacAddress: %.*Rhxs rc=%Rrc\n", sizeof(SetMacAddressReq.Mac), &SetMacAddressReq.Mac, rc));
142 return rc;
143}
144
145
146/**
147 * Sets the kernel interface active or inactive.
148 *
149 * Worker for poweron, poweroff, suspend and resume.
150 *
151 * @returns VBox status code.
152 * @param pThis The driver instance.
153 * @param fActive The new state.
154 */
155static int drvIntNetSetActive(PDRVINTNET pThis, bool fActive)
156{
157 if (!pThis->pConfigIf)
158 return VINF_SUCCESS;
159
160 INTNETIFSETACTIVEREQ SetActiveReq;
161 SetActiveReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
162 SetActiveReq.Hdr.cbReq = sizeof(SetActiveReq);
163 SetActiveReq.pSession = NIL_RTR0PTR;
164 SetActiveReq.hIf = pThis->hIf;
165 SetActiveReq.fActive = fActive;
166 int rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvIns, VMMR0_DO_INTNET_IF_SET_ACTIVE,
167 &SetActiveReq, sizeof(SetActiveReq));
168
169 Log(("drvIntNetUpdateMacAddress: fActive=%d rc=%Rrc\n", fActive, rc));
170 AssertRC(rc);
171 return rc;
172}
173
174
175/**
176 * Writes a frame packet to the buffer.
177 *
178 * @returns VBox status code.
179 * @param pBuf The buffer.
180 * @param pRingBuf The ring buffer to read from.
181 * @param pvFrame The frame to write.
182 * @param cbFrame The size of the frame.
183 * @remark This is the same as INTNETRingWriteFrame
184 */
185static int drvIntNetRingWriteFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, const void *pvFrame, uint32_t cbFrame)
186{
187 /*
188 * Validate input.
189 */
190 Assert(pBuf);
191 Assert(pRingBuf);
192 Assert(pvFrame);
193 Assert(cbFrame >= sizeof(RTMAC) * 2);
194 uint32_t offWrite = pRingBuf->offWrite;
195 Assert(offWrite == RT_ALIGN_32(offWrite, sizeof(INTNETHDR)));
196 uint32_t offRead = pRingBuf->offRead;
197 Assert(offRead == RT_ALIGN_32(offRead, sizeof(INTNETHDR)));
198
199 const uint32_t cb = RT_ALIGN_32(cbFrame, sizeof(INTNETHDR));
200 if (offRead <= offWrite)
201 {
202 /*
203 * Try fit it all before the end of the buffer.
204 */
205 if (pRingBuf->offEnd - offWrite >= cb + sizeof(INTNETHDR))
206 {
207 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
208 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
209 pHdr->cbFrame = cbFrame;
210 pHdr->offFrame = sizeof(INTNETHDR);
211
212 memcpy(pHdr + 1, pvFrame, cbFrame);
213
214 offWrite += cb + sizeof(INTNETHDR);
215 Assert(offWrite <= pRingBuf->offEnd && offWrite >= pRingBuf->offStart);
216 if (offWrite >= pRingBuf->offEnd)
217 offWrite = pRingBuf->offStart;
218 Log2(("WriteFrame: offWrite: %#x -> %#x (1)\n", pRingBuf->offWrite, offWrite));
219 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
220 return VINF_SUCCESS;
221 }
222
223 /*
224 * Try fit the frame at the start of the buffer.
225 * (The header fits before the end of the buffer because of alignment.)
226 */
227 AssertMsg(pRingBuf->offEnd - offWrite >= sizeof(INTNETHDR), ("offEnd=%x offWrite=%x\n", pRingBuf->offEnd, offWrite));
228 if (offRead - pRingBuf->offStart > cb) /* not >= ! */
229 {
230 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
231 void *pvFrameOut = (PINTNETHDR)((uint8_t *)pBuf + pRingBuf->offStart);
232 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
233 pHdr->cbFrame = cbFrame;
234 pHdr->offFrame = (intptr_t)pvFrameOut - (intptr_t)pHdr;
235
236 memcpy(pvFrameOut, pvFrame, cbFrame);
237
238 offWrite = pRingBuf->offStart + cb;
239 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
240 Log2(("WriteFrame: offWrite: %#x -> %#x (2)\n", pRingBuf->offWrite, offWrite));
241 return VINF_SUCCESS;
242 }
243 }
244 /*
245 * The reader is ahead of the writer, try fit it into that space.
246 */
247 else if (offRead - offWrite > cb + sizeof(INTNETHDR)) /* not >= ! */
248 {
249 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
250 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
251 pHdr->cbFrame = cbFrame;
252 pHdr->offFrame = sizeof(INTNETHDR);
253
254 memcpy(pHdr + 1, pvFrame, cbFrame);
255
256 offWrite += cb + sizeof(INTNETHDR);
257 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
258 Log2(("WriteFrame: offWrite: %#x -> %#x (3)\n", pRingBuf->offWrite, offWrite));
259 return VINF_SUCCESS;
260 }
261
262 /* (it didn't fit) */
263 /** @todo stats */
264 return VERR_BUFFER_OVERFLOW;
265}
266
267
268/**
269 * Send data to the network.
270 *
271 * @returns VBox status code.
272 * @param pInterface Pointer to the interface structure containing the called function pointer.
273 * @param pvBuf Data to send.
274 * @param cb Number of bytes to send.
275 * @thread EMT
276 */
277static DECLCALLBACK(int) drvIntNetSend(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
278{
279 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
280 STAM_PROFILE_START(&pThis->StatTransmit, a);
281
282#ifdef LOG_ENABLED
283 uint64_t u64Now = RTTimeProgramNanoTS();
284 LogFlow(("drvIntNetSend: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
285 cb, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
286 pThis->u64LastTransferTS = u64Now;
287 Log2(("drvIntNetSend: pvBuf=%p cb=%#x\n"
288 "%.*Rhxd\n",
289 pvBuf, cb, cb, pvBuf));
290#endif
291
292 /*
293 * Add the frame to the send buffer and push it onto the network.
294 */
295 int rc = drvIntNetRingWriteFrame(pThis->pBuf, &pThis->pBuf->Send, pvBuf, (uint32_t)cb);
296 if ( rc == VERR_BUFFER_OVERFLOW
297 && pThis->pBuf->cbSend < cb)
298 {
299 INTNETIFSENDREQ SendReq;
300 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
301 SendReq.Hdr.cbReq = sizeof(SendReq);
302 SendReq.pSession = NIL_RTR0PTR;
303 SendReq.hIf = pThis->hIf;
304 PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvIns, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
305
306 rc = drvIntNetRingWriteFrame(pThis->pBuf, &pThis->pBuf->Send, pvBuf, (uint32_t)cb);
307 }
308
309 if (RT_SUCCESS(rc))
310 {
311 INTNETIFSENDREQ SendReq;
312 SendReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
313 SendReq.Hdr.cbReq = sizeof(SendReq);
314 SendReq.pSession = NIL_RTR0PTR;
315 SendReq.hIf = pThis->hIf;
316 rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvIns, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
317 }
318
319 STAM_PROFILE_STOP(&pThis->StatTransmit, a);
320 AssertRC(rc);
321 return rc;
322}
323
324
325/**
326 * Set promiscuous mode.
327 *
328 * This is called when the promiscuous mode is set. This means that there doesn't have
329 * to be a mode change when it's called.
330 *
331 * @param pInterface Pointer to the interface structure containing the called function pointer.
332 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
333 * @thread EMT
334 */
335static DECLCALLBACK(void) drvIntNetSetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
336{
337 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
338 INTNETIFSETPROMISCUOUSMODEREQ Req;
339 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
340 Req.Hdr.cbReq = sizeof(Req);
341 Req.pSession = NIL_RTR0PTR;
342 Req.hIf = pThis->hIf;
343 Req.fPromiscuous = fPromiscuous;
344 int rc = PDMDrvHlpSUPCallVMMR0Ex(pThis->pDrvIns, VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, &Req, sizeof(Req));
345 LogFlow(("drvIntNetSetPromiscuousMode: fPromiscuous=%RTbool\n", fPromiscuous));
346 AssertRC(rc);
347}
348
349
350/**
351 * Notification on link status changes.
352 *
353 * @param pInterface Pointer to the interface structure containing the called function pointer.
354 * @param enmLinkState The new link state.
355 * @thread EMT
356 */
357static DECLCALLBACK(void) drvIntNetNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
358{
359 PDRVINTNET pThis = PDMINETWORKCONNECTOR_2_DRVINTNET(pInterface);
360 bool fLinkDown;
361 switch (enmLinkState)
362 {
363 case PDMNETWORKLINKSTATE_DOWN:
364 case PDMNETWORKLINKSTATE_DOWN_RESUME:
365 fLinkDown = true;
366 break;
367 default:
368 AssertMsgFailed(("enmLinkState=%d\n", enmLinkState));
369 case PDMNETWORKLINKSTATE_UP:
370 fLinkDown = false;
371 break;
372 }
373 LogFlow(("drvIntNetNotifyLinkChanged: enmLinkState=%d %d->%d\n", enmLinkState, pThis->fLinkDown, fLinkDown));
374 ASMAtomicXchgSize(&pThis->fLinkDown, fLinkDown);
375}
376
377
378/**
379 * Wait for space to become available up the driver/device chain.
380 *
381 * @returns VINF_SUCCESS if space is available.
382 * @returns VERR_STATE_CHANGED if the state changed.
383 * @returns VBox status code on other errors.
384 * @param pThis Pointer to the instance data.
385 */
386static int drvIntNetAsyncIoWaitForSpace(PDRVINTNET pThis)
387{
388 LogFlow(("drvIntNetAsyncIoWaitForSpace:\n"));
389 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
390 int rc = pThis->pPort->pfnWaitReceiveAvail(pThis->pPort, RT_INDEFINITE_WAIT);
391 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
392 LogFlow(("drvIntNetAsyncIoWaitForSpace: returns %Rrc\n", rc));
393 return rc;
394}
395
396
397/**
398 * Executes async I/O (RUNNING mode).
399 *
400 * @returns VERR_STATE_CHANGED if the state changed.
401 * @returns Appropriate VBox status code (error) on fatal error.
402 * @param pThis The driver instance data.
403 */
404static int drvIntNetAsyncIoRun(PDRVINTNET pThis)
405{
406 PPDMDRVINS pDrvIns = pThis->pDrvIns;
407 LogFlow(("drvIntNetAsyncIoRun: pThis=%p\n", pThis));
408
409 /*
410 * The running loop - processing received data and waiting for more to arrive.
411 */
412 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
413 PINTNETBUF pBuf = pThis->pBuf;
414 PINTNETRINGBUF pRingBuf = &pThis->pBuf->Recv;
415 for (;;)
416 {
417 /*
418 * Process the receive buffer.
419 */
420 while (INTNETRingGetReadable(pRingBuf) > 0)
421 {
422 /*
423 * Check the state and then inspect the packet.
424 */
425 if (pThis->enmState != ASYNCSTATE_RUNNING)
426 {
427 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
428 LogFlow(("drvIntNetAsyncIoRun: returns VERR_STATE_CHANGED (state changed - #0)\n"));
429 return VERR_STATE_CHANGED;
430 }
431
432 PINTNETHDR pHdr = (PINTNETHDR)((uintptr_t)pBuf + pRingBuf->offRead);
433 Log2(("pHdr=%p offRead=%#x: %.8Rhxs\n", pHdr, pRingBuf->offRead, pHdr));
434 if ( pHdr->u16Type == INTNETHDR_TYPE_FRAME
435 && !pThis->fLinkDown)
436 {
437 /*
438 * Check if there is room for the frame and pass it up.
439 */
440 size_t cbFrame = pHdr->cbFrame;
441 int rc = pThis->pPort->pfnWaitReceiveAvail(pThis->pPort, 0);
442 if (rc == VINF_SUCCESS)
443 {
444#ifdef LOG_ENABLED
445 uint64_t u64Now = RTTimeProgramNanoTS();
446 LogFlow(("drvIntNetAsyncIoRun: %-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
447 cbFrame, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
448 pThis->u64LastReceiveTS = u64Now;
449 Log2(("drvIntNetAsyncIoRun: cbFrame=%#x\n"
450 "%.*Rhxd\n",
451 cbFrame, cbFrame, INTNETHdrGetFramePtr(pHdr, pBuf)));
452#endif
453 rc = pThis->pPort->pfnReceive(pThis->pPort, INTNETHdrGetFramePtr(pHdr, pBuf), cbFrame);
454 AssertRC(rc);
455
456 /* skip to the next frame. */
457 INTNETRingSkipFrame(pBuf, pRingBuf);
458 }
459 else
460 {
461 /*
462 * Wait for sufficient space to become available and then retry.
463 */
464 rc = drvIntNetAsyncIoWaitForSpace(pThis);
465 if (RT_FAILURE(rc))
466 {
467 if (rc == VERR_INTERRUPTED)
468 {
469 /*
470 * NIC is going down, likely because the VM is being reset. Skip the frame.
471 */
472 AssertMsg(pHdr->u16Type == INTNETHDR_TYPE_FRAME, ("Unknown frame type %RX16! offRead=%#x\n",
473 pHdr->u16Type, pRingBuf->offRead));
474 INTNETRingSkipFrame(pBuf, pRingBuf);
475 }
476 else
477 {
478 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
479 LogFlow(("drvIntNetAsyncIoRun: returns %Rrc (wait-for-space)\n", rc));
480 return rc;
481 }
482 }
483 }
484 }
485 else
486 {
487 /*
488 * Link down or unknown frame - skip to the next frame.
489 */
490 AssertMsg(pHdr->u16Type == INTNETHDR_TYPE_FRAME, ("Unknown frame type %RX16! offRead=%#x\n",
491 pHdr->u16Type, pRingBuf->offRead));
492 INTNETRingSkipFrame(pBuf, pRingBuf);
493 }
494 } /* while more received data */
495
496 /*
497 * Wait for data, checking the state before we block.
498 */
499 if (pThis->enmState != ASYNCSTATE_RUNNING)
500 {
501 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
502 LogFlow(("drvIntNetAsyncIoRun: returns VINF_SUCCESS (state changed - #1)\n"));
503 return VERR_STATE_CHANGED;
504 }
505 INTNETIFWAITREQ WaitReq;
506 WaitReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
507 WaitReq.Hdr.cbReq = sizeof(WaitReq);
508 WaitReq.pSession = NIL_RTR0PTR;
509 WaitReq.hIf = pThis->hIf;
510 WaitReq.cMillies = 30000; /* 30s - don't wait forever, timeout now and then. */
511 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
512 int rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_WAIT, &WaitReq, sizeof(WaitReq));
513 if ( RT_FAILURE(rc)
514 && rc != VERR_TIMEOUT
515 && rc != VERR_INTERRUPTED)
516 {
517 LogFlow(("drvIntNetAsyncIoRun: returns %Rrc\n", rc));
518 return rc;
519 }
520 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
521 }
522}
523
524
525/**
526 * Asynchronous I/O thread for handling receive.
527 *
528 * @returns VINF_SUCCESS (ignored).
529 * @param ThreadSelf Thread handle.
530 * @param pvUser Pointer to a DRVINTNET structure.
531 */
532static DECLCALLBACK(int) drvIntNetAsyncIoThread(RTTHREAD ThreadSelf, void *pvUser)
533{
534 PDRVINTNET pThis = (PDRVINTNET)pvUser;
535 LogFlow(("drvIntNetAsyncIoThread: pThis=%p\n", pThis));
536 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
537
538 /*
539 * The main loop - acting on state.
540 */
541 for (;;)
542 {
543 ASYNCSTATE enmState = pThis->enmState;
544 switch (enmState)
545 {
546 case ASYNCSTATE_SUSPENDED:
547 {
548 int rc = RTSemEventWait(pThis->EventSuspended, 30000);
549 if ( RT_FAILURE(rc)
550 && rc != VERR_TIMEOUT)
551 {
552 LogFlow(("drvIntNetAsyncIoThread: returns %Rrc\n", rc));
553 return rc;
554 }
555 break;
556 }
557
558 case ASYNCSTATE_RUNNING:
559 {
560 int rc = drvIntNetAsyncIoRun(pThis);
561 if ( rc != VERR_STATE_CHANGED
562 && RT_FAILURE(rc))
563 {
564 LogFlow(("drvIntNetAsyncIoThread: returns %Rrc\n", rc));
565 return rc;
566 }
567 break;
568 }
569
570 default:
571 AssertMsgFailed(("Invalid state %d\n", enmState));
572 case ASYNCSTATE_TERMINATE:
573 LogFlow(("drvIntNetAsyncIoThread: returns VINF_SUCCESS\n"));
574 return VINF_SUCCESS;
575 }
576 }
577}
578
579
580/**
581 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
582 */
583static DECLCALLBACK(void *) drvIntNetQueryInterface(PPDMIBASE pInterface, const char *pszIID)
584{
585 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
586 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
587
588 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
589 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONNECTOR, &pThis->INetworkConnector);
590 return NULL;
591}
592
593
594/**
595 * Power Off notification.
596 *
597 * @param pDrvIns The driver instance.
598 */
599static DECLCALLBACK(void) drvIntNetPowerOff(PPDMDRVINS pDrvIns)
600{
601 LogFlow(("drvIntNetPowerOff\n"));
602 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
603 if (!pThis->fActivateEarlyDeactivateLate)
604 {
605 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
606 drvIntNetSetActive(pThis, false /* fActive */);
607 }
608}
609
610
611/**
612 * Resume notification.
613 *
614 * @param pDrvIns The driver instance.
615 */
616static DECLCALLBACK(void) drvIntNetResume(PPDMDRVINS pDrvIns)
617{
618 LogFlow(("drvIntNetPowerResume\n"));
619 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
620 if (!pThis->fActivateEarlyDeactivateLate)
621 {
622 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
623 RTSemEventSignal(pThis->EventSuspended);
624 drvIntNetUpdateMacAddress(pThis); /* (could be a state restore) */
625 drvIntNetSetActive(pThis, true /* fActive */);
626 }
627 if ( PDMDrvHlpVMTeleportedAndNotFullyResumedYet(pDrvIns)
628 && pThis->pConfigIf)
629 {
630 /*
631 * We've just been teleported and need to drop a hint to the switch
632 * since we're likely to have changed to a different port. We just
633 * push out some ethernet frame that doesn't mean anything to anyone.
634 * For this purpose ethertype 0x801e was chosen since it was registered
635 * to Sun (dunno what it is/was used for though).
636 */
637 union
638 {
639 RTNETETHERHDR Hdr;
640 uint8_t ab[128];
641 } Frame;
642 RT_ZERO(Frame);
643 Frame.Hdr.DstMac.au16[0] = 0xffff;
644 Frame.Hdr.DstMac.au16[1] = 0xffff;
645 Frame.Hdr.DstMac.au16[2] = 0xffff;
646 Frame.Hdr.EtherType = RT_H2BE_U16(0x801e);
647 int rc = pThis->pConfigIf->pfnGetMac(pThis->pConfigIf, &Frame.Hdr.SrcMac);
648 if (RT_SUCCESS(rc))
649 rc = drvIntNetSend(&pThis->INetworkConnector, &Frame, sizeof(Frame));
650 if (RT_FAILURE(rc))
651 LogRel(("IntNet#%u: Sending dummy frame failed: %Rrc\n", pDrvIns->iInstance, rc));
652 }
653}
654
655
656/**
657 * Suspend notification.
658 *
659 * @param pDrvIns The driver instance.
660 */
661static DECLCALLBACK(void) drvIntNetSuspend(PPDMDRVINS pDrvIns)
662{
663 LogFlow(("drvIntNetPowerSuspend\n"));
664 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
665 if (!pThis->fActivateEarlyDeactivateLate)
666 {
667 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
668 drvIntNetSetActive(pThis, false /* fActive */);
669 }
670}
671
672
673/**
674 * Power On notification.
675 *
676 * @param pDrvIns The driver instance.
677 */
678static DECLCALLBACK(void) drvIntNetPowerOn(PPDMDRVINS pDrvIns)
679{
680 LogFlow(("drvIntNetPowerOn\n"));
681 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
682 if (!pThis->fActivateEarlyDeactivateLate)
683 {
684 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
685 RTSemEventSignal(pThis->EventSuspended);
686 drvIntNetUpdateMacAddress(pThis);
687 drvIntNetSetActive(pThis, true /* fActive */);
688 }
689}
690
691
692/**
693 * Destruct a driver instance.
694 *
695 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
696 * resources can be freed correctly.
697 *
698 * @param pDrvIns The driver instance data.
699 */
700static DECLCALLBACK(void) drvIntNetDestruct(PPDMDRVINS pDrvIns)
701{
702 LogFlow(("drvIntNetDestruct\n"));
703 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
704
705 /*
706 * Indicate to the thread that it's time to quit.
707 */
708 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_TERMINATE);
709 ASMAtomicXchgSize(&pThis->fLinkDown, true);
710 RTSEMEVENT EventSuspended = pThis->EventSuspended;
711 pThis->EventSuspended = NIL_RTSEMEVENT;
712
713 /*
714 * Close the interface
715 */
716 if (pThis->hIf != INTNET_HANDLE_INVALID)
717 {
718 INTNETIFCLOSEREQ CloseReq;
719 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
720 CloseReq.Hdr.cbReq = sizeof(CloseReq);
721 CloseReq.pSession = NIL_RTR0PTR;
722 CloseReq.hIf = pThis->hIf;
723 pThis->hIf = INTNET_HANDLE_INVALID;
724 int rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_CLOSE, &CloseReq, sizeof(CloseReq));
725 AssertRC(rc);
726 }
727
728 /*
729 * Wait for the thread to terminate.
730 */
731 if (pThis->Thread != NIL_RTTHREAD)
732 {
733 if (EventSuspended != NIL_RTSEMEVENT)
734 RTSemEventSignal(EventSuspended);
735 int rc = RTThreadWait(pThis->Thread, 5000, NULL);
736 AssertRC(rc);
737 pThis->Thread = NIL_RTTHREAD;
738 }
739
740 /*
741 * Destroy the semaphores.
742 */
743 if (EventSuspended != NIL_RTSEMEVENT)
744 RTSemEventDestroy(EventSuspended);
745
746 /*
747 * Deregister statistics in case we're being detached.
748 */
749 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBuf->cbStatRecv);
750 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBuf->cbStatSend);
751 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBuf->cStatRecvs);
752 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBuf->cStatSends);
753 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBuf->cStatLost);
754 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBuf->cStatYieldsNok);
755#ifdef VBOX_WITH_STATISTICS
756 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceive);
757 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatTransmit);
758#endif
759}
760
761
762/**
763 * Construct a TAP network transport driver instance.
764 *
765 * @copydoc FNPDMDRVCONSTRUCT
766 */
767static DECLCALLBACK(int) drvIntNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
768{
769 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
770 bool f;
771
772 /*
773 * Init the static parts.
774 */
775 pThis->pDrvIns = pDrvIns;
776 pThis->hIf = INTNET_HANDLE_INVALID;
777 pThis->Thread = NIL_RTTHREAD;
778 pThis->EventSuspended = NIL_RTSEMEVENT;
779 pThis->enmState = ASYNCSTATE_SUSPENDED;
780 pThis->fActivateEarlyDeactivateLate = false;
781 /* IBase */
782 pDrvIns->IBase.pfnQueryInterface = drvIntNetQueryInterface;
783 /* INetwork */
784 pThis->INetworkConnector.pfnSend = drvIntNetSend;
785 pThis->INetworkConnector.pfnSetPromiscuousMode = drvIntNetSetPromiscuousMode;
786 pThis->INetworkConnector.pfnNotifyLinkChanged = drvIntNetNotifyLinkChanged;
787
788 /*
789 * Validate the config.
790 */
791 if (!CFGMR3AreValuesValid(pCfgHandle,
792 "Network\0"
793 "Trunk\0"
794 "TrunkType\0"
795 "ReceiveBufferSize\0"
796 "SendBufferSize\0"
797 "RestrictAccess\0"
798 "SharedMacOnWire\0"
799 "IgnoreAllPromisc\0"
800 "QuietlyIgnoreAllPromisc\0"
801 "IgnoreClientPromisc\0"
802 "QuietlyIgnoreClientPromisc\0"
803 "IgnoreTrunkWirePromisc\0"
804 "QuietlyIgnoreTrunkWirePromisc\0"
805 "IgnoreTrunkHostPromisc\0"
806 "QuietlyIgnoreTrunkHostPromisc\0"
807 "IsService\0"))
808 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
809
810 /*
811 * Check that no-one is attached to us.
812 */
813 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
814 ("Configuration error: Not possible to attach anything to this driver!\n"),
815 VERR_PDM_DRVINS_NO_ATTACH);
816
817 /*
818 * Query the network port interface.
819 */
820 pThis->pPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKPORT);
821 if (!pThis->pPort)
822 {
823 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
824 return VERR_PDM_MISSING_INTERFACE_ABOVE;
825 }
826 pThis->pConfigIf = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
827
828 /*
829 * Read the configuration.
830 */
831 INTNETOPENREQ OpenReq;
832 memset(&OpenReq, 0, sizeof(OpenReq));
833 OpenReq.Hdr.cbReq = sizeof(OpenReq);
834 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
835 OpenReq.pSession = NIL_RTR0PTR;
836
837 /** @cfgm{Network, string}
838 * The name of the internal network to connect to.
839 */
840 int rc = CFGMR3QueryString(pCfgHandle, "Network", OpenReq.szNetwork, sizeof(OpenReq.szNetwork));
841 if (RT_FAILURE(rc))
842 return PDMDRV_SET_ERROR(pDrvIns, rc,
843 N_("Configuration error: Failed to get the \"Network\" value"));
844 strcpy(pThis->szNetwork, OpenReq.szNetwork);
845
846 /** @cfgm{TrunkType, uint32_t, kIntNetTrunkType_None}
847 * The trunk connection type see INTNETTRUNKTYPE.
848 */
849 uint32_t u32TrunkType;
850 rc = CFGMR3QueryU32(pCfgHandle, "TrunkType", &u32TrunkType);
851 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
852 u32TrunkType = kIntNetTrunkType_None;
853 else if (RT_FAILURE(rc))
854 return PDMDRV_SET_ERROR(pDrvIns, rc,
855 N_("Configuration error: Failed to get the \"TrunkType\" value"));
856 OpenReq.enmTrunkType = (INTNETTRUNKTYPE)u32TrunkType;
857
858 /** @cfgm{Trunk, string, ""}
859 * The name of the trunk connection.
860 */
861 rc = CFGMR3QueryString(pCfgHandle, "Trunk", OpenReq.szTrunk, sizeof(OpenReq.szTrunk));
862 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
863 OpenReq.szTrunk[0] = '\0';
864 else if (RT_FAILURE(rc))
865 return PDMDRV_SET_ERROR(pDrvIns, rc,
866 N_("Configuration error: Failed to get the \"Trunk\" value"));
867
868 /** @cfgm{RestrictAccess, boolean, true}
869 * Whether to restrict the access to the network or if it should be public. Everyone on
870 * the computer can connect to a public network. Don't change this.
871 */
872 bool fRestrictAccess;
873 rc = CFGMR3QueryBool(pCfgHandle, "RestrictAccess", &fRestrictAccess);
874 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
875 fRestrictAccess = true;
876 else if (RT_FAILURE(rc))
877 return PDMDRV_SET_ERROR(pDrvIns, rc,
878 N_("Configuration error: Failed to get the \"RestrictAccess\" value"));
879 OpenReq.fFlags = fRestrictAccess ? 0 : INTNET_OPEN_FLAGS_PUBLIC;
880
881 /** @cfgm{IgnoreAllPromisc, boolean, false}
882 * When set all request for operating any interface or trunk in promiscuous
883 * mode will be ignored. */
884 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreAllPromisc", &f, false);
885 if (RT_FAILURE(rc))
886 return PDMDRV_SET_ERROR(pDrvIns, rc,
887 N_("Configuration error: Failed to get the \"IgnoreAllPromisc\" value"));
888 if (f)
889 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC;
890
891 /** @cfgm{QuietlyIgnoreAllPromisc, boolean, false}
892 * When set all request for operating any interface or trunk in promiscuous
893 * mode will be ignored. This differs from IgnoreAllPromisc in that clients
894 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
895 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreAllPromisc", &f, false);
896 if (RT_FAILURE(rc))
897 return PDMDRV_SET_ERROR(pDrvIns, rc,
898 N_("Configuration error: Failed to get the \"QuietlyIgnoreAllPromisc\" value"));
899 if (f)
900 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC;
901
902 /** @cfgm{IgnoreClientPromisc, boolean, false}
903 * When set all request for operating any non-trunk interface in promiscuous
904 * mode will be ignored. */
905 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreClientPromisc", &f, false);
906 if (RT_FAILURE(rc))
907 return PDMDRV_SET_ERROR(pDrvIns, rc,
908 N_("Configuration error: Failed to get the \"IgnoreClientPromisc\" value"));
909 if (f)
910 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC; /** @todo add special flag for this. */
911
912 /** @cfgm{QuietlyIgnoreClientPromisc, boolean, false}
913 * When set all request for operating any non-trunk interface promiscuous mode
914 * will be ignored. This differs from IgnoreClientPromisc in that clients won't
915 * get VERR_INTNET_INCOMPATIBLE_FLAGS. */
916 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreClientPromisc", &f, false);
917 if (RT_FAILURE(rc))
918 return PDMDRV_SET_ERROR(pDrvIns, rc,
919 N_("Configuration error: Failed to get the \"QuietlyIgnoreClientPromisc\" value"));
920 if (f)
921 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC; /** @todo add special flag for this. */
922
923 /** @cfgm{IgnoreTrunkWirePromisc, boolean, false}
924 * When set all request for operating the trunk-wire connection in promiscuous
925 * mode will be ignored. */
926 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreTrunkWirePromisc", &f, false);
927 if (RT_FAILURE(rc))
928 return PDMDRV_SET_ERROR(pDrvIns, rc,
929 N_("Configuration error: Failed to get the \"IgnoreTrunkWirePromisc\" value"));
930 if (f)
931 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE;
932
933 /** @cfgm{QuietlyIgnoreTrunkWirePromisc, boolean, false}
934 * When set all request for operating any trunk-wire connection promiscuous mode
935 * will be ignored. This differs from IgnoreTrunkWirePromisc in that clients
936 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
937 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreTrunkWirePromisc", &f, false);
938 if (RT_FAILURE(rc))
939 return PDMDRV_SET_ERROR(pDrvIns, rc,
940 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkWirePromisc\" value"));
941 if (f)
942 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE;
943
944 /** @cfgm{IgnoreTrunkHostPromisc, boolean, false}
945 * When set all request for operating the trunk-host connection in promiscuous
946 * mode will be ignored. */
947 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreTrunkHostPromisc", &f, false);
948 if (RT_FAILURE(rc))
949 return PDMDRV_SET_ERROR(pDrvIns, rc,
950 N_("Configuration error: Failed to get the \"IgnoreTrunkHostPromisc\" value"));
951 if (f)
952 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST;
953
954 /** @cfgm{QuietlyIgnoreTrunkHostPromisc, boolean, false}
955 * When set all request for operating any trunk-host connection promiscuous mode
956 * will be ignored. This differs from IgnoreTrunkHostPromisc in that clients
957 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
958 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreTrunkHostPromisc", &f, false);
959 if (RT_FAILURE(rc))
960 return PDMDRV_SET_ERROR(pDrvIns, rc,
961 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkHostPromisc\" value"));
962 if (f)
963 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST;
964
965 /** @todo flags for not sending to the host and for setting the trunk-wire
966 * connection in promiscuous mode. */
967
968
969 /** @cfgm{SharedMacOnWire, boolean, false}
970 * Whether to shared the MAC address of the host interface when using the wire. When
971 * attaching to a wireless NIC this option is usally a requirement.
972 */
973 bool fSharedMacOnWire;
974 rc = CFGMR3QueryBoolDef(pCfgHandle, "SharedMacOnWire", &fSharedMacOnWire, false);
975 if (RT_FAILURE(rc))
976 return PDMDRV_SET_ERROR(pDrvIns, rc,
977 N_("Configuration error: Failed to get the \"SharedMacOnWire\" value"));
978 if (fSharedMacOnWire)
979 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
980
981 /** @cfgm{ReceiveBufferSize, uint32_t, 218 KB}
982 * The size of the receive buffer.
983 */
984 rc = CFGMR3QueryU32(pCfgHandle, "ReceiveBufferSize", &OpenReq.cbRecv);
985 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
986 OpenReq.cbRecv = 218 * _1K ;
987 else if (RT_FAILURE(rc))
988 return PDMDRV_SET_ERROR(pDrvIns, rc,
989 N_("Configuration error: Failed to get the \"ReceiveBufferSize\" value"));
990
991 /** @cfgm{SendBufferSize, uint32_t, 36 KB}
992 * The size of the send (transmit) buffer.
993 * This should be more than twice the size of the larges frame size because
994 * the ring buffer is very simple and doesn't support splitting up frames
995 * nor inserting padding. So, if this is too close to the frame size the
996 * header will fragment the buffer such that the frame won't fit on either
997 * side of it and the code will get very upset about it all.
998 */
999 rc = CFGMR3QueryU32(pCfgHandle, "SendBufferSize", &OpenReq.cbSend);
1000 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1001 OpenReq.cbSend = 36*_1K;
1002 else if (RT_FAILURE(rc))
1003 return PDMDRV_SET_ERROR(pDrvIns, rc,
1004 N_("Configuration error: Failed to get the \"SendBufferSize\" value"));
1005 if (OpenReq.cbSend < 32)
1006 return PDMDRV_SET_ERROR(pDrvIns, rc,
1007 N_("Configuration error: The \"SendBufferSize\" value is too small"));
1008 if (OpenReq.cbSend < 16384*2 + 64)
1009 LogRel(("DrvIntNet: Warning! SendBufferSize=%u, Recommended minimum size %u butes.\n", OpenReq.cbSend, 16384*2 + 64));
1010
1011 /** @cfgm{IsService, boolean, true}
1012 * This alterns the way the thread is suspended and resumed. When it's being used by
1013 * a service such as LWIP/iSCSI it shouldn't suspend immediately like for a NIC.
1014 */
1015 rc = CFGMR3QueryBool(pCfgHandle, "IsService", &pThis->fActivateEarlyDeactivateLate);
1016 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1017 pThis->fActivateEarlyDeactivateLate = false;
1018 else if (RT_FAILURE(rc))
1019 return PDMDRV_SET_ERROR(pDrvIns, rc,
1020 N_("Configuration error: Failed to get the \"IsService\" value"));
1021
1022 LogRel(("IntNet#%u: szNetwork={%s} enmTrunkType=%d szTrunk={%s} fFlags=%#x cbRecv=%u cbSend=%u\n",
1023 pDrvIns->iInstance, OpenReq.szNetwork, OpenReq.enmTrunkType, OpenReq.szTrunk, OpenReq.fFlags,
1024 OpenReq.cbRecv, OpenReq.cbSend));
1025
1026#ifdef RT_OS_DARWIN
1027 /* Temporary hack: attach to a network with the name 'if=en0' and you're hitting the wire. */
1028 if ( !OpenReq.szTrunk[0]
1029 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1030 && !strncmp(pThis->szNetwork, "if=en", sizeof("if=en") - 1)
1031 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("if=en") - 1])
1032 && !pThis->szNetwork[sizeof("if=en")])
1033 {
1034 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1035 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("if=") - 1]);
1036 }
1037 /* Temporary hack: attach to a network with the name 'wif=en0' and you're on the air. */
1038 if ( !OpenReq.szTrunk[0]
1039 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1040 && !strncmp(pThis->szNetwork, "wif=en", sizeof("wif=en") - 1)
1041 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("wif=en") - 1])
1042 && !pThis->szNetwork[sizeof("wif=en")])
1043 {
1044 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1045 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1046 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("wif=") - 1]);
1047 }
1048#endif /* DARWIN */
1049
1050 /*
1051 * Create the event semaphores
1052 */
1053 rc = RTSemEventCreate(&pThis->EventSuspended);
1054 if (RT_FAILURE(rc))
1055 return rc;
1056
1057 /*
1058 * Create the interface.
1059 */
1060 OpenReq.hIf = INTNET_HANDLE_INVALID;
1061 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_OPEN, &OpenReq, sizeof(OpenReq));
1062 if (RT_FAILURE(rc))
1063 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1064 N_("Failed to open/create the internal network '%s'"), pThis->szNetwork);
1065 AssertRelease(OpenReq.hIf != INTNET_HANDLE_INVALID);
1066 pThis->hIf = OpenReq.hIf;
1067 Log(("IntNet%d: hIf=%RX32 '%s'\n", pDrvIns->iInstance, pThis->hIf, pThis->szNetwork));
1068
1069 /*
1070 * Get default buffer.
1071 */
1072 INTNETIFGETRING3BUFFERREQ GetRing3BufferReq;
1073 GetRing3BufferReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1074 GetRing3BufferReq.Hdr.cbReq = sizeof(GetRing3BufferReq);
1075 GetRing3BufferReq.pSession = NIL_RTR0PTR;
1076 GetRing3BufferReq.hIf = pThis->hIf;
1077 GetRing3BufferReq.pRing3Buf = NULL;
1078 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_GET_RING3_BUFFER, &GetRing3BufferReq, sizeof(GetRing3BufferReq));
1079 if (RT_FAILURE(rc))
1080 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1081 N_("Failed to get ring-3 buffer for the newly created interface to '%s'"), pThis->szNetwork);
1082 AssertRelease(VALID_PTR(GetRing3BufferReq.pRing3Buf));
1083 pThis->pBuf = GetRing3BufferReq.pRing3Buf;
1084
1085 /*
1086 * Create the async I/O thread.
1087 * Note! Using a PDM thread here doesn't fit with the IsService=true operation.
1088 */
1089 rc = RTThreadCreate(&pThis->Thread, drvIntNetAsyncIoThread, pThis, _128K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET");
1090 if (RT_FAILURE(rc))
1091 {
1092 AssertRC(rc);
1093 return rc;
1094 }
1095
1096 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cbStatRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Net/IntNet%d/Bytes/Received", pDrvIns->iInstance);
1097 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cbStatSend, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Net/IntNet%d/Bytes/Sent", pDrvIns->iInstance);
1098 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatRecvs, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of received packets.", "/Net/IntNet%d/Packets/Received", pDrvIns->iInstance);
1099 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatSends, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of sent packets.", "/Net/IntNet%d/Packets/Sent", pDrvIns->iInstance);
1100 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatLost, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of sent packets.", "/Net/IntNet%d/Packets/Lost", pDrvIns->iInstance);
1101 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatYieldsNok, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of times yielding didn't help fix an overflow.", "/Net/IntNet%d/YieldNok", pDrvIns->iInstance);
1102#ifdef VBOX_WITH_STATISTICS
1103 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Net/IntNet%d/Receive", pDrvIns->iInstance);
1104 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Net/IntNet%d/Transmit", pDrvIns->iInstance);
1105#endif
1106
1107 /*
1108 * Activate data transmission as early as possible
1109 */
1110 if (pThis->fActivateEarlyDeactivateLate)
1111 {
1112 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
1113 RTSemEventSignal(pThis->EventSuspended);
1114 drvIntNetUpdateMacAddress(pThis);
1115 drvIntNetSetActive(pThis, true /* fActive */);
1116 }
1117
1118 return rc;
1119}
1120
1121
1122/**
1123 * Internal networking transport driver registration record.
1124 */
1125const PDMDRVREG g_DrvIntNet =
1126{
1127 /* u32Version */
1128 PDM_DRVREG_VERSION,
1129 /* szDriverName */
1130 "IntNet",
1131 /* szRCMod */
1132 "",
1133 /* szR0Mod */
1134 "",
1135 /* pszDescription */
1136 "Internal Networking Transport Driver",
1137 /* fFlags */
1138 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1139 /* fClass. */
1140 PDM_DRVREG_CLASS_NETWORK,
1141 /* cMaxInstances */
1142 ~0,
1143 /* cbInstance */
1144 sizeof(DRVINTNET),
1145 /* pfnConstruct */
1146 drvIntNetConstruct,
1147 /* pfnDestruct */
1148 drvIntNetDestruct,
1149 /* pfnRelocate */
1150 NULL,
1151 /* pfnIOCtl */
1152 NULL,
1153 /* pfnPowerOn */
1154 drvIntNetPowerOn,
1155 /* pfnReset */
1156 NULL,
1157 /* pfnSuspend */
1158 drvIntNetSuspend,
1159 /* pfnResume */
1160 drvIntNetResume,
1161 /* pfnAttach */
1162 NULL,
1163 /* pfnDetach */
1164 NULL,
1165 /* pfnPowerOff */
1166 drvIntNetPowerOff,
1167 /* pfnSoftReset */
1168 NULL,
1169 /* u32EndVersion */
1170 PDM_DRVREG_VERSION
1171};
1172
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