VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvNAT.cpp@ 13733

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

Resolved locks in UDP
Some mutex operations checked with AssertReleaseRC
Still TCP part need to be re-checked
udb_mutex now used only for controlling pData->udb
and udp_last_so controlled by udp_last_so_mutex

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.7 KB
Line 
1/** @file
2 *
3 * VBox network devices:
4 * NAT network transport driver
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#define LOG_GROUP LOG_GROUP_DRV_NAT
28#define __STDC_LIMIT_MACROS
29#define __STDC_CONSTANT_MACROS
30#ifndef VBOX_NAT_SOURCES
31#include "Network/slirp/libslirp.h"
32#else
33#include <sys/types.h>
34#include <sys/socket.h>
35
36#include <netinet/in.h>
37
38#include <errno.h>
39
40#include <unistd.h>
41
42#include <fcntl.h>
43
44#include <string.h>
45
46#endif
47#include <VBox/pdmdrv.h>
48#include <iprt/assert.h>
49#include <iprt/file.h>
50#include <iprt/string.h>
51#include <iprt/critsect.h>
52#include <iprt/cidr.h>
53
54#include "Builtins.h"
55
56#ifdef VBOX_NAT_SOURCES
57#include "Network/nat/nat.h"
58#endif
59
60#ifdef VBOX_WITH_SYNC_SLIRP
61#include <iprt/semaphore.h>
62#endif
63
64
65/*******************************************************************************
66* Structures and Typedefs *
67*******************************************************************************/
68/**
69 * NAT network transport driver instance data.
70 */
71typedef struct DRVNAT
72{
73 /** The network interface. */
74 PDMINETWORKCONNECTOR INetworkConnector;
75 /** The port we're attached to. */
76 PPDMINETWORKPORT pPort;
77 /** The network config of the port we're attached to. */
78 PPDMINETWORKCONFIG pConfig;
79 /** Pointer to the driver instance. */
80 PPDMDRVINS pDrvIns;
81 /** Slirp critical section. */
82 RTCRITSECT CritSect;
83 /** Link state */
84 PDMNETWORKLINKSTATE enmLinkState;
85 /** NAT state for this instance. */
86#ifndef VBOX_NAT_SOURCES
87 PNATState pNATState;
88#endif
89 /** TFTP directory prefix. */
90 char *pszTFTPPrefix;
91 /** Boot file name to provide in the DHCP server response. */
92 char *pszBootFile;
93#ifdef VBOX_WITH_SYNC_SLIRP
94 /*polling thread*/
95 PPDMTHREAD pThread;
96 /*used for wakep of poling thread*/
97 RTSEMEVENT semIOmutex;
98#endif
99} DRVNAT, *PDRVNAT;
100
101/** Converts a pointer to NAT::INetworkConnector to a PRDVNAT. */
102#define PDMINETWORKCONNECTOR_2_DRVNAT(pInterface) ( (PDRVNAT)((uintptr_t)pInterface - RT_OFFSETOF(DRVNAT, INetworkConnector)) )
103
104
105/*******************************************************************************
106* Global Variables *
107*******************************************************************************/
108#if 0
109/** If set the thread should terminate. */
110static bool g_fThreadTerm = false;
111/** The thread id of the select thread (drvNATSelectThread()). */
112static RTTHREAD g_ThreadSelect;
113#endif
114
115
116/*******************************************************************************
117* Internal Functions *
118*******************************************************************************/
119
120
121#ifdef VBOX_NAT_SOURCES
122/*
123 * Sends data to guest called from NAT glue code
124 */
125static DECLCALLBACK(void) drvNATOutput(const void * data, const uint8_t *msg, int size)
126{
127 PDRVNAT pThis = (PDRVNAT)(void *)data;
128 LogFlow(("output: pvBuf=%p cb=%#x\n", msg, size));
129 int rc = pThis->pPort->pfnWaitReceiveAvail(pThis->pPort, 0);
130 if (RT_SUCCESS(rc))
131 pThis->pPort->pfnReceive(pThis->pPort, msg, size);
132 LogFlow(("output: exit\n"));
133}
134
135#endif
136
137/**
138 * Send data to the network.
139 *
140 * @returns VBox status code.
141 * @param pInterface Pointer to the interface structure containing the called function pointer.
142 * @param pvBuf Data to send.
143 * @param cb Number of bytes to send.
144 * @thread EMT
145 */
146static DECLCALLBACK(int) drvNATSend(PPDMINETWORKCONNECTOR pInterface, const void *pvBuf, size_t cb)
147{
148 PDRVNAT pThis = PDMINETWORKCONNECTOR_2_DRVNAT(pInterface);
149
150 LogFlow(("drvNATSend: pvBuf=%p cb=%#x\n", pvBuf, cb));
151 Log2(("drvNATSend: pvBuf=%p cb=%#x\n"
152 "%.*Vhxd\n",
153 pvBuf, cb, cb, pvBuf));
154
155#ifndef VBOX_WITH_SYNC_SLIRP
156 int rc = RTCritSectEnter(&pThis->CritSect);
157 AssertReleaseRC(rc);
158#endif
159
160 Assert(pThis->enmLinkState == PDMNETWORKLINKSTATE_UP);
161 if (pThis->enmLinkState == PDMNETWORKLINKSTATE_UP) {
162#ifndef VBOX_NAT_SOURCES
163 slirp_input(pThis->pNATState, (uint8_t *)pvBuf, cb);
164#else
165 ether_chk(pThis, pvBuf, cb);
166#endif
167 }
168#ifndef VBOX_WITH_SYNC_SLIRP
169 RTCritSectLeave(&pThis->CritSect);
170#endif
171 LogFlow(("drvNATSend: end\n"));
172 return VINF_SUCCESS;
173}
174
175
176/**
177 * Set promiscuous mode.
178 *
179 * This is called when the promiscuous mode is set. This means that there doesn't have
180 * to be a mode change when it's called.
181 *
182 * @param pInterface Pointer to the interface structure containing the called function pointer.
183 * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not.
184 * @thread EMT
185 */
186static DECLCALLBACK(void) drvNATSetPromiscuousMode(PPDMINETWORKCONNECTOR pInterface, bool fPromiscuous)
187{
188 LogFlow(("drvNATSetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
189 /* nothing to do */
190}
191
192
193/**
194 * Notification on link status changes.
195 *
196 * @param pInterface Pointer to the interface structure containing the called function pointer.
197 * @param enmLinkState The new link state.
198 * @thread EMT
199 */
200static DECLCALLBACK(void) drvNATNotifyLinkChanged(PPDMINETWORKCONNECTOR pInterface, PDMNETWORKLINKSTATE enmLinkState)
201{
202 PDRVNAT pThis = PDMINETWORKCONNECTOR_2_DRVNAT(pInterface);
203
204 LogFlow(("drvNATNotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
205
206#ifndef VBOX_WITH_SYNC_SLIRP
207 int rc = RTCritSectEnter(&pThis->CritSect);
208 AssertReleaseRC(rc);
209#endif
210 pThis->enmLinkState = enmLinkState;
211
212 switch (enmLinkState)
213 {
214 case PDMNETWORKLINKSTATE_UP:
215 LogRel(("NAT: link up\n"));
216#ifndef VBOX_NAT_SOURCES
217 slirp_link_up(pThis->pNATState);
218#endif
219 break;
220
221 case PDMNETWORKLINKSTATE_DOWN:
222 case PDMNETWORKLINKSTATE_DOWN_RESUME:
223 LogRel(("NAT: link down\n"));
224#ifndef VBOX_NAT_SOURCES
225 slirp_link_down(pThis->pNATState);
226#endif
227 break;
228
229 default:
230 AssertMsgFailed(("drvNATNotifyLinkChanged: unexpected link state %d\n", enmLinkState));
231 }
232#ifndef VBOX_WITH_SYNC_SLIRP
233 RTCritSectLeave(&pThis->CritSect);
234#endif
235}
236
237
238/**
239 * Poller callback.
240 */
241#ifndef VBOX_WITH_SYNC_SLIRP
242static DECLCALLBACK(void) drvNATPoller(PPDMDRVINS pDrvIns)
243{
244 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
245 fd_set ReadFDs;
246 fd_set WriteFDs;
247 fd_set XcptFDs;
248 int cFDs = -1;
249 FD_ZERO(&ReadFDs);
250 FD_ZERO(&WriteFDs);
251 FD_ZERO(&XcptFDs);
252
253 int rc = RTCritSectEnter(&pThis->CritSect);
254 AssertReleaseRC(rc);
255
256#ifndef VBOX_NAT_SOURCES
257 slirp_select_fill(pThis->pNATState, &cFDs, &ReadFDs, &WriteFDs, &XcptFDs);
258#else
259 nat_select_fill(NULL, &cFDs, &ReadFDs, &WriteFDs, &XcptFDs);
260#endif
261
262 struct timeval tv = {0, 0}; /* no wait */
263 int cReadFDs = select(cFDs + 1, &ReadFDs, &WriteFDs, &XcptFDs, &tv);
264#ifndef VBOX_NAT_SOURCES
265 if (cReadFDs >= 0)
266 slirp_select_poll(pThis->pNATState, &ReadFDs, &WriteFDs, &XcptFDs);
267#else
268 if (cReadFDs >= 0) {
269 nat_select_poll(pThis, &ReadFDs, &WriteFDs, &XcptFDs);
270 }
271#endif
272
273 RTCritSectLeave(&pThis->CritSect);
274}
275#else
276
277static DECLCALLBACK(int) drvNATAsyncIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
278{
279 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
280 fd_set ReadFDs;
281 fd_set WriteFDs;
282 fd_set XcptFDs;
283 int cFDs = -1;
284 int rc;
285
286 LogFlow(("drvNATAsyncIoThread: pThis=%p\n", pThis));
287
288
289 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
290 return VINF_SUCCESS;
291 /*
292 * Polling loop.
293 */
294 while (pThread->enmState == PDMTHREADSTATE_RUNNING)
295 {
296 FD_ZERO(&ReadFDs);
297 FD_ZERO(&WriteFDs);
298 FD_ZERO(&XcptFDs);
299 cFDs = -1;
300
301 slirp_select_fill(pThis->pNATState, &cFDs, &ReadFDs, &WriteFDs, &XcptFDs);
302
303 struct timeval tv = {0, 0}; /* no wait */
304
305 int cReadFDs = select(cFDs + 1, &ReadFDs, &WriteFDs, &XcptFDs, &tv);
306
307 if (cReadFDs >= 0)
308 slirp_select_poll(pThis->pNATState, &ReadFDs, &WriteFDs, &XcptFDs);
309
310#if 0
311 if (cReadFDs == 0) {
312 rc = RTSemEventWait(pThis->semIOmutex, RT_INDEFINITE_WAIT);
313 AssertReleaseRC(rc);
314 }
315#endif
316 }
317
318 return VINF_SUCCESS;
319}
320 /**
321 * Unblock the send thread so it can respond to a state change.
322 *
323 * @returns VBox status code.
324 * @param pDevIns The pcnet device instance.
325 * @param pThread The send thread.
326 */
327static DECLCALLBACK(int) drvNATAsyncIoWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
328{
329#if 0
330 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
331 int rc = RTSemEventSignal(pThis->semIOmutex);
332 AssertReleaseRC(rc);
333#endif
334 return (VINF_SUCCESS);
335}
336
337#endif
338
339#ifndef VBOX_NAT_SOURCES
340/**
341 * Function called by slirp to check if it's possible to feed incoming data to the network port.
342 * @returns 1 if possible.
343 * @returns 0 if not possible.
344 */
345int slirp_can_output(void *pvUser)
346{
347 PDRVNAT pThis = (PDRVNAT)pvUser;
348
349 Assert(pThis);
350
351#ifndef VBOX_WITH_SYNC_SLIRP
352 /** Happens during termination */
353 if (!RTCritSectIsOwner(&pThis->CritSect))
354 return 0;
355#endif
356
357 int rc = pThis->pPort->pfnWaitReceiveAvail(pThis->pPort, 0);
358 return RT_SUCCESS(rc);
359}
360
361
362/**
363 * Function called by slirp to feed incoming data to the network port.
364 */
365void slirp_output(void *pvUser, const uint8_t *pu8Buf, int cb)
366{
367 PDRVNAT pThis = (PDRVNAT)pvUser;
368
369 LogFlow(("slirp_output BEGIN %x %d\n", pu8Buf, cb));
370 Log2(("slirp_output: pu8Buf=%p cb=%#x (pThis=%p)\n"
371 "%.*Vhxd\n",
372 pu8Buf, cb, pThis,
373 cb, pu8Buf));
374
375 Assert(pThis);
376
377#ifndef VBOX_WITH_SYNC_SLIRP
378 /** Happens during termination */
379 if (!RTCritSectIsOwner(&pThis->CritSect))
380 return;
381#endif
382
383 int rc = pThis->pPort->pfnReceive(pThis->pPort, pu8Buf, cb);
384 AssertRC(rc);
385 LogFlow(("slirp_output END %x %d\n", pu8Buf, cb));
386}
387#endif
388
389/**
390 * Queries an interface to the driver.
391 *
392 * @returns Pointer to interface.
393 * @returns NULL if the interface was not supported by the driver.
394 * @param pInterface Pointer to this interface structure.
395 * @param enmInterface The requested interface identification.
396 * @thread Any thread.
397 */
398static DECLCALLBACK(void *) drvNATQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
399{
400 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
401 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
402 switch (enmInterface)
403 {
404 case PDMINTERFACE_BASE:
405 return &pDrvIns->IBase;
406 case PDMINTERFACE_NETWORK_CONNECTOR:
407 return &pThis->INetworkConnector;
408 default:
409 return NULL;
410 }
411}
412
413
414/**
415 * Destruct a driver instance.
416 *
417 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
418 * resources can be freed correctly.
419 *
420 * @param pDrvIns The driver instance data.
421 */
422static DECLCALLBACK(void) drvNATDestruct(PPDMDRVINS pDrvIns)
423{
424 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
425
426 LogFlow(("drvNATDestruct:\n"));
427
428 int rc = RTCritSectEnter(&pThis->CritSect);
429 AssertReleaseRC(rc);
430#ifndef VBOX_NAT_SOURCES
431 slirp_term(pThis->pNATState);
432 pThis->pNATState = NULL;
433#endif
434 RTCritSectLeave(&pThis->CritSect);
435
436 RTCritSectDelete(&pThis->CritSect);
437}
438
439
440/**
441 * Sets up the redirectors.
442 *
443 * @returns VBox status code.
444 * @param pCfgHandle The drivers configuration handle.
445 */
446static int drvNATConstructRedir(unsigned iInstance, PDRVNAT pThis, PCFGMNODE pCfgHandle, RTIPV4ADDR Network)
447{
448#ifndef VBOX_NAT_SOURCES
449 /*
450 * Enumerate redirections.
451 */
452 for (PCFGMNODE pNode = CFGMR3GetFirstChild(pCfgHandle); pNode; pNode = CFGMR3GetNextChild(pNode))
453 {
454 /*
455 * Validate the port forwarding config.
456 */
457 if (!CFGMR3AreValuesValid(pNode, "Protocol\0UDP\0HostPort\0GuestPort\0GuestIP\0"))
458 return PDMDRV_SET_ERROR(pThis->pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES, N_("Unknown configuration in port forwarding"));
459
460 /* protocol type */
461 bool fUDP;
462 char szProtocol[32];
463 int rc = CFGMR3QueryString(pNode, "Protocol", &szProtocol[0], sizeof(szProtocol));
464 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
465 {
466 rc = CFGMR3QueryBool(pNode, "UDP", &fUDP);
467 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
468 fUDP = false;
469 else if (RT_FAILURE(rc))
470 return PDMDrvHlpVMSetError(pThis->pDrvIns, rc, RT_SRC_POS, N_("NAT#%d: configuration query for \"UDP\" boolean failed"), iInstance);
471 }
472 else if (RT_SUCCESS(rc))
473 {
474 if (!RTStrICmp(szProtocol, "TCP"))
475 fUDP = false;
476 else if (!RTStrICmp(szProtocol, "UDP"))
477 fUDP = true;
478 else
479 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS, N_("NAT#%d: Invalid configuration value for \"Protocol\": \"%s\""), iInstance, szProtocol);
480 }
481 else
482 return PDMDrvHlpVMSetError(pThis->pDrvIns, rc, RT_SRC_POS, N_("NAT#%d: configuration query for \"Protocol\" string failed"), iInstance);
483
484 /* host port */
485 int32_t iHostPort;
486 rc = CFGMR3QueryS32(pNode, "HostPort", &iHostPort);
487 if (RT_FAILURE(rc))
488 return PDMDrvHlpVMSetError(pThis->pDrvIns, rc, RT_SRC_POS, N_("NAT#%d: configuration query for \"HostPort\" integer failed"), iInstance);
489
490 /* guest port */
491 int32_t iGuestPort;
492 rc = CFGMR3QueryS32(pNode, "GuestPort", &iGuestPort);
493 if (RT_FAILURE(rc))
494 return PDMDrvHlpVMSetError(pThis->pDrvIns, rc, RT_SRC_POS, N_("NAT#%d: configuration query for \"GuestPort\" integer failed"), iInstance);
495
496 /* guest address */
497 char szGuestIP[32];
498 rc = CFGMR3QueryString(pNode, "GuestIP", &szGuestIP[0], sizeof(szGuestIP));
499 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
500 RTStrPrintf(szGuestIP, sizeof(szGuestIP), "%d.%d.%d.%d",
501 (Network & 0xFF000000) >> 24, (Network & 0xFF0000) >> 16, (Network & 0xFF00) >> 8, (Network & 0xE0) | 15);
502 else if (RT_FAILURE(rc))
503 return PDMDrvHlpVMSetError(pThis->pDrvIns, rc, RT_SRC_POS, N_("NAT#%d: configuration query for \"GuestIP\" string failed"), iInstance);
504 struct in_addr GuestIP;
505 if (!inet_aton(szGuestIP, &GuestIP))
506 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_NAT_REDIR_GUEST_IP, RT_SRC_POS, N_("NAT#%d: configuration error: invalid \"GuestIP\"=\"%s\", inet_aton failed"), iInstance, szGuestIP);
507
508 /*
509 * Call slirp about it.
510 */
511 Log(("drvNATConstruct: Redir %d -> %s:%d\n", iHostPort, szGuestIP, iGuestPort));
512 if (slirp_redir(pThis->pNATState, fUDP, iHostPort, GuestIP, iGuestPort) < 0)
513 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_NAT_REDIR_SETUP, RT_SRC_POS, N_("NAT#%d: configuration error: failed to set up redirection of %d to %s:%d. Probably a conflict with existing services or other rules"), iInstance, iHostPort, szGuestIP, iGuestPort);
514 } /* for each redir rule */
515#endif
516
517 return VINF_SUCCESS;
518}
519
520/**
521 * Get the MAC address into the slirp stack.
522 */
523static void drvNATSetMac(PDRVNAT pThis)
524{
525#ifndef VBOX_NAT_SOURCES
526 if (pThis->pConfig)
527 {
528 RTMAC Mac;
529 pThis->pConfig->pfnGetMac(pThis->pConfig, &Mac);
530 slirp_set_ethaddr(pThis->pNATState, Mac.au8);
531 }
532#endif
533}
534
535
536/**
537 * After loading we have to pass the MAC address of the ethernet device to the slirp stack.
538 * Otherwise the guest is not reachable until it performs a DHCP request or an ARP request
539 * (usually done during guest boot).
540 */
541static DECLCALLBACK(int) drvNATLoadDone(PPDMDRVINS pDrvIns, PSSMHANDLE pSSMHandle)
542{
543 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
544 drvNATSetMac(pThis);
545 return VINF_SUCCESS;
546}
547
548
549/**
550 * Some guests might not use DHCP to retrieve an IP but use a static IP.
551 */
552static DECLCALLBACK(void) drvNATPowerOn(PPDMDRVINS pDrvIns)
553{
554 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
555 drvNATSetMac(pThis);
556}
557
558
559/**
560 * Construct a NAT network transport driver instance.
561 *
562 * @returns VBox status.
563 * @param pDrvIns The driver instance data.
564 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
565 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
566 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
567 * iInstance it's expected to be used a bit in this function.
568 */
569static DECLCALLBACK(int) drvNATConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
570{
571 PDRVNAT pThis = PDMINS_2_DATA(pDrvIns, PDRVNAT);
572 char szNetAddr[16];
573 char szNetwork[32]; /* xxx.xxx.xxx.xxx/yy */
574 LogFlow(("drvNATConstruct:\n"));
575
576 /*
577 * Validate the config.
578 */
579 if (!CFGMR3AreValuesValid(pCfgHandle, "PassDomain\0TFTPPrefix\0BootFile\0Network\0"))
580 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES, N_("Unknown NAT configuration option, only supports PassDomain, TFTPPrefix, BootFile and Network"));
581
582 /*
583 * Init the static parts.
584 */
585 pThis->pDrvIns = pDrvIns;
586#ifndef VBOX_NAT_SOURCES
587 pThis->pNATState = NULL;
588#endif
589 pThis->pszTFTPPrefix = NULL;
590 pThis->pszBootFile = NULL;
591 /* IBase */
592 pDrvIns->IBase.pfnQueryInterface = drvNATQueryInterface;
593 /* INetwork */
594 pThis->INetworkConnector.pfnSend = drvNATSend;
595 pThis->INetworkConnector.pfnSetPromiscuousMode = drvNATSetPromiscuousMode;
596 pThis->INetworkConnector.pfnNotifyLinkChanged = drvNATNotifyLinkChanged;
597
598 /*
599 * Get the configuration settings.
600 */
601 bool fPassDomain = true;
602 int rc = CFGMR3QueryBool(pCfgHandle, "PassDomain", &fPassDomain);
603 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
604 fPassDomain = true;
605 else if (RT_FAILURE(rc))
606 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NAT#%d: configuration query for \"PassDomain\" boolean failed"), pDrvIns->iInstance);
607
608 rc = CFGMR3QueryStringAlloc(pCfgHandle, "TFTPPrefix", &pThis->pszTFTPPrefix);
609 if (RT_FAILURE(rc) && rc != VERR_CFGM_VALUE_NOT_FOUND)
610 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NAT#%d: configuration query for \"TFTPPrefix\" string failed"), pDrvIns->iInstance);
611 rc = CFGMR3QueryStringAlloc(pCfgHandle, "BootFile", &pThis->pszBootFile);
612 if (RT_FAILURE(rc) && rc != VERR_CFGM_VALUE_NOT_FOUND)
613 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NAT#%d: configuration query for \"BootFile\" string failed"), pDrvIns->iInstance);
614
615 /*
616 * Query the network port interface.
617 */
618 pThis->pPort = (PPDMINETWORKPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_PORT);
619 if (!pThis->pPort)
620 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
621 N_("Configuration error: the above device/driver didn't export the network port interface"));
622 pThis->pConfig = (PPDMINETWORKCONFIG)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_NETWORK_CONFIG);
623 if (!pThis->pConfig)
624 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
625 N_("Configuration error: the above device/driver didn't export the network config interface"));
626
627 /* Generate a network address for this network card. */
628 rc = CFGMR3QueryString(pCfgHandle, "Network", szNetwork, sizeof(szNetwork));
629 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
630 RTStrPrintf(szNetwork, sizeof(szNetwork), "10.0.%d.0/24", pDrvIns->iInstance + 2);
631 else if (RT_FAILURE(rc))
632 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NAT#%d: configuration query for \"Network\" string failed"), pDrvIns->iInstance);
633
634 RTIPV4ADDR Network;
635 RTIPV4ADDR Netmask;
636 rc = RTCidrStrToIPv4(szNetwork, &Network, &Netmask);
637 if (RT_FAILURE(rc))
638 return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, N_("NAT#%d: Configuration error: network '%s' describes not a valid IPv4 network"), pDrvIns->iInstance, szNetwork);
639
640 RTStrPrintf(szNetAddr, sizeof(szNetAddr), "%d.%d.%d.%d",
641 (Network & 0xFF000000) >> 24, (Network & 0xFF0000) >> 16, (Network & 0xFF00) >> 8, Network & 0xFF);
642
643 /*
644 * The slirp lock..
645 */
646 rc = RTCritSectInit(&pThis->CritSect);
647 if (RT_FAILURE(rc))
648 return rc;
649#if 0
650 rc = RTSemEventCreate(&g_EventSem);
651 if (RT_SUCCESS(rc))
652 {
653 /*
654 * Start the select thread. (it'll block on the sem)
655 */
656 g_fThreadTerm = false;
657 rc = RTThreadCreate(&g_ThreadSelect, drvNATSelectThread, 0, NULL, "NATSEL");
658 if (RT_SUCCESS(rc))
659 {
660#endif
661#ifndef VBOX_NAT_SOURCES
662 /*
663 * Initialize slirp.
664 */
665 rc = slirp_init(&pThis->pNATState, &szNetAddr[0], Netmask, fPassDomain, pThis->pszTFTPPrefix, pThis->pszBootFile, pThis);
666 if (RT_SUCCESS(rc))
667 {
668 int rc2 = drvNATConstructRedir(pDrvIns->iInstance, pThis, pCfgHandle, Network);
669 if (RT_SUCCESS(rc2))
670 {
671 /*
672 * Register a load done notification to get the MAC address into the slirp
673 * engine after we loaded a guest state.
674 */
675 rc2 = PDMDrvHlpSSMRegister(pDrvIns, pDrvIns->pDrvReg->szDriverName,
676 pDrvIns->iInstance, 0, 0,
677 NULL, NULL, NULL, NULL, NULL, drvNATLoadDone);
678 AssertRC(rc2);
679#ifndef VBOX_WITH_SYNC_SLIRP
680 pDrvIns->pDrvHlp->pfnPDMPollerRegister(pDrvIns, drvNATPoller);
681#else
682 rc = RTSemEventCreate(&pThis->semIOmutex);
683 AssertReleaseRC(rc);
684 rc = PDMDrvHlpPDMThreadCreate(pDrvIns, &pThis->pThread, pThis, drvNATAsyncIoThread, drvNATAsyncIoWakeup, 128 * _1K, RTTHREADTYPE_IO, "NAT");
685 AssertReleaseRC(rc);
686#endif
687
688 pThis->enmLinkState = PDMNETWORKLINKSTATE_UP;
689#if 0
690 RTSemEventSignal(g_EventSem);
691 RTThreadSleep(0);
692#endif
693 /* might return VINF_NAT_DNS */
694 return rc;
695 }
696 /* failure path */
697 rc = rc2;
698 slirp_term(pThis->pNATState);
699 pThis->pNATState = NULL;
700 }
701 else
702 {
703 PDMDRV_SET_ERROR(pDrvIns, rc, N_("Unknown error during NAT networking setup: "));
704 AssertMsgFailed(("Add error message for rc=%d (%Rrc)\n", rc, rc));
705 }
706#else
707 pDrvIns->pDrvHlp->pfnPDMPollerRegister(pDrvIns, drvNATPoller);
708 pThis->enmLinkState = PDMNETWORKLINKSTATE_UP;
709 struct nat_output_callbacks cb;
710 cb.noc_guest_out = drvNATOutput;
711 nat_init(&cb, pDrvIns);
712#endif
713#if 0
714 g_fThreadTerm = true;
715 RTSemEventSignal(g_EventSem);
716 RTThreadSleep(0);
717 }
718 RTSemEventDestroy(g_EventSem);
719 g_EventSem = NULL;
720 }
721#endif
722#ifndef VBOX_NAT_SOURCES
723 RTCritSectDelete(&pThis->CritSect);
724#endif
725 return rc;
726}
727
728
729
730
731/**
732 * NAT network transport driver registration record.
733 */
734const PDMDRVREG g_DrvNAT =
735{
736 /* u32Version */
737 PDM_DRVREG_VERSION,
738 /* szDriverName */
739 "NAT",
740 /* pszDescription */
741 "NAT Network Transport Driver",
742 /* fFlags */
743 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
744 /* fClass. */
745 PDM_DRVREG_CLASS_NETWORK,
746 /* cMaxInstances */
747 16,
748 /* cbInstance */
749 sizeof(DRVNAT),
750 /* pfnConstruct */
751 drvNATConstruct,
752 /* pfnDestruct */
753 drvNATDestruct,
754 /* pfnIOCtl */
755 NULL,
756 /* pfnPowerOn */
757 drvNATPowerOn,
758 /* pfnReset */
759 NULL,
760 /* pfnSuspend */
761 NULL,
762 /* pfnResume */
763 NULL,
764 /* pfnDetach */
765 NULL,
766 /* pfnPowerOff */
767 NULL
768};
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