VirtualBox

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

Last change on this file since 18099 was 18099, checked in by vboxsync, 16 years ago

DHCP server: make it launched properly for internal networking

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 47.6 KB
Line 
1/* $Id: DrvIntNet.cpp 18099 2009-03-19 17:07:16Z 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.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/thread.h>
36#include <iprt/semaphore.h>
37#include <iprt/string.h>
38#include <iprt/time.h>
39#include <iprt/ctype.h>
40
41#include "../Builtins.h"
42
43#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
44# include "win/DrvIntNet-win.h"
45#endif
46
47#include "DHCPServerRunner.h"
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/**
53 * The state of the asynchronous thread.
54 */
55typedef enum ASYNCSTATE
56{
57 /** The thread is suspended. */
58 ASYNCSTATE_SUSPENDED = 1,
59 /** The thread is running. */
60 ASYNCSTATE_RUNNING,
61 /** The thread must (/has) terminate. */
62 ASYNCSTATE_TERMINATE,
63 /** The usual 32-bit type blowup. */
64 ASYNCSTATE_32BIT_HACK = 0x7fffffff
65} ASYNCSTATE;
66
67/**
68 * Block driver instance data.
69 */
70typedef struct DRVINTNET
71{
72 /** The network interface. */
73 PDMINETWORKCONNECTOR INetworkConnector;
74 /** The network interface. */
75 PPDMINETWORKPORT pPort;
76 /** The network config interface.
77 * Can (in theory at least) be NULL. */
78 PPDMINETWORKCONFIG pConfigIf;
79 /** Pointer to the driver instance. */
80 PPDMDRVINS pDrvIns;
81 /** Interface handle. */
82 INTNETIFHANDLE hIf;
83 /** Pointer to the communication buffer. */
84 PINTNETBUF pBuf;
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
98#ifdef VBOX_WITH_STATISTICS
99 /** Profiling packet transmit runs. */
100 STAMPROFILE StatTransmit;
101 /** Profiling packet receive runs. */
102 STAMPROFILEADV StatReceive;
103#endif /* VBOX_WITH_STATISTICS */
104
105#ifdef LOG_ENABLED
106 /** The nano ts of the last transfer. */
107 uint64_t u64LastTransferTS;
108 /** The nano ts of the last receive. */
109 uint64_t u64LastReceiveTS;
110#endif
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 = pThis->pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(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 = pThis->pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(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, 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 pThis->pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pThis->pDrvIns, VMMR0_DO_INTNET_IF_SEND, &SendReq, sizeof(SendReq));
305
306 rc = drvIntNetRingWriteFrame(pThis->pBuf, &pThis->pBuf->Send, pvBuf, 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 = pThis->pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(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 = pThis->pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(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 int 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 = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(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 * Queries an interface to the driver.
582 *
583 * @returns Pointer to interface.
584 * @returns NULL if the interface was not supported by the driver.
585 * @param pInterface Pointer to this interface structure.
586 * @param enmInterface The requested interface identification.
587 * @thread Any thread.
588 */
589static DECLCALLBACK(void *) drvIntNetQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
590{
591 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
592 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
593 switch (enmInterface)
594 {
595 case PDMINTERFACE_BASE:
596 return &pDrvIns->IBase;
597 case PDMINTERFACE_NETWORK_CONNECTOR:
598 return &pThis->INetworkConnector;
599 default:
600 return NULL;
601 }
602}
603
604
605/**
606 * Power Off notification.
607 *
608 * @param pDrvIns The driver instance.
609 */
610static DECLCALLBACK(void) drvIntNetPowerOff(PPDMDRVINS pDrvIns)
611{
612 LogFlow(("drvIntNetPowerOff\n"));
613 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
614 if (!pThis->fActivateEarlyDeactivateLate)
615 {
616 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
617 drvIntNetSetActive(pThis, false /* fActive */);
618 }
619}
620
621
622/**
623 * Resume notification.
624 *
625 * @param pDrvIns The driver instance.
626 */
627static DECLCALLBACK(void) drvIntNetResume(PPDMDRVINS pDrvIns)
628{
629 LogFlow(("drvIntNetPowerResume\n"));
630 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
631 if (!pThis->fActivateEarlyDeactivateLate)
632 {
633 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
634 RTSemEventSignal(pThis->EventSuspended);
635 drvIntNetUpdateMacAddress(pThis); /* (could be a state restore) */
636 drvIntNetSetActive(pThis, true /* fActive */);
637 }
638}
639
640
641/**
642 * Suspend notification.
643 *
644 * @param pDrvIns The driver instance.
645 */
646static DECLCALLBACK(void) drvIntNetSuspend(PPDMDRVINS pDrvIns)
647{
648 LogFlow(("drvIntNetPowerSuspend\n"));
649 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
650 if (!pThis->fActivateEarlyDeactivateLate)
651 {
652 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_SUSPENDED);
653 drvIntNetSetActive(pThis, false /* fActive */);
654 }
655}
656
657
658/**
659 * Power On notification.
660 *
661 * @param pDrvIns The driver instance.
662 */
663static DECLCALLBACK(void) drvIntNetPowerOn(PPDMDRVINS pDrvIns)
664{
665 LogFlow(("drvIntNetPowerOn\n"));
666 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
667 if (!pThis->fActivateEarlyDeactivateLate)
668 {
669 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
670 RTSemEventSignal(pThis->EventSuspended);
671 drvIntNetUpdateMacAddress(pThis);
672 drvIntNetSetActive(pThis, true /* fActive */);
673 }
674}
675
676
677/**
678 * Destruct a driver instance.
679 *
680 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
681 * resources can be freed correctly.
682 *
683 * @param pDrvIns The driver instance data.
684 */
685static DECLCALLBACK(void) drvIntNetDestruct(PPDMDRVINS pDrvIns)
686{
687 LogFlow(("drvIntNetDestruct\n"));
688 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
689
690 /*
691 * Indicate to the thread that it's time to quit.
692 */
693 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_TERMINATE);
694 ASMAtomicXchgSize(&pThis->fLinkDown, true);
695 RTSEMEVENT EventSuspended = pThis->EventSuspended;
696 pThis->EventSuspended = NIL_RTSEMEVENT;
697
698 /*
699 * Close the interface
700 */
701 if (pThis->hIf != INTNET_HANDLE_INVALID)
702 {
703 INTNETIFCLOSEREQ CloseReq;
704 CloseReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
705 CloseReq.Hdr.cbReq = sizeof(CloseReq);
706 CloseReq.pSession = NIL_RTR0PTR;
707 CloseReq.hIf = pThis->hIf;
708 pThis->hIf = INTNET_HANDLE_INVALID;
709 int rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_CLOSE, &CloseReq, sizeof(CloseReq));
710 AssertRC(rc);
711 }
712
713 /*
714 * Wait for the thread to terminate.
715 */
716 if (pThis->Thread != NIL_RTTHREAD)
717 {
718 if (EventSuspended != NIL_RTSEMEVENT)
719 RTSemEventSignal(EventSuspended);
720 int rc = RTThreadWait(pThis->Thread, 5000, NULL);
721 AssertRC(rc);
722 pThis->Thread = NIL_RTTHREAD;
723 }
724
725 /*
726 * Destroy the semaphores.
727 */
728 if (EventSuspended != NIL_RTSEMEVENT)
729 RTSemEventDestroy(EventSuspended);
730}
731
732
733/**
734 * Construct a TAP network transport driver instance.
735 *
736 * @returns VBox status.
737 * @param pDrvIns The driver instance data.
738 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
739 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
740 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
741 * iInstance it's expected to be used a bit in this function.
742 */
743static DECLCALLBACK(int) drvIntNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
744{
745 PDRVINTNET pThis = PDMINS_2_DATA(pDrvIns, PDRVINTNET);
746 bool f;
747
748 /*
749 * Init the static parts.
750 */
751 pThis->pDrvIns = pDrvIns;
752 pThis->hIf = INTNET_HANDLE_INVALID;
753 pThis->Thread = NIL_RTTHREAD;
754 pThis->EventSuspended = NIL_RTSEMEVENT;
755 pThis->enmState = ASYNCSTATE_SUSPENDED;
756 pThis->fActivateEarlyDeactivateLate = false;
757 /* IBase */
758 pDrvIns->IBase.pfnQueryInterface = drvIntNetQueryInterface;
759 /* INetwork */
760 pThis->INetworkConnector.pfnSend = drvIntNetSend;
761 pThis->INetworkConnector.pfnSetPromiscuousMode = drvIntNetSetPromiscuousMode;
762 pThis->INetworkConnector.pfnNotifyLinkChanged = drvIntNetNotifyLinkChanged;
763
764 /*
765 * Validate the config.
766 */
767 if (!CFGMR3AreValuesValid(pCfgHandle,
768 "Network\0"
769 "Trunk\0"
770 "TrunkType\0"
771 "ReceiveBufferSize\0"
772 "SendBufferSize\0"
773 "RestrictAccess\0"
774 "SharedMacOnWire\0"
775 "IgnoreAllPromisc\0"
776 "QuietlyIgnoreAllPromisc\0"
777 "IgnoreClientPromisc\0"
778 "QuietlyIgnoreClientPromisc\0"
779 "IgnoreTrunkWirePromisc\0"
780 "QuietlyIgnoreTrunkWirePromisc\0"
781 "IgnoreTrunkHostPromisc\0"
782 "QuietlyIgnoreTrunkHostPromisc\0"
783 "IsService\0"
784 "DhcpIPAddress\0"
785 "DhcpNetworkMask\0"
786 "DhcpLowerIP\0"
787 "DhcpUpperIP\0"
788 "DhcpMacAddress\0"))
789 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
790
791 /*
792 * Check that no-one is attached to us.
793 */
794 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, NULL);
795 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
796 {
797 AssertMsgFailed(("Configuration error: Cannot attach drivers to the TAP driver!\n"));
798 return VERR_PDM_DRVINS_NO_ATTACH;
799 }
800
801 /*
802 * Query the network port interface.
803 */
804 pThis->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
805 if (!pThis->pPort)
806 {
807 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
808 return VERR_PDM_MISSING_INTERFACE_ABOVE;
809 }
810 pThis->pConfigIf = (PPDMINETWORKCONFIG)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_CONFIG);
811
812 /*
813 * Read the configuration.
814 */
815 INTNETOPENREQ OpenReq;
816 memset(&OpenReq, 0, sizeof(OpenReq));
817 OpenReq.Hdr.cbReq = sizeof(OpenReq);
818 OpenReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
819 OpenReq.pSession = NIL_RTR0PTR;
820
821 /** @cfgm{Network, string}
822 * The name of the internal network to connect to.
823 */
824 rc = CFGMR3QueryString(pCfgHandle, "Network", OpenReq.szNetwork, sizeof(OpenReq.szNetwork));
825 if (RT_FAILURE(rc))
826 return PDMDRV_SET_ERROR(pDrvIns, rc,
827 N_("Configuration error: Failed to get the \"Network\" value"));
828 strcpy(pThis->szNetwork, OpenReq.szNetwork);
829
830 /** @cfgm{TrunkType, uint32_t, kIntNetTrunkType_None}
831 * The trunk connection type see INTNETTRUNKTYPE.
832 */
833 uint32_t u32TrunkType;
834 rc = CFGMR3QueryU32(pCfgHandle, "TrunkType", &u32TrunkType);
835 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
836 u32TrunkType = kIntNetTrunkType_None;
837 else if (RT_FAILURE(rc))
838 return PDMDRV_SET_ERROR(pDrvIns, rc,
839 N_("Configuration error: Failed to get the \"TrunkType\" value"));
840 OpenReq.enmTrunkType = (INTNETTRUNKTYPE)u32TrunkType;
841
842 /** @cfgm{Trunk, string, ""}
843 * The name of the trunk connection.
844 */
845 rc = CFGMR3QueryString(pCfgHandle, "Trunk", OpenReq.szTrunk, sizeof(OpenReq.szTrunk));
846 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
847 OpenReq.szTrunk[0] = '\0';
848 else if (RT_FAILURE(rc))
849 return PDMDRV_SET_ERROR(pDrvIns, rc,
850 N_("Configuration error: Failed to get the \"Trunk\" value"));
851
852 /** @cfgm{RestrictAccess, boolean, true}
853 * Whether to restrict the access to the network or if it should be public. Everyone on
854 * the computer can connect to a public network. Don't change this.
855 */
856 bool fRestrictAccess;
857 rc = CFGMR3QueryBool(pCfgHandle, "RestrictAccess", &fRestrictAccess);
858 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
859 fRestrictAccess = true;
860 else if (RT_FAILURE(rc))
861 return PDMDRV_SET_ERROR(pDrvIns, rc,
862 N_("Configuration error: Failed to get the \"RestrictAccess\" value"));
863 OpenReq.fFlags = fRestrictAccess ? 0 : INTNET_OPEN_FLAGS_PUBLIC;
864
865 /** @cfgm{IgnoreAllPromisc, boolean, false}
866 * When set all request for operating any interface or trunk in promiscuous
867 * mode will be ignored. */
868 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreAllPromisc", &f, false);
869 if (RT_FAILURE(rc))
870 return PDMDRV_SET_ERROR(pDrvIns, rc,
871 N_("Configuration error: Failed to get the \"IgnoreAllPromisc\" value"));
872 if (f)
873 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC;
874
875 /** @cfgm{QuietlyIgnoreAllPromisc, boolean, false}
876 * When set all request for operating any interface or trunk in promiscuous
877 * mode will be ignored. This differs from IgnoreAllPromisc in that clients
878 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
879 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreAllPromisc", &f, false);
880 if (RT_FAILURE(rc))
881 return PDMDRV_SET_ERROR(pDrvIns, rc,
882 N_("Configuration error: Failed to get the \"QuietlyIgnoreAllPromisc\" value"));
883 if (f)
884 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC;
885
886 /** @cfgm{IgnoreClientPromisc, boolean, false}
887 * When set all request for operating any non-trunk interface in promiscuous
888 * mode will be ignored. */
889 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreClientPromisc", &f, false);
890 if (RT_FAILURE(rc))
891 return PDMDRV_SET_ERROR(pDrvIns, rc,
892 N_("Configuration error: Failed to get the \"IgnoreClientPromisc\" value"));
893 if (f)
894 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC; /** @todo add special flag for this. */
895
896 /** @cfgm{QuietlyIgnoreClientPromisc, boolean, false}
897 * When set all request for operating any non-trunk interface promiscuous mode
898 * will be ignored. This differs from IgnoreClientPromisc in that clients won't
899 * get VERR_INTNET_INCOMPATIBLE_FLAGS. */
900 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreClientPromisc", &f, false);
901 if (RT_FAILURE(rc))
902 return PDMDRV_SET_ERROR(pDrvIns, rc,
903 N_("Configuration error: Failed to get the \"QuietlyIgnoreClientPromisc\" value"));
904 if (f)
905 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC; /** @todo add special flag for this. */
906
907 /** @cfgm{IgnoreTrunkWirePromisc, boolean, false}
908 * When set all request for operating the trunk-wire connection in promiscuous
909 * mode will be ignored. */
910 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreTrunkWirePromisc", &f, false);
911 if (RT_FAILURE(rc))
912 return PDMDRV_SET_ERROR(pDrvIns, rc,
913 N_("Configuration error: Failed to get the \"IgnoreTrunkWirePromisc\" value"));
914 if (f)
915 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE;
916
917 /** @cfgm{QuietlyIgnoreTrunkWirePromisc, boolean, false}
918 * When set all request for operating any trunk-wire connection promiscuous mode
919 * will be ignored. This differs from IgnoreTrunkWirePromisc in that clients
920 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
921 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreTrunkWirePromisc", &f, false);
922 if (RT_FAILURE(rc))
923 return PDMDRV_SET_ERROR(pDrvIns, rc,
924 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkWirePromisc\" value"));
925 if (f)
926 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE;
927
928 /** @cfgm{IgnoreTrunkHostPromisc, boolean, false}
929 * When set all request for operating the trunk-host connection in promiscuous
930 * mode will be ignored. */
931 rc = CFGMR3QueryBoolDef(pCfgHandle, "IgnoreTrunkHostPromisc", &f, false);
932 if (RT_FAILURE(rc))
933 return PDMDRV_SET_ERROR(pDrvIns, rc,
934 N_("Configuration error: Failed to get the \"IgnoreTrunkHostPromisc\" value"));
935 if (f)
936 OpenReq.fFlags |= INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST;
937
938 /** @cfgm{QuietlyIgnoreTrunkHostPromisc, boolean, false}
939 * When set all request for operating any trunk-host connection promiscuous mode
940 * will be ignored. This differs from IgnoreTrunkHostPromisc in that clients
941 * won't get VERR_INTNET_INCOMPATIBLE_FLAGS. */
942 rc = CFGMR3QueryBoolDef(pCfgHandle, "QuietlyIgnoreTrunkHostPromisc", &f, false);
943 if (RT_FAILURE(rc))
944 return PDMDRV_SET_ERROR(pDrvIns, rc,
945 N_("Configuration error: Failed to get the \"QuietlyIgnoreTrunkHostPromisc\" value"));
946 if (f)
947 OpenReq.fFlags |= INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST;
948
949 /** @todo flags for not sending to the host and for setting the trunk-wire
950 * connection in promiscuous mode. */
951
952
953 /** @cfgm{SharedMacOnWire, boolean, false}
954 * Whether to shared the MAC address of the host interface when using the wire. When
955 * attaching to a wireless NIC this option is usally a requirement.
956 */
957 bool fSharedMacOnWire;
958 rc = CFGMR3QueryBoolDef(pCfgHandle, "SharedMacOnWire", &fSharedMacOnWire, false);
959 if (RT_FAILURE(rc))
960 return PDMDRV_SET_ERROR(pDrvIns, rc,
961 N_("Configuration error: Failed to get the \"SharedMacOnWire\" value"));
962 if (fSharedMacOnWire)
963 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
964
965 /** @cfgm{ReceiveBufferSize, uint32_t, 218 KB}
966 * The size of the receive buffer.
967 */
968 rc = CFGMR3QueryU32(pCfgHandle, "ReceiveBufferSize", &OpenReq.cbRecv);
969 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
970 OpenReq.cbRecv = 218 * _1K ;
971 else if (RT_FAILURE(rc))
972 return PDMDRV_SET_ERROR(pDrvIns, rc,
973 N_("Configuration error: Failed to get the \"ReceiveBufferSize\" value"));
974
975 /** @cfgm{SendBufferSize, uint32_t, 36 KB}
976 * The size of the send (transmit) buffer.
977 * This should be more than twice the size of the larges frame size because
978 * the ring buffer is very simple and doesn't support splitting up frames
979 * nor inserting padding. So, if this is too close to the frame size the
980 * header will fragment the buffer such that the frame won't fit on either
981 * side of it and the code will get very upset about it all.
982 */
983 rc = CFGMR3QueryU32(pCfgHandle, "SendBufferSize", &OpenReq.cbSend);
984 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
985 OpenReq.cbSend = 36*_1K;
986 else if (RT_FAILURE(rc))
987 return PDMDRV_SET_ERROR(pDrvIns, rc,
988 N_("Configuration error: Failed to get the \"SendBufferSize\" value"));
989 if (OpenReq.cbSend < 32)
990 return PDMDRV_SET_ERROR(pDrvIns, rc,
991 N_("Configuration error: The \"SendBufferSize\" value is too small"));
992 if (OpenReq.cbSend < 16384*2 + 64)
993 LogRel(("DrvIntNet: Warning! SendBufferSize=%u, Recommended minimum size %u butes.\n", OpenReq.cbSend, 16384*2 + 64));
994
995 /** @cfgm{IsService, boolean, true}
996 * This alterns the way the thread is suspended and resumed. When it's being used by
997 * a service such as LWIP/iSCSI it shouldn't suspend immediately like for a NIC.
998 */
999 rc = CFGMR3QueryBool(pCfgHandle, "IsService", &pThis->fActivateEarlyDeactivateLate);
1000 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1001 pThis->fActivateEarlyDeactivateLate = false;
1002 else if (RT_FAILURE(rc))
1003 return PDMDRV_SET_ERROR(pDrvIns, rc,
1004 N_("Configuration error: Failed to get the \"IsService\" value"));
1005
1006 LogRel(("IntNet#%u: szNetwork={%s} enmTrunkType=%d szTrunk={%s} fFlags=%#x cbRecv=%u cbSend=%u\n",
1007 pDrvIns->iInstance, OpenReq.szNetwork, OpenReq.enmTrunkType, OpenReq.szTrunk, OpenReq.fFlags,
1008 OpenReq.cbRecv, OpenReq.cbSend));
1009
1010#ifdef RT_OS_DARWIN
1011 /* Temporary hack: attach to a network with the name 'if=en0' and you're hitting the wire. */
1012 if ( !OpenReq.szTrunk[0]
1013 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1014 && !strncmp(pThis->szNetwork, "if=en", sizeof("if=en") - 1)
1015 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("if=en") - 1])
1016 && !pThis->szNetwork[sizeof("if=en")])
1017 {
1018 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1019 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("if=") - 1]);
1020 }
1021 /* Temporary hack: attach to a network with the name 'wif=en0' and you're on the air. */
1022 if ( !OpenReq.szTrunk[0]
1023 && OpenReq.enmTrunkType == kIntNetTrunkType_None
1024 && !strncmp(pThis->szNetwork, "wif=en", sizeof("wif=en") - 1)
1025 && RT_C_IS_DIGIT(pThis->szNetwork[sizeof("wif=en") - 1])
1026 && !pThis->szNetwork[sizeof("wif=en")])
1027 {
1028 OpenReq.enmTrunkType = kIntNetTrunkType_NetFlt;
1029 OpenReq.fFlags |= INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE;
1030 strcpy(OpenReq.szTrunk, &pThis->szNetwork[sizeof("wif=") - 1]);
1031 }
1032
1033#elif defined(RT_OS_WINDOWS) && defined(VBOX_WITH_NETFLT)
1034 if (OpenReq.enmTrunkType == kIntNetTrunkType_NetFlt
1035 || OpenReq.enmTrunkType == kIntNetTrunkType_NetAdp)
1036 {
1037# ifndef VBOX_NETFLT_ONDEMAND_BIND
1038 /*
1039 * We have a ndis filter driver started on system boot before the VBoxDrv,
1040 * tell the filter driver to init VBoxNetFlt functionality.
1041 */
1042 rc = drvIntNetWinConstruct(pDrvIns, pCfgHandle, OpenReq.enmTrunkType);
1043 AssertLogRelMsgRCReturn(rc, ("drvIntNetWinConstruct failed, rc=%Rrc", rc), rc);
1044# endif
1045
1046 /*
1047 * <Describe what this does here or/and in the function docs of drvIntNetWinIfGuidToBindName>.
1048 */
1049 char szBindName[INTNET_MAX_TRUNK_NAME];
1050 rc = drvIntNetWinIfGuidToBindName(OpenReq.szTrunk, szBindName, INTNET_MAX_TRUNK_NAME);
1051 AssertLogRelMsgRCReturn(rc, ("drvIntNetWinIfGuidToBindName failed, rc=%Rrc", rc), rc);
1052 strcpy(OpenReq.szTrunk, szBindName);
1053 }
1054#endif /* WINDOWS && NETFLT */
1055
1056 /*
1057 * Create the event semaphores
1058 */
1059 rc = RTSemEventCreate(&pThis->EventSuspended);
1060 if (RT_FAILURE(rc))
1061 return rc;
1062
1063 /*
1064 * Create the interface.
1065 */
1066 OpenReq.hIf = INTNET_HANDLE_INVALID;
1067 rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_OPEN, &OpenReq, sizeof(OpenReq));
1068 if (RT_FAILURE(rc))
1069 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1070 N_("Failed to open/create the internal network '%s'"), pThis->szNetwork);
1071 AssertRelease(OpenReq.hIf != INTNET_HANDLE_INVALID);
1072 pThis->hIf = OpenReq.hIf;
1073 Log(("IntNet%d: hIf=%RX32 '%s'\n", pDrvIns->iInstance, pThis->hIf, pThis->szNetwork));
1074
1075 if(rc != VINF_ALREADY_INITIALIZED)
1076 {
1077 /* new network gets created, check if we need to launch a DHCP server for it */
1078 char ip[16], mask[16], lowerIp[16], upperIp[16], mac[13];
1079 rc = CFGMR3QueryString(pCfgHandle, "DhcpIPAddress", ip, sizeof(ip));
1080 if (RT_SUCCESS(rc))
1081 {
1082 /* this means we have DHCP server enabled */
1083 rc = CFGMR3QueryString(pCfgHandle, "DhcpNetworkMask", mask, sizeof(mask));
1084 if (RT_FAILURE(rc))
1085 return PDMDRV_SET_ERROR(pDrvIns, rc,
1086 N_("Configuration error: Failed to get the \"DhcpNetworkMask\" value"));
1087
1088 rc = CFGMR3QueryString(pCfgHandle, "DhcpLowerIP", lowerIp, sizeof(lowerIp));
1089 if (RT_FAILURE(rc))
1090 return PDMDRV_SET_ERROR(pDrvIns, rc,
1091 N_("Configuration error: Failed to get the \"DhcpLowerIP\" value"));
1092
1093 rc = CFGMR3QueryString(pCfgHandle, "DhcpUpperIP", upperIp, sizeof(upperIp));
1094 if (RT_FAILURE(rc))
1095 return PDMDRV_SET_ERROR(pDrvIns, rc,
1096 N_("Configuration error: Failed to get the \"DhcpUpperIP\" value"));
1097
1098 rc = CFGMR3QueryString(pCfgHandle, "DhcpMacAddress", mac, sizeof(mac));
1099 if (RT_FAILURE(rc))
1100 return PDMDRV_SET_ERROR(pDrvIns, rc,
1101 N_("Configuration error: Failed to get the \"DhcpMacAddress\" value"));
1102
1103
1104 DHCPServerRunner dhcp;
1105 dhcp.setOption(DHCPCFG_NETNAME, OpenReq.szNetwork);
1106 if(OpenReq.enmTrunkType == kIntNetTrunkType_NetFlt
1107 || OpenReq.enmTrunkType == kIntNetTrunkType_NetAdp)
1108 dhcp.setOption(DHCPCFG_TRUNKNAME, OpenReq.szTrunk);
1109
1110 switch(OpenReq.enmTrunkType)
1111 {
1112 case kIntNetTrunkType_WhateverNone:
1113 case kIntNetTrunkType_None:
1114 dhcp.setOption(DHCPCFG_TRUNKTYPE, TRUNKTYPE_WHATEVER);
1115 break;
1116 case kIntNetTrunkType_NetFlt:
1117 dhcp.setOption(DHCPCFG_TRUNKTYPE, TRUNKTYPE_NETFLT);
1118 break;
1119 case kIntNetTrunkType_NetAdp:
1120 dhcp.setOption(DHCPCFG_TRUNKTYPE, TRUNKTYPE_NETADP);
1121 break;
1122 case kIntNetTrunkType_SrvNat:
1123 dhcp.setOption(DHCPCFG_TRUNKTYPE, TRUNKTYPE_SRVNAT);
1124 break;
1125 default:
1126 AssertFailed();
1127 break;
1128 }
1129 //temporary hack for testing
1130 // DHCPCFG_NAME
1131 dhcp.setOption(DHCPCFG_MACADDRESS, mac);
1132 dhcp.setOption(DHCPCFG_IPADDRESS, ip);
1133 // DHCPCFG_LEASEDB,
1134 // DHCPCFG_VERBOSE,
1135 // DHCPCFG_GATEWAY,
1136 dhcp.setOption(DHCPCFG_LOWERIP, lowerIp);
1137 dhcp.setOption(DHCPCFG_UPPERIP, upperIp);
1138 dhcp.setOption(DHCPCFG_NETMASK, mask);
1139
1140 // DHCPCFG_HELP,
1141 // DHCPCFG_VERSION,
1142 // DHCPCFG_NOTOPT_MAXVAL
1143 dhcp.setOption(DHCPCFG_BEGINCONFIG, "");
1144 dhcp.start();
1145
1146 dhcp.detachFromServer(); /* need to do this to avoid server shutdown on runner destruction */
1147 }
1148 }
1149
1150 /*
1151 * Get default buffer.
1152 */
1153 INTNETIFGETRING3BUFFERREQ GetRing3BufferReq;
1154 GetRing3BufferReq.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
1155 GetRing3BufferReq.Hdr.cbReq = sizeof(GetRing3BufferReq);
1156 GetRing3BufferReq.pSession = NIL_RTR0PTR;
1157 GetRing3BufferReq.hIf = pThis->hIf;
1158 GetRing3BufferReq.pRing3Buf = NULL;
1159 rc = pDrvIns->pDrvHlp->pfnSUPCallVMMR0Ex(pDrvIns, VMMR0_DO_INTNET_IF_GET_RING3_BUFFER, &GetRing3BufferReq, sizeof(GetRing3BufferReq));
1160 if (RT_FAILURE(rc))
1161 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
1162 N_("Failed to get ring-3 buffer for the newly created interface to '%s'"), pThis->szNetwork);
1163 AssertRelease(VALID_PTR(GetRing3BufferReq.pRing3Buf));
1164 pThis->pBuf = GetRing3BufferReq.pRing3Buf;
1165
1166 /*
1167 * Create the async I/O thread.
1168 * Note! Using a PDM thread here doesn't fit with the IsService=true operation.
1169 */
1170 rc = RTThreadCreate(&pThis->Thread, drvIntNetAsyncIoThread, pThis, _128K, RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "INTNET");
1171 if (RT_FAILURE(rc))
1172 {
1173 AssertRC(rc);
1174 return rc;
1175 }
1176
1177 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cbStatRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Net/IntNet%d/Bytes/Received", pDrvIns->iInstance);
1178 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cbStatSend, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Net/IntNet%d/Bytes/Sent", pDrvIns->iInstance);
1179 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatRecvs, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received packets.", "/Net/IntNet%d/Packets/Received", pDrvIns->iInstance);
1180 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatSends, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent packets.", "/Net/IntNet%d/Packets/Sent", pDrvIns->iInstance);
1181 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatLost, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent packets.", "/Net/IntNet%d/Packets/Lost", pDrvIns->iInstance);
1182 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->pBuf->cStatYieldsNok, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of times yielding didn't help fix an overflow.", "/Net/IntNet%d/YieldNok", pDrvIns->iInstance);
1183#ifdef VBOX_WITH_STATISTICS
1184 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Net/IntNet%d/Receive", pDrvIns->iInstance);
1185 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Net/IntNet%d/Transmit", pDrvIns->iInstance);
1186#endif
1187
1188 /*
1189 * Activate data transmission as early as possible
1190 */
1191 if (pThis->fActivateEarlyDeactivateLate)
1192 {
1193 ASMAtomicXchgSize(&pThis->enmState, ASYNCSTATE_RUNNING);
1194 RTSemEventSignal(pThis->EventSuspended);
1195 drvIntNetUpdateMacAddress(pThis);
1196 drvIntNetSetActive(pThis, true /* fActive */);
1197 }
1198
1199 return rc;
1200}
1201
1202
1203/**
1204 * Internal networking transport driver registration record.
1205 */
1206const PDMDRVREG g_DrvIntNet =
1207{
1208 /* u32Version */
1209 PDM_DRVREG_VERSION,
1210 /* szDriverName */
1211 "IntNet",
1212 /* pszDescription */
1213 "Internal Networking Transport Driver",
1214 /* fFlags */
1215 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1216 /* fClass. */
1217 PDM_DRVREG_CLASS_NETWORK,
1218 /* cMaxInstances */
1219 ~0,
1220 /* cbInstance */
1221 sizeof(DRVINTNET),
1222 /* pfnConstruct */
1223 drvIntNetConstruct,
1224 /* pfnDestruct */
1225 drvIntNetDestruct,
1226 /* pfnIOCtl */
1227 NULL,
1228 /* pfnPowerOn */
1229 drvIntNetPowerOn,
1230 /* pfnReset */
1231 NULL,
1232 /* pfnSuspend */
1233 drvIntNetSuspend,
1234 /* pfnResume */
1235 drvIntNetResume,
1236 /* pfnDetach */
1237 NULL,
1238 /* pfnPowerOff */
1239 drvIntNetPowerOff
1240};
1241
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