VirtualBox

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

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

typo.

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