VirtualBox

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

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

coding style

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