VirtualBox

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

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

swithed to PDMDrv timers and VBox/tm.h API for timer management

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