VirtualBox

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

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

DrvIntNet.cpp: Preparing for R0/RC.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.0 KB
Line 
1/* $Id: DrvIntNet.cpp 25993 2010-01-25 11:04:09Z 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
714 /*
715 * Indicate to the thread that it's time to quit.
716 */
717 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_TERMINATE);
718 ASMAtomicXchgSize(&pThis->fLinkDown, true);
719 RTSEMEVENT EventSuspended = pThis->EventSuspended;
720 pThis->EventSuspended = NIL_RTSEMEVENT;
721
722 /*
723 * Close the interface
724 */
725 if (pThis->hIf != INTNET_HANDLE_INVALID)
726 {
727 INTNETIFCLOSEREQ CloseReq;
728 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
729 CloseReq.Hdr.cbReq = sizeof(CloseReq);
730 CloseReq.pSession = NIL_RTR0PTR;
731 CloseReq.hIf = pThis->hIf;
732 pThis->hIf = INTNET_HANDLE_INVALID;
733 int rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_CLOSE, &CloseReq, sizeof(CloseReq));
734 AssertRC(rc);
735 }
736
737 /*
738 * Wait for the thread to terminate.
739 */
740 if (pThis->Thread != NIL_RTTHREAD)
741 {
742 if (EventSuspended != NIL_RTSEMEVENT)
743 RTSemEventSignal(EventSuspended);
744 int rc = RTThreadWait(pThis->Thread, 5000, NULL);
745 AssertRC(rc);
746 pThis->Thread = NIL_RTTHREAD;
747 }
748
749 /*
750 * Destroy the semaphores.
751 */
752 if (EventSuspended != NIL_RTSEMEVENT)
753 RTSemEventDestroy(EventSuspended);
754
755 /*
756 * Deregister statistics in case we're being detached.
757 */
758 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cbStatRecv);
759 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cbStatSend);
760 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatRecvs);
761 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatSends);
762 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatLost);
763 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->pBufR3->cStatYieldsNok);
764#ifdef VBOX_WITH_STATISTICS
765 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceive);
766 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatTransmit);
767#endif
768}
769
770
771/**
772 * Construct a TAP network transport driver instance.
773 *
774 * @copydoc FNPDMDRVCONSTRUCT
775 */
776static DECLCALLBACK(int) drvR3IntNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle, uint32_t fFlags)
777{
778 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
779 bool f;
780
781 /*
782 * Init the static parts.
783 */
784 pThis->pDrvInsR3 = pDrvIns;
785 pThis->hIf = INTNET_HANDLE_INVALID;
786 pThis->Thread = NIL_RTTHREAD;
787 pThis->EventSuspended = NIL_RTSEMEVENT;
788 pThis->enmState = ASYNCSTATE_SUSPENDED;
789 pThis->fActivateEarlyDeactivateLate = false;
790 /* IBase */
791 pDrvIns->IBase.pfnQueryInterface = drvR3IntNetQueryInterface;
792 /* INetwork */
793 pThis->INetworkConnectorR3.pfnSend = drvR3IntNetSend;
794 pThis->INetworkConnectorR3.pfnSetPromiscuousMode= drvR3IntNetSetPromiscuousMode;
795 pThis->INetworkConnectorR3.pfnNotifyLinkChanged = drvR3IntNetNotifyLinkChanged;
796
797 /*
798 * Validate the config.
799 */
800 if (!CFGMR3AreValuesValid(pCfgHandle,
801 "Network\0"
802 "Trunk\0"
803 "TrunkType\0"
804 "ReceiveBufferSize\0"
805 "SendBufferSize\0"
806 "RestrictAccess\0"
807 "SharedMacOnWire\0"
808 "IgnoreAllPromisc\0"
809 "QuietlyIgnoreAllPromisc\0"
810 "IgnoreClientPromisc\0"
811 "QuietlyIgnoreClientPromisc\0"
812 "IgnoreTrunkWirePromisc\0"
813 "QuietlyIgnoreTrunkWirePromisc\0"
814 "IgnoreTrunkHostPromisc\0"
815 "QuietlyIgnoreTrunkHostPromisc\0"
816 "IsService\0"))
817 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
818
819 /*
820 * Check that no-one is attached to us.
821 */
822 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
823 ("Configuration error: Not possible to attach anything to this driver!\n"),
824 VERR_PDM_DRVINS_NO_ATTACH);
825
826 /*
827 * Query the network port interface.
828 */
829 pThis->pIPortR3 = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKPORT);
830 if (!pThis->pIPortR3)
831 {
832 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
833 return VERR_PDM_MISSING_INTERFACE_ABOVE;
834 }
835 pThis->pIConfigIfR3 = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
836
837 /*
838 * Read the configuration.
839 */
840 INTNETOPENREQ OpenReq;
841 memset(&OpenReq, 0, sizeof(OpenReq));
842 OpenReq.Hdr.cbReq = sizeof(OpenReq);
843 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
844 OpenReq.pSession = NIL_RTR0PTR;
845
846 /** @cfgm{Network, string}
847 * The name of the internal network to connect to.
848 */
849 int rc = CFGMR3QueryString(pCfgHandle, "Network", OpenReq.szNetwork, sizeof(OpenReq.szNetwork));
850 if (RT_FAILURE(rc))
851 return PDMDRV_SET_ERROR(pDrvIns, rc,
852 N_("Configuration error: Failed to get the \"Network\" value"));
853 strcpy(pThis->szNetwork, OpenReq.szNetwork);
854
855 /** @cfgm{TrunkType, uint32_t, kIntNetTrunkType_None}
856 * The trunk connection type see INTNETTRUNKTYPE.
857 */
858 uint32_t u32TrunkType;
859 rc = CFGMR3QueryU32(pCfgHandle, "TrunkType", &u32TrunkType);
860 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
861 u32TrunkType = kIntNetTrunkType_None;
862 else if (RT_FAILURE(rc))
863 return PDMDRV_SET_ERROR(pDrvIns, rc,
864 N_("Configuration error: Failed to get the \"TrunkType\" value"));
865 OpenReq.enmTrunkType = (INTNETTRUNKTYPE)u32TrunkType;
866
867 /** @cfgm{Trunk, string, ""}
868 * The name of the trunk connection.
869 */
870 rc = CFGMR3QueryString(pCfgHandle, "Trunk", OpenReq.szTrunk, sizeof(OpenReq.szTrunk));
871 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
872 OpenReq.szTrunk[0] = '\0';
873 else if (RT_FAILURE(rc))
874 return PDMDRV_SET_ERROR(pDrvIns, rc,
875 N_("Configuration error: Failed to get the \"Trunk\" value"));
876
877 /** @cfgm{RestrictAccess, boolean, true}
878 * Whether to restrict the access to the network or if it should be public. Everyone on
879 * the computer can connect to a public network. Don't change this.
880 */
881 bool fRestrictAccess;
882 rc = CFGMR3QueryBool(pCfgHandle, "RestrictAccess", &fRestrictAccess);
883 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
884 fRestrictAccess = true;
885 else if (RT_FAILURE(rc))
886 return PDMDRV_SET_ERROR(pDrvIns, rc,
887 N_("Configuration error: Failed to get the \"RestrictAccess\" value"));
888 OpenReq.fFlags = fRestrictAccess ? 0 : INTNET_OPEN_FLAGS_PUBLIC;
889
890 /** @cfgm{IgnoreAllPromisc, boolean, false}
891 * When set all request for operating any interface or trunk in promiscuous
892 * mode will be ignored. */
893 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreAllPromisc", &f, false);
894 if (RT_FAILURE(rc))
895 return PDMDRV_SET_ERROR(pDrvIns, rc,
896 N_("Configuration error: Failed to get the \"IgnoreAllPromisc\" value"));
897 if (f)
898 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC;
899
900 /** @cfgm{QuietlyIgnoreAllPromisc, boolean, false}
901 * When set all request for operating any interface or trunk in promiscuous
902 * mode will be ignored. This differs from IgnoreAllPromisc in that clients
903 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
904 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreAllPromisc", &f, false);
905 if (RT_FAILURE(rc))
906 return PDMDRV_SET_ERROR(pDrvIns, rc,
907 N_("Configuration error: Failed to get the \"QuietlyIgnoreAllPromisc\" value"));
908 if (f)
909 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC;
910
911 /** @cfgm{IgnoreClientPromisc, boolean, false}
912 * When set all request for operating any non-trunk interface in promiscuous
913 * mode will be ignored. */
914 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreClientPromisc", &f, false);
915 if (RT_FAILURE(rc))
916 return PDMDRV_SET_ERROR(pDrvIns, rc,
917 N_("Configuration error: Failed to get the \"IgnoreClientPromisc\" value"));
918 if (f)
919 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC; /** @todo add special flag for this. */
920
921 /** @cfgm{QuietlyIgnoreClientPromisc, boolean, false}
922 * When set all request for operating any non-trunk interface promiscuous mode
923 * will be ignored. This differs from IgnoreClientPromisc in that clients won't
924 * get VERR_INTNET_INCOMPATIBLE_FLAGS. */
925 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreClientPromisc", &f, false);
926 if (RT_FAILURE(rc))
927 return PDMDRV_SET_ERROR(pDrvIns, rc,
928 N_("Configuration error: Failed to get the \"QuietlyIgnoreClientPromisc\" value"));
929 if (f)
930 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC; /** @todo add special flag for this. */
931
932 /** @cfgm{IgnoreTrunkWirePromisc, boolean, false}
933 * When set all request for operating the trunk-wire connection in promiscuous
934 * mode will be ignored. */
935 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreTrunkWirePromisc", &f, false);
936 if (RT_FAILURE(rc))
937 return PDMDRV_SET_ERROR(pDrvIns, rc,
938 N_("Configuration error: Failed to get the \"IgnoreTrunkWirePromisc\" value"));
939 if (f)
940 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE;
941
942 /** @cfgm{QuietlyIgnoreTrunkWirePromisc, boolean, false}
943 * When set all request for operating any trunk-wire connection promiscuous mode
944 * will be ignored. This differs from IgnoreTrunkWirePromisc in that clients
945 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
946 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreTrunkWirePromisc", &f, false);
947 if (RT_FAILURE(rc))
948 return PDMDRV_SET_ERROR(pDrvIns, rc,
949 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkWirePromisc\" value"));
950 if (f)
951 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE;
952
953 /** @cfgm{IgnoreTrunkHostPromisc, boolean, false}
954 * When set all request for operating the trunk-host connection in promiscuous
955 * mode will be ignored. */
956 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreTrunkHostPromisc", &f, false);
957 if (RT_FAILURE(rc))
958 return PDMDRV_SET_ERROR(pDrvIns, rc,
959 N_("Configuration error: Failed to get the \"IgnoreTrunkHostPromisc\" value"));
960 if (f)
961 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST;
962
963 /** @cfgm{QuietlyIgnoreTrunkHostPromisc, boolean, false}
964 * When set all request for operating any trunk-host connection promiscuous mode
965 * will be ignored. This differs from IgnoreTrunkHostPromisc in that clients
966 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
967 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreTrunkHostPromisc", &f, false);
968 if (RT_FAILURE(rc))
969 return PDMDRV_SET_ERROR(pDrvIns, rc,
970 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkHostPromisc\" value"));
971 if (f)
972 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST;
973
974 /** @todo flags for not sending to the host and for setting the trunk-wire
975 * connection in promiscuous mode. */
976
977
978 /** @cfgm{SharedMacOnWire, boolean, false}
979 * Whether to shared the MAC address of the host interface when using the wire. When
980 * attaching to a wireless NIC this option is usally a requirement.
981 */
982 bool fSharedMacOnWire;
983 rc = CFGMR3QueryBoolDef(pCfgHandle, "SharedMacOnWire", &fSharedMacOnWire, false);
984 if (RT_FAILURE(rc))
985 return PDMDRV_SET_ERROR(pDrvIns, rc,
986 N_("Configuration error: Failed to get the \"SharedMacOnWire\" value"));
987 if (fSharedMacOnWire)
988 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
989
990 /** @cfgm{ReceiveBufferSize, uint32_t, 218 KB}
991 * The size of the receive buffer.
992 */
993 rc = CFGMR3QueryU32(pCfgHandle, "ReceiveBufferSize", &OpenReq.cbRecv);
994 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
995 OpenReq.cbRecv = 218 * _1K ;
996 else if (RT_FAILURE(rc))
997 return PDMDRV_SET_ERROR(pDrvIns, rc,
998 N_("Configuration error: Failed to get the \"ReceiveBufferSize\" value"));
999
1000 /** @cfgm{SendBufferSize, uint32_t, 36 KB}
1001 * The size of the send (transmit) buffer.
1002 * This should be more than twice the size of the larges frame size because
1003 * the ring buffer is very simple and doesn't support splitting up frames
1004 * nor inserting padding. So, if this is too close to the frame size the
1005 * header will fragment the buffer such that the frame won't fit on either
1006 * side of it and the code will get very upset about it all.
1007 */
1008 rc = CFGMR3QueryU32(pCfgHandle, "SendBufferSize", &OpenReq.cbSend);
1009 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1010 OpenReq.cbSend = 36*_1K;
1011 else if (RT_FAILURE(rc))
1012 return PDMDRV_SET_ERROR(pDrvIns, rc,
1013 N_("Configuration error: Failed to get the \"SendBufferSize\" value"));
1014 if (OpenReq.cbSend < 32)
1015 return PDMDRV_SET_ERROR(pDrvIns, rc,
1016 N_("Configuration error: The \"SendBufferSize\" value is too small"));
1017 if (OpenReq.cbSend < 16384*2 + 64)
1018 LogRel(("DrvIntNet: Warning! SendBufferSize=%u, Recommended minimum size %u butes.\n", OpenReq.cbSend, 16384*2 + 64));
1019
1020 /** @cfgm{IsService, boolean, true}
1021 * This alterns the way the thread is suspended and resumed. When it's being used by
1022 * a service such as LWIP/iSCSI it shouldn't suspend immediately like for a NIC.
1023 */
1024 rc = CFGMR3QueryBool(pCfgHandle, "IsService", &pThis->fActivateEarlyDeactivateLate);
1025 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1026 pThis->fActivateEarlyDeactivateLate = false;
1027 else if (RT_FAILURE(rc))
1028 return PDMDRV_SET_ERROR(pDrvIns, rc,
1029 N_("Configuration error: Failed to get the \"IsService\" value"));
1030
1031 LogRel(("IntNet#%u: szNetwork={%s} enmTrunkType=%d szTrunk={%s} fFlags=%#x cbRecv=%u cbSend=%u\n",
1032 pDrvIns->iInstance, OpenReq.szNetwork, OpenReq.enmTrunkType, OpenReq.szTrunk, OpenReq.fFlags,
1033 OpenReq.cbRecv, OpenReq.cbSend));
1034
1035#ifdef RT_OS_DARWIN
1036 /* Temporary hack: attach to a network with the name 'if=en0' and you're hitting the wire. */
1037 if ( !OpenReq.szTrunk[0]
1038 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1039 && !strncmp(pThis->szNetwork, "if=en", sizeof("if=en") - 1)
1040 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("if=en") - 1])
1041 && !pThis->szNetwork[sizeof("if=en")])
1042 {
1043 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1044 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("if=") - 1]);
1045 }
1046 /* Temporary hack: attach to a network with the name 'wif=en0' and you're on the air. */
1047 if ( !OpenReq.szTrunk[0]
1048 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1049 && !strncmp(pThis->szNetwork, "wif=en", sizeof("wif=en") - 1)
1050 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("wif=en") - 1])
1051 && !pThis->szNetwork[sizeof("wif=en")])
1052 {
1053 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1054 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1055 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("wif=") - 1]);
1056 }
1057#endif /* DARWIN */
1058
1059 /*
1060 * Create the event semaphores
1061 */
1062 rc = RTSemEventCreate(&pThis->EventSuspended);
1063 if (RT_FAILURE(rc))
1064 return rc;
1065
1066 /*
1067 * Create the interface.
1068 */
1069 OpenReq.hIf = INTNET_HANDLE_INVALID;
1070 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_OPEN, &OpenReq, sizeof(OpenReq));
1071 if (RT_FAILURE(rc))
1072 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1073 N_("Failed to open/create the internal network '%s'"), pThis->szNetwork);
1074 AssertRelease(OpenReq.hIf != INTNET_HANDLE_INVALID);
1075 pThis->hIf = OpenReq.hIf;
1076 Log(("IntNet%d: hIf=%RX32 '%s'\n", pDrvIns->iInstance, pThis->hIf, pThis->szNetwork));
1077
1078 /*
1079 * Get default buffer.
1080 */
1081 INTNETIFGETRING3BUFFERREQ GetRing3BufferReq;
1082 GetRing3BufferReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1083 GetRing3BufferReq.Hdr.cbReq = sizeof(GetRing3BufferReq);
1084 GetRing3BufferReq.pSession = NIL_RTR0PTR;
1085 GetRing3BufferReq.hIf = pThis->hIf;
1086 GetRing3BufferReq.pRing3Buf = NULL;
1087 rc = PDMDrvHlpSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_GET_RING3_BUFFER, &GetRing3BufferReq, sizeof(GetRing3BufferReq));
1088 if (RT_FAILURE(rc))
1089 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1090 N_("Failed to get ring-3 buffer for the newly created interface to '%s'"), pThis->szNetwork);
1091 AssertRelease(VALID_PTR(GetRing3BufferReq.pRing3Buf));
1092 pThis->pBufR3 = GetRing3BufferReq.pRing3Buf;
1093
1094 /*
1095 * Create the async I/O thread.
1096 * Note! Using a PDM thread here doesn't fit with the IsService=true operation.
1097 */
1098 rc = RTThreadCreate(&pThis->Thread, drvR3IntNetAsyncIoThread, pThis, _128K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET");
1099 if (RT_FAILURE(rc))
1100 {
1101 AssertRC(rc);
1102 return rc;
1103 }
1104
1105 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->cbStatRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Net/IntNet%d/Bytes/Received", pDrvIns->iInstance);
1106 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->cbStatSend, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Net/IntNet%d/Bytes/Sent", pDrvIns->iInstance);
1107 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->cStatRecvs, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of received packets.", "/Net/IntNet%d/Packets/Received", pDrvIns->iInstance);
1108 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->cStatSends, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of sent packets.", "/Net/IntNet%d/Packets/Sent", pDrvIns->iInstance);
1109 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBufR3->cStatLost, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Number of sent packets.", "/Net/IntNet%d/Packets/Lost", pDrvIns->iInstance);
1110 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);
1111#ifdef VBOX_WITH_STATISTICS
1112 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Net/IntNet%d/Receive", pDrvIns->iInstance);
1113 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Net/IntNet%d/Transmit", pDrvIns->iInstance);
1114#endif
1115
1116 /*
1117 * Activate data transmission as early as possible
1118 */
1119 if (pThis->fActivateEarlyDeactivateLate)
1120 {
1121 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
1122 RTSemEventSignal(pThis->EventSuspended);
1123 drvR3IntNetUpdateMacAddress(pThis);
1124 drvR3IntNetSetActive(pThis, true /* fActive */);
1125 }
1126
1127 return rc;
1128}
1129
1130
1131/**
1132 * Internal networking transport driver registration record.
1133 */
1134const PDMDRVREG g_DrvIntNet =
1135{
1136 /* u32Version */
1137 PDM_DRVREG_VERSION,
1138 /* szDriverName */
1139 "IntNet",
1140 /* szRCMod */
1141 "VBoxDD",
1142 /* szR0Mod */
1143 "VBoxDD",
1144 /* pszDescription */
1145 "Internal Networking Transport Driver",
1146 /* fFlags */
1147#ifdef VBOX_WITH_R0_AND_RC_DRIVERS
1148 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DRVREG_FLAGS_R0 | PDM_DRVREG_FLAGS_RC,
1149#else
1150 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1151#endif
1152 /* fClass. */
1153 PDM_DRVREG_CLASS_NETWORK,
1154 /* cMaxInstances */
1155 ~0,
1156 /* cbInstance */
1157 sizeof(DRVINTNET),
1158 /* pfnConstruct */
1159 drvR3IntNetConstruct,
1160 /* pfnDestruct */
1161 drvR3IntNetDestruct,
1162 /* pfnRelocate */
1163 NULL,
1164 /* pfnIOCtl */
1165 NULL,
1166 /* pfnPowerOn */
1167 drvR3IntNetPowerOn,
1168 /* pfnReset */
1169 NULL,
1170 /* pfnSuspend */
1171 drvR3IntNetSuspend,
1172 /* pfnResume */
1173 drvR3IntNetResume,
1174 /* pfnAttach */
1175 NULL,
1176 /* pfnDetach */
1177 NULL,
1178 /* pfnPowerOff */
1179 drvR3IntNetPowerOff,
1180 /* pfnSoftReset */
1181 NULL,
1182 /* u32EndVersion */
1183 PDM_DRVREG_VERSION
1184};
1185
1186#endif /* IN_RING3 */
1187
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