VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/slirp.c@ 16612

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

NAT:win burn fix

  • Property svn:eol-style set to native
File size: 46.3 KB
Line 
1#include "slirp.h"
2#ifdef RT_OS_OS2
3# include <paths.h>
4#endif
5
6#include <VBox/err.h>
7#include <VBox/pdmdrv.h>
8#include <iprt/assert.h>
9#ifndef RT_OS_WINDOWS
10#include <poll.h>
11#endif
12
13#if !defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
14
15# ifndef VBOX_WITH_SIMPLIFIED_SLIRP_SYNC
16# define DO_ENGAGE_EVENT1(so, fdset, label) \
17 do { \
18 FD_SET((so)->s, (fdset)); \
19 UPD_NFDS((so)->s); \
20 } while(0)
21
22
23# define DO_ENGAGE_EVENT2(so, fdset1, fdset2, label) \
24 do { \
25 FD_SET((so)->s, (fdset1)); \
26 FD_SET((so)->s, (fdset2)); \
27 UPD_NFDS((so)->s); \
28 } while(0)
29
30# define DO_POLL_EVENTS(rc, error, so, events, label) do {} while (0)
31
32# define DO_CHECK_FD_SET(so, events, fdset) (FD_ISSET((so)->s, fdset))
33# define DO_UNIX_CHECK_FD_SET(so, events, fdset ) 0 /*specific for Unix API */
34# else /* !VBOX_WITH_SIMPLIFIED_SLIRP_SYNC */
35# define DO_ENGAGE_EVENT1(so, fdset, label) \
36 do { \
37 polls[poll_index].fd = (so)->s; \
38 (so)->so_poll_index = poll_index; \
39 polls[poll_index].events = N_(fdset ## _poll); \
40 poll_index++; \
41 } while(0)
42
43
44# define DO_ENGAGE_EVENT2(so, fdset1, fdset2, label) \
45 do { \
46 polls[poll_index].fd = (so)->s; \
47 (so)->so_poll_index = poll_index; \
48 polls[poll_index].events = N_(fdset1 ## _poll) | N_(fdset1 ## _poll); \
49 poll_index++; \
50 } while(0)
51
52# define DO_POLL_EVENTS(rc, error, so, events, label) do {} while (0)
53
54# define DO_CHECK_FD_SET(so, events, fdset) ( ((so)->so_poll_index != -1) \
55 && ((so)->so_poll_index <= ndfs) \
56 && ((so)->s == polls[so->so_poll_index].fd) \
57 && (polls[(so)->so_poll_index].revents & N_(fdset ## _poll)))
58# define DO_UNIX_CHECK_FD_SET(so, events, fdset ) DO_CHECK_FD_SET((so), (events), fdset) /*specific for Unix API */
59# define DO_WIN_CHECK_FD_SET(so, events, fdset ) 0 /* specific for Windows Winsock API */
60# endif /* VBOX_WITH_SIMPLIFIED_SLIRP_SYNC */
61
62# ifndef RT_OS_WINDOWS
63
64# ifndef RT_OS_LINUX
65# define readfds_poll (POLLRDNORM)
66# define writefds_poll (POLLWRNORM)
67# define xfds_poll (POLLRDBAND|POLLWRBAND|POLLPRI)
68# else
69# define readfds_poll (POLLIN)
70# define writefds_poll (POLLOUT)
71# define xfds_poll (POLLPRI)
72# endif
73# define rderr_poll (POLLERR)
74# define rdhup_poll (POLLHUP)
75# define nval_poll (POLLNVAL)
76
77# define ICMP_ENGAGE_EVENT(so, fdset) \
78 do { \
79 if (pData->icmp_socket.s != -1) \
80 DO_ENGAGE_EVENT1((so), fdset, ICMP); \
81 } while (0)
82# else /* !RT_OS_WINDOWS */
83# define DO_WIN_CHECK_FD_SET(so, events, fdset ) DO_CHECK_FD_SET((so), (events), fdset)
84# define ICMP_ENGAGE_EVENT(so, fdset) do {} while(0)
85#endif /* RT_OS_WINDOWS */
86
87#else /* defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS) */
88
89/*
90 * On Windows, we will be notified by IcmpSendEcho2() when the response arrives.
91 * So no call to WSAEventSelect necessary.
92 */
93# define ICMP_ENGAGE_EVENT(so, fdset) do {} while(0)
94
95# define DO_ENGAGE_EVENT1(so, fdset1, label) \
96 do { \
97 rc = WSAEventSelect((so)->s, VBOX_SOCKET_EVENT, FD_ALL_EVENTS); \
98 if (rc == SOCKET_ERROR) \
99 { \
100 /* This should not happen */ \
101 error = WSAGetLastError(); \
102 LogRel(("WSAEventSelect (" #label ") error %d (so=%x, socket=%s, event=%x)\n", \
103 error, (so), (so)->s, VBOX_SOCKET_EVENT)); \
104 } \
105 } while(0); \
106 CONTINUE(label)
107
108# define DO_ENGAGE_EVENT2(so, fdset1, fdset2, label) \
109 DO_ENGAGE_EVENT1((so), (fdset1), label)
110
111# define DO_POLL_EVENTS(rc, error, so, events, label) \
112 (rc) = WSAEnumNetworkEvents((so)->s, VBOX_SOCKET_EVENT, (events)); \
113 if ((rc) == SOCKET_ERROR) \
114 { \
115 (error) = WSAGetLastError(); \
116 LogRel(("WSAEnumNetworkEvents " #label " error %d\n", (error))); \
117 CONTINUE(label); \
118 }
119
120# define acceptds_win FD_ACCEPT
121# define acceptds_win_bit FD_ACCEPT_BIT
122
123# define readfds_win FD_READ
124# define readfds_win_bit FD_READ_BIT
125
126# define writefds_win FD_WRITE
127# define writefds_win_bit FD_WRITE_BIT
128
129# define xfds_win FD_OOB
130# define xfds_win_bit FD_OOB_BIT
131
132# define DO_CHECK_FD_SET(so, events, fdset) \
133 (((events).lNetworkEvents & fdset ## _win) && ((events).iErrorCode[fdset ## _win_bit] == 0))
134
135# define DO_WIN_CHECK_FD_SET(so, events, fdset ) DO_CHECK_FD_SET((so), (events), fdset)
136# define DO_UNIX_CHECK_FD_SET(so, events, fdset ) 1 /*specific for Unix API */
137
138#endif /* defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS) */
139
140#define TCP_ENGAGE_EVENT1(so, fdset) \
141 DO_ENGAGE_EVENT1((so), fdset, tcp)
142
143#define TCP_ENGAGE_EVENT2(so, fdset1, fdset2) \
144 DO_ENGAGE_EVENT2((so), fdset1, fdset2, tcp)
145
146#define UDP_ENGAGE_EVENT(so, fdset) \
147 DO_ENGAGE_EVENT1((so), fdset, udp)
148
149#define POLL_TCP_EVENTS(rc, error, so, events) \
150 DO_POLL_EVENTS((rc), (error), (so), (events), tcp)
151
152#define POLL_UDP_EVENTS(rc, error, so, events) \
153 DO_POLL_EVENTS((rc), (error), (so), (events), udp)
154
155#define CHECK_FD_SET(so, events, set) \
156 (DO_CHECK_FD_SET((so), (events), set))
157
158#define WIN_CHECK_FD_SET(so, events, set) \
159 (DO_WIN_CHECK_FD_SET((so), (events), set))
160#define UNIX_CHECK_FD_SET(so, events, set) \
161 (DO_UNIX_CHECK_FD_SET(so, events, set))
162
163/*
164 * Loging macros
165 */
166#if VBOX_WITH_DEBUG_NAT_SOCKETS
167# if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC)
168# if defined(RT_OS_WINDOWS)
169# define DO_LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) \
170 do { \
171 LogRel((" " #proto " %R[natsock] %R[natwinnetevents]\n", (so), (winevent))); \
172 } while (0)
173# else /* RT_OS_WINDOWS */
174# define DO_LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) \
175 do { \
176 LogRel((" " #proto " %R[natsock] %s %s %s er: %s, %s, %s\n", (so), \
177 CHECK_FD_SET(so, ign ,r_fdset) ? "READ":"", \
178 CHECK_FD_SET(so, ign, w_fdset) ? "WRITE":"", \
179 CHECK_FD_SET(so, ign, x_fdset) ? "OOB":"", \
180 CHECK_FD_SET(so, ign, rderr) ? "RDERR":"", \
181 CHECK_FD_SET(so, ign, rdhup) ? "RDHUP":"", \
182 CHECK_FD_SET(so, ign, nval) ? "RDNVAL":"")); \
183 } while (0)
184# endif /* !RT_OS_WINDOWS */
185# else /* VBOX_WITH_SIMPLIFIED_SLIRP_SYNC */
186# define DO_LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) \
187 do { \
188 LogRel((" " #proto " %R[natsock] %s %s %s\n", (so), FD_ISSET((so)->s, (r_fdset))?"READ":"",\
189 FD_ISSET((so)->s, (w_fdset))?"WRITE":"", FD_ISSET((so)->s, (x_fdset))?"OOB":"")); \
190 } while (0)
191# endif
192#else /* VBOX_WITH_DEBUG_NAT_SOCKETS */
193# define DO_LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) do {} while (0)
194#endif /* !VBOX_WITH_DEBUG_NAT_SOCKETS */
195
196#define LOG_NAT_SOCK(so, proto, winevent, r_fdset, w_fdset, x_fdset) DO_LOG_NAT_SOCK((so), proto, (winevent), r_fdset, w_fdset, x_fdset)
197
198static const uint8_t special_ethaddr[6] =
199{
200 0x52, 0x54, 0x00, 0x12, 0x35, 0x00
201};
202
203#ifdef RT_OS_WINDOWS
204
205static int get_dns_addr_domain(PNATState pData, bool fVerbose,
206 struct in_addr *pdns_addr,
207 const char **ppszDomain)
208{
209 int rc = 0;
210 FIXED_INFO *FixedInfo = NULL;
211 ULONG BufLen;
212 DWORD ret;
213 IP_ADDR_STRING *pIPAddr;
214 struct in_addr tmp_addr;
215
216 FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
217 BufLen = sizeof(FIXED_INFO);
218
219 /** @todo: this API returns all DNS servers, no matter whether the
220 * corresponding network adapter is disabled or not. Maybe replace
221 * this by GetAdapterAddresses(), which is XP/Vista only though. */
222 if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen))
223 {
224 if (FixedInfo)
225 {
226 GlobalFree(FixedInfo);
227 FixedInfo = NULL;
228 }
229 FixedInfo = GlobalAlloc(GPTR, BufLen);
230 }
231
232 if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS)
233 {
234 Log(("GetNetworkParams failed. ret = %08x\n", (u_int)ret ));
235 if (FixedInfo)
236 {
237 GlobalFree(FixedInfo);
238 FixedInfo = NULL;
239 }
240 rc = -1;
241 goto get_dns_prefix;
242 }
243
244#ifndef VBOX_WITH_MULTI_DNS
245 pIPAddr = &(FixedInfo->DnsServerList);
246 inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
247 Log(("nat: DNS Servers:\n"));
248 if (fVerbose || pdns_addr->s_addr != tmp_addr.s_addr)
249 LogRel(("NAT: DNS address: %s\n", pIPAddr->IpAddress.String));
250 *pdns_addr = tmp_addr;
251
252 pIPAddr = FixedInfo -> DnsServerList.Next;
253 while (pIPAddr)
254 {
255 if (fVerbose)
256 LogRel(("NAT: ignored DNS address: %s\n", pIPAddr ->IpAddress.String));
257 pIPAddr = pIPAddr ->Next;
258 }
259#else
260 /*localhost mask */
261 for (pIPAddr = &FixedInfo->DnsServerList; pIPAddr != NULL; pIPAddr = pIPAddr->Next)
262 {
263 struct dns_entry *da;
264 if(!inet_aton(pIPAddr->IpAddress.String, &tmp_addr))
265 continue;
266 da = RTMemAllocZ(sizeof (struct dns_entry));
267 if (da == NULL)
268 {
269 LogRel(("can't alloc memory for DNS entry\n"));
270 return -1;
271 }
272 /*check */
273 if ((da->de_addr.s_addr & htonl(IN_CLASSA_NET)) == ntohl(INADDR_LOOPBACK & IN_CLASSA_NET)) {
274 da->de_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
275 }
276 LIST_INSERT_HEAD(&pData->dns_list_head, da, de_list);
277 }
278#endif
279 if (FixedInfo)
280 {
281 GlobalFree(FixedInfo);
282 FixedInfo = NULL;
283 }
284
285get_dns_prefix:
286 if (ppszDomain)
287 {
288 OSVERSIONINFO ver;
289 char szDnsDomain[256];
290 DWORD dwSize = sizeof(szDnsDomain);
291
292 *ppszDomain = NULL;
293 GetVersionEx(&ver);
294 if (ver.dwMajorVersion >= 5)
295 {
296 /* GetComputerNameEx exists in Windows versions starting with 2000. */
297 if (GetComputerNameEx(ComputerNameDnsDomain, szDnsDomain, &dwSize))
298 {
299 if (szDnsDomain[0])
300 {
301 /* Just non-empty strings are valid. */
302 *ppszDomain = RTStrDup(szDnsDomain);
303 if (pData->fPassDomain)
304 {
305 if (fVerbose)
306 LogRel(("NAT: passing domain name %s\n", szDnsDomain));
307 }
308 else
309 Log(("nat: ignoring domain %s\n", szDnsDomain));
310 }
311 }
312 else
313 Log(("nat: GetComputerNameEx failed (%d)\n", GetLastError()));
314 }
315 }
316 return rc;
317}
318
319#else
320
321static int get_dns_addr_domain(PNATState pData, bool fVerbose,
322 struct in_addr *pdns_addr,
323 const char **ppszDomain)
324{
325 char buff[512];
326 char buff2[256];
327 FILE *f;
328 int found = 0;
329 struct in_addr tmp_addr;
330
331#ifdef RT_OS_OS2
332 /* Try various locations. */
333 char *etc = getenv("ETC");
334 f = NULL;
335 if (etc)
336 {
337 snprintf(buff, sizeof(buff), "%s/RESOLV2", etc);
338 f = fopen(buff, "rt");
339 }
340 if (!f)
341 {
342 snprintf(buff, sizeof(buff), "%s/RESOLV2", _PATH_ETC);
343 f = fopen(buff, "rt");
344 }
345 if (!f)
346 {
347 snprintf(buff, sizeof(buff), "%s/resolv.conf", _PATH_ETC);
348 f = fopen(buff, "rt");
349 }
350#else
351 f = fopen("/etc/resolv.conf", "r");
352#endif
353 if (!f)
354 return -1;
355
356 if (ppszDomain)
357 *ppszDomain = NULL;
358 Log(("nat: DNS Servers:\n"));
359 while (fgets(buff, 512, f) != NULL)
360 {
361#ifdef VBOX_WITH_MULTI_DNS
362 struct dns_entry *da = NULL;
363#endif
364 if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1)
365 {
366 if (!inet_aton(buff2, &tmp_addr))
367 continue;
368#ifndef VBOX_WITH_MULTI_DNS
369 /* If it's the first one, set it to dns_addr */
370 if (!found)
371 {
372 if (fVerbose || pdns_addr->s_addr != tmp_addr.s_addr)
373 LogRel(("NAT: DNS address: %s\n", buff2));
374 *pdns_addr = tmp_addr;
375 }
376 else
377 {
378 if (fVerbose)
379 LogRel(("NAT: ignored DNS address: %s\n", buff2));
380 }
381#else
382 /*localhost mask */
383 da = RTMemAllocZ(sizeof (struct dns_entry));
384 if (da == NULL)
385 {
386 LogRel(("can't alloc memory for DNS entry\n"));
387 return -1;
388 }
389 /*check */
390 da->de_addr.s_addr = tmp_addr.s_addr;
391 if ((da->de_addr.s_addr & htonl(IN_CLASSA_NET)) == ntohl(INADDR_LOOPBACK & IN_CLASSA_NET)) {
392 da->de_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
393 }
394 LIST_INSERT_HEAD(&pData->dns_list_head, da, de_list);
395#endif
396 found++;
397 }
398 if ( ppszDomain
399 && (!strncmp(buff, "domain", 6) || !strncmp(buff, "search", 6)))
400 {
401 /* Domain name/search list present. Pick first entry */
402 if (*ppszDomain == NULL)
403 {
404 char *tok;
405 char *saveptr;
406 tok = strtok_r(&buff[6], " \t\n", &saveptr);
407 if (tok)
408 {
409 *ppszDomain = RTStrDup(tok);
410 if (pData->fPassDomain)
411 {
412 if (fVerbose)
413 LogRel(("NAT: passing domain name %s\n", tok));
414 }
415 else
416 Log(("nat: ignoring domain %s\n", tok));
417 }
418 }
419 }
420 }
421 fclose(f);
422 if (!found)
423 return -1;
424 return 0;
425}
426
427#endif
428
429int get_dns_addr(PNATState pData, struct in_addr *pdns_addr)
430{
431 return get_dns_addr_domain(pData, false, pdns_addr, NULL);
432}
433
434int slirp_init(PNATState *ppData, const char *pszNetAddr, uint32_t u32Netmask,
435 bool fPassDomain, const char *pszTFTPPrefix,
436 const char *pszBootFile, void *pvUser)
437{
438 int fNATfailed = 0;
439 int rc;
440 PNATState pData = RTMemAllocZ(sizeof(NATState));
441 *ppData = pData;
442 if (!pData)
443 return VERR_NO_MEMORY;
444 if (u32Netmask & 0x1f)
445 /* CTL is x.x.x.15, bootp passes up to 16 IPs (15..31) */
446 return VERR_INVALID_PARAMETER;
447 memset(pData, '\0', sizeof(NATState));
448 pData->fPassDomain = fPassDomain;
449 pData->pvUser = pvUser;
450 tftp_prefix = pszTFTPPrefix;
451 bootp_filename = pszBootFile;
452 pData->netmask = u32Netmask;
453
454#ifdef RT_OS_WINDOWS
455 {
456 WSADATA Data;
457 WSAStartup(MAKEWORD(2,0), &Data);
458 }
459# if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC)
460 pData->phEvents[VBOX_SOCKET_EVENT_INDEX] = CreateEvent(NULL, FALSE, FALSE, NULL);
461# endif
462#endif
463#ifdef VBOX_WITH_SLIRP_MT
464 QSOCKET_LOCK_CREATE(tcb);
465 QSOCKET_LOCK_CREATE(udb);
466 rc = RTReqCreateQueue(&pData->pReqQueue);
467 AssertReleaseRC(rc);
468#endif
469
470 link_up = 1;
471
472 debug_init();
473 if_init(pData);
474 ip_init(pData);
475 icmp_init(pData);
476
477 /* Initialise mbufs *after* setting the MTU */
478 m_init(pData);
479
480 inet_aton(pszNetAddr, &special_addr);
481 alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
482 /* @todo: add ability to configure this staff */
483 pData->tftp_server.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_TFTP);
484
485 /* set default addresses */
486 inet_aton("127.0.0.1", &loopback_addr);
487#ifndef VBOX_WITH_MULTI_DNS
488 inet_aton("127.0.0.1", &dns_addr);
489
490 if (get_dns_addr_domain(pData, true, &dns_addr, &pData->pszDomain) < 0)
491#else
492 LIST_INIT(&pData->dns_list_head);
493 if (get_dns_addr_domain(pData, true, NULL, &pData->pszDomain) < 0)
494#endif
495 fNATfailed = 1;
496
497 getouraddr(pData);
498 return fNATfailed ? VINF_NAT_DNS : VINF_SUCCESS;
499}
500
501/**
502 * Statistics counters.
503 */
504void slirp_register_timers(PNATState pData, PPDMDRVINS pDrvIns)
505{
506#ifdef VBOX_WITH_STATISTICS
507 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatFill, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS,
508 STAMUNIT_TICKS_PER_CALL, "Profiling slirp fills", "/Drivers/NAT%d/Fill", pDrvIns->iInstance);
509 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPoll, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS,
510 STAMUNIT_TICKS_PER_CALL, "Profiling slirp polls", "/Drivers/NAT%d/Poll", pDrvIns->iInstance);
511 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatFastTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS,
512 STAMUNIT_TICKS_PER_CALL, "Profiling slirp fast timer", "/Drivers/NAT%d/TimerFast", pDrvIns->iInstance);
513 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatSlowTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS,
514 STAMUNIT_TICKS_PER_CALL, "Profiling slirp slow timer", "/Drivers/NAT%d/TimerSlow", pDrvIns->iInstance);
515 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatTCP, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
516 STAMUNIT_COUNT, "TCP sockets", "/Drivers/NAT%d/SockTCP", pDrvIns->iInstance);
517 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatTCPHot, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
518 STAMUNIT_COUNT, "TCP sockets active", "/Drivers/NAT%d/SockTCPHot", pDrvIns->iInstance);
519 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatUDP, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
520 STAMUNIT_COUNT, "UDP sockets", "/Drivers/NAT%d/SockUDP", pDrvIns->iInstance);
521 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatUDPHot, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
522 STAMUNIT_COUNT, "UDP sockets active", "/Drivers/NAT%d/SockUDPHot", pDrvIns->iInstance);
523#endif /* VBOX_WITH_STATISTICS */
524}
525
526/**
527 * Marks the link as up, making it possible to establish new connections.
528 */
529void slirp_link_up(PNATState pData)
530{
531 link_up = 1;
532}
533
534/**
535 * Marks the link as down and cleans up the current connections.
536 */
537void slirp_link_down(PNATState pData)
538{
539 struct socket *so;
540
541 while ((so = tcb.so_next) != &tcb)
542 {
543 if (so->so_state & SS_NOFDREF || so->s == -1)
544 sofree(pData, so);
545 else
546 tcp_drop(pData, sototcpcb(so), 0);
547 }
548
549 while ((so = udb.so_next) != &udb)
550 udp_detach(pData, so);
551
552 link_up = 0;
553}
554
555/**
556 * Terminates the slirp component.
557 */
558void slirp_term(PNATState pData)
559{
560#ifdef VBOX_WITH_MULTI_DNS
561 struct dns_entry *de = NULL;
562#endif
563 if (pData->pszDomain)
564 RTStrFree((char *)(void *)pData->pszDomain);
565
566#ifdef RT_OS_WINDOWS
567 pData->pfIcmpCloseHandle(pData->icmp_socket.sh);
568 FreeLibrary(pData->hmIcmpLibrary);
569 RTMemFree(pData->pvIcmpBuffer);
570# else
571 closesocket(pData->icmp_socket.s);
572#endif
573
574 slirp_link_down(pData);
575#ifdef VBOX_WITH_MULTI_DNS
576 while(!LIST_EMPTY(&pData->dns_list_head)) {
577 de = LIST_FIRST(&pData->dns_list_head);
578 LIST_REMOVE(de, de_list);
579 RTMemFree(de);
580 }
581#endif
582#ifdef RT_OS_WINDOWS
583 WSACleanup();
584#endif
585#ifdef LOG_ENABLED
586 Log(("\n"
587 "NAT statistics\n"
588 "--------------\n"
589 "\n"));
590 ipstats(pData);
591 tcpstats(pData);
592 udpstats(pData);
593 icmpstats(pData);
594 mbufstats(pData);
595 sockstats(pData);
596 Log(("\n"
597 "\n"
598 "\n"));
599#endif
600 RTMemFree(pData);
601}
602
603
604#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
605#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
606#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
607
608/*
609 * curtime kept to an accuracy of 1ms
610 */
611#ifdef RT_OS_WINDOWS
612static void updtime(PNATState pData)
613{
614 struct _timeb tb;
615
616 _ftime(&tb);
617 curtime = (u_int)tb.time * (u_int)1000;
618 curtime += (u_int)tb.millitm;
619}
620#else
621static void updtime(PNATState pData)
622{
623 gettimeofday(&tt, 0);
624
625 curtime = (u_int)tt.tv_sec * (u_int)1000;
626 curtime += (u_int)tt.tv_usec / (u_int)1000;
627
628 if ((tt.tv_usec % 1000) >= 500)
629 curtime++;
630}
631#endif
632
633#ifndef VBOX_WITH_SIMPLIFIED_SLIRP_SYNC
634void slirp_select_fill(PNATState pData, int *pnfds,
635 fd_set *readfds, fd_set *writefds, fd_set *xfds)
636#else /* !VBOX_WITH_SIMPLIFIED_SLIRP_SYNC */
637# ifdef RT_OS_WINDOWS
638void slirp_select_fill(PNATState pData, int *pnfds)
639# else /* RT_OS_WINDOWS */
640void slirp_select_fill(PNATState pData, int *pnfds, struct pollfd *polls)
641# endif /* !RT_OS_WINDOWS */
642#endif /* VBOX_WITH_SIMPLIFIED_SLIRP_SYNC */
643{
644 struct socket *so, *so_next;
645 int nfds;
646#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
647 int rc;
648 int error;
649#endif
650#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && !defined(RT_OS_WINDOWS)
651 int poll_index = 0;
652#endif
653 int i;
654
655 STAM_PROFILE_START(&pData->StatFill, a);
656
657 nfds = *pnfds;
658
659 /*
660 * First, TCP sockets
661 */
662 do_slowtimo = 0;
663 if (link_up)
664 {
665 /*
666 * *_slowtimo needs calling if there are IP fragments
667 * in the fragment queue, or there are TCP connections active
668 */
669 /* XXX:
670 * triggering of fragment expiration should be the same but use new macroses
671 */
672 do_slowtimo = (tcb.so_next != &tcb);
673 if (!do_slowtimo)
674 {
675 for (i = 0; i < IPREASS_NHASH; i++)
676 {
677 if (!TAILQ_EMPTY(&ipq[i]))
678 {
679 do_slowtimo = 1;
680 break;
681 }
682 }
683 }
684 ICMP_ENGAGE_EVENT(&pData->icmp_socket, readfds);
685
686 STAM_COUNTER_RESET(&pData->StatTCP);
687 STAM_COUNTER_RESET(&pData->StatTCPHot);
688
689 QSOCKET_FOREACH(so, so_next, tcp)
690 /* { */
691 STAM_COUNTER_INC(&pData->StatTCP);
692
693 /*
694 * See if we need a tcp_fasttimo
695 */
696 if ( time_fasttimo == 0
697 && so->so_tcpcb != NULL
698 && so->so_tcpcb->t_flags & TF_DELACK)
699 time_fasttimo = curtime; /* Flag when we want a fasttimo */
700
701 /*
702 * NOFDREF can include still connecting to local-host,
703 * newly socreated() sockets etc. Don't want to select these.
704 */
705 if (so->so_state & SS_NOFDREF || so->s == -1)
706 CONTINUE(tcp);
707
708 /*
709 * Set for reading sockets which are accepting
710 */
711 if (so->so_state & SS_FACCEPTCONN)
712 {
713 STAM_COUNTER_INC(&pData->StatTCPHot);
714 TCP_ENGAGE_EVENT1(so, readfds);
715 CONTINUE(tcp);
716 }
717
718 /*
719 * Set for writing sockets which are connecting
720 */
721 if (so->so_state & SS_ISFCONNECTING)
722 {
723 Log2(("connecting %R[natsock] engaged\n",so));
724 STAM_COUNTER_INC(&pData->StatTCPHot);
725 TCP_ENGAGE_EVENT1(so, writefds);
726 }
727
728 /*
729 * Set for writing if we are connected, can send more, and
730 * we have something to send
731 */
732 if (CONN_CANFSEND(so) && so->so_rcv.sb_cc)
733 {
734 STAM_COUNTER_INC(&pData->StatTCPHot);
735 TCP_ENGAGE_EVENT1(so, writefds);
736 }
737
738 /*
739 * Set for reading (and urgent data) if we are connected, can
740 * receive more, and we have room for it XXX /2 ?
741 */
742 if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2)))
743 {
744 STAM_COUNTER_INC(&pData->StatTCPHot);
745 TCP_ENGAGE_EVENT2(so, readfds, xfds);
746 }
747 LOOP_LABEL(tcp, so, so_next);
748 }
749
750 /*
751 * UDP sockets
752 */
753 STAM_COUNTER_RESET(&pData->StatUDP);
754 STAM_COUNTER_RESET(&pData->StatUDPHot);
755
756 QSOCKET_FOREACH(so, so_next, udp)
757 /* { */
758
759 STAM_COUNTER_INC(&pData->StatUDP);
760
761 /*
762 * See if it's timed out
763 */
764 if (so->so_expire)
765 {
766 if (so->so_expire <= curtime)
767 {
768#ifdef VBOX_WITH_SLIRP_MT
769 /* we need so_next for continue our cycle*/
770 so_next = so->so_next;
771#endif
772 UDP_DETACH(pData, so, so_next);
773 CONTINUE_NO_UNLOCK(udp);
774 }
775 else
776 do_slowtimo = 1; /* Let socket expire */
777 }
778
779 /*
780 * When UDP packets are received from over the link, they're
781 * sendto()'d straight away, so no need for setting for writing
782 * Limit the number of packets queued by this session to 4.
783 * Note that even though we try and limit this to 4 packets,
784 * the session could have more queued if the packets needed
785 * to be fragmented.
786 *
787 * (XXX <= 4 ?)
788 */
789 if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4)
790 {
791 STAM_COUNTER_INC(&pData->StatUDPHot);
792 UDP_ENGAGE_EVENT(so, readfds);
793 }
794 LOOP_LABEL(udp, so, so_next);
795 }
796
797 }
798
799#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC)
800# if defined(RT_OS_WINDOWS)
801 *pnfds = VBOX_EVENT_COUNT;
802# else /* RT_OS_WINDOWS */
803 *pnfds = poll_index;
804# endif /* !RT_OS_WINDOWS */
805#else /* VBOX_WITH_SIMPLIFIED_SLIRP_SYNC */
806 *pnfds = nfds;
807#endif /* !VBOX_WITH_SIMPLIFIED_SLIRP_SYNC */
808
809 STAM_PROFILE_STOP(&pData->StatFill, a);
810}
811
812#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC)
813# if defined(RT_OS_WINDOWS)
814void slirp_select_poll(PNATState pData, int fTimeout, int fIcmp)
815# else /* RT_OS_WINDOWS */
816void slirp_select_poll(PNATState pData, struct pollfd *polls, int ndfs)
817# endif /* !RT_OS_WINDOWS */
818#else /* VBOX_WITH_SIMPLIFIED_SLIRP_SYNC */
819void slirp_select_poll(PNATState pData, fd_set *readfds, fd_set *writefds, fd_set *xfds)
820#endif /* !VBOX_WITH_SIMPLIFIED_SLIRP_SYNC */
821{
822 struct socket *so, *so_next;
823 int ret;
824#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
825 WSANETWORKEVENTS NetworkEvents;
826 int rc;
827 int error;
828#endif
829#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && !defined(RT_OS_WINDOWS)
830 int poll_index = 0;
831#endif
832
833 STAM_PROFILE_START(&pData->StatPoll, a);
834
835 /* Update time */
836 updtime(pData);
837
838 /*
839 * See if anything has timed out
840 */
841 if (link_up)
842 {
843 if (time_fasttimo && ((curtime - time_fasttimo) >= 2))
844 {
845 STAM_PROFILE_START(&pData->StatFastTimer, a);
846 tcp_fasttimo(pData);
847 time_fasttimo = 0;
848 STAM_PROFILE_STOP(&pData->StatFastTimer, a);
849 }
850 if (do_slowtimo && ((curtime - last_slowtimo) >= 499))
851 {
852 STAM_PROFILE_START(&pData->StatSlowTimer, a);
853 ip_slowtimo(pData);
854 tcp_slowtimo(pData);
855 last_slowtimo = curtime;
856 STAM_PROFILE_STOP(&pData->StatSlowTimer, a);
857 }
858 }
859#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
860 if (fTimeout)
861 return; /* only timer update */
862#endif
863
864 /*
865 * Check sockets
866 */
867 if (link_up)
868 {
869#if defined(RT_OS_WINDOWS)
870 /*XXX: before renaming please make see define
871 * fIcmp in slirp_state.h
872 */
873 if (fIcmp)
874 sorecvfrom(pData, &pData->icmp_socket);
875#else
876 if ( (pData->icmp_socket.s != -1)
877 && CHECK_FD_SET(&pData->icmp_socket, ignored, readfds))
878 sorecvfrom(pData, &pData->icmp_socket);
879#endif
880 /*
881 * Check TCP sockets
882 */
883 QSOCKET_FOREACH(so, so_next, tcp)
884 /* { */
885
886#ifdef VBOX_WITH_SLIRP_MT
887 if ( so->so_state & SS_NOFDREF
888 && so->so_deleted == 1)
889 {
890 struct socket *son, *sop = NULL;
891 QSOCKET_LOCK(tcb);
892 if (so->so_next != NULL)
893 {
894 if (so->so_next != &tcb)
895 SOCKET_LOCK(so->so_next);
896 son = so->so_next;
897 }
898 if ( so->so_prev != &tcb
899 && so->so_prev != NULL)
900 {
901 SOCKET_LOCK(so->so_prev);
902 sop = so->so_prev;
903 }
904 QSOCKET_UNLOCK(tcb);
905 remque(pData, so);
906 NSOCK_DEC();
907 SOCKET_UNLOCK(so);
908 SOCKET_LOCK_DESTROY(so);
909 RTMemFree(so);
910 so_next = son;
911 if (sop != NULL)
912 SOCKET_UNLOCK(sop);
913 CONTINUE_NO_UNLOCK(tcp);
914 }
915#endif
916 /*
917 * FD_ISSET is meaningless on these sockets
918 * (and they can crash the program)
919 */
920 if (so->so_state & SS_NOFDREF || so->s == -1)
921 CONTINUE(tcp);
922
923 POLL_TCP_EVENTS(rc, error, so, &NetworkEvents);
924
925 LOG_NAT_SOCK(so, TCP, &NetworkEvents, readfds, writefds, xfds);
926
927 /*
928 * Check for URG data
929 * This will soread as well, so no need to
930 * test for readfds below if this succeeds
931 */
932
933 /* out-of-band data */
934 if (CHECK_FD_SET(so, NetworkEvents, xfds))
935 {
936 sorecvoob(pData, so);
937 }
938
939 /*
940 * Check sockets for reading
941 */
942 else if ( CHECK_FD_SET(so, NetworkEvents, readfds)
943 || WIN_CHECK_FD_SET(so, NetworkEvents, acceptds))
944 {
945 /*
946 * Check for incoming connections
947 */
948 if (so->so_state & SS_FACCEPTCONN)
949 {
950 TCP_CONNECT(pData, so);
951#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
952 if (!(NetworkEvents.lNetworkEvents & FD_CLOSE))
953#endif
954 CONTINUE(tcp);
955 }
956
957 ret = soread(pData, so);
958 /* Output it if we read something */
959 if (ret > 0)
960 TCP_OUTPUT(pData, sototcpcb(so));
961 }
962
963#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
964 /*
965 * Check for FD_CLOSE events.
966 */
967 if (NetworkEvents.lNetworkEvents & FD_CLOSE)
968 {
969 /*
970 * drain the socket
971 */
972 for (;;)
973 {
974 ret = soread(pData, so);
975 if (ret > 0)
976 TCP_OUTPUT(pData, sototcpcb(so));
977 else
978 break;
979 }
980 }
981#endif
982
983 /*
984 * Check sockets for writing
985 */
986 if (CHECK_FD_SET(so, NetworkEvents, writefds))
987 {
988 /*
989 * Check for non-blocking, still-connecting sockets
990 */
991 if (so->so_state & SS_ISFCONNECTING)
992 {
993 Log2(("connecting %R[natsock] catched\n", so));
994 /* Connected */
995 so->so_state &= ~SS_ISFCONNECTING;
996
997 /*
998 * This should be probably guarded by PROBE_CONN too. Anyway,
999 * we disable it on OS/2 because the below send call returns
1000 * EFAULT which causes the opened TCP socket to close right
1001 * after it has been opened and connected.
1002 */
1003#ifndef RT_OS_OS2
1004 ret = send(so->s, (const char *)&ret, 0, 0);
1005 if (ret < 0)
1006 {
1007 /* XXXXX Must fix, zero bytes is a NOP */
1008 if ( errno == EAGAIN
1009 || errno == EWOULDBLOCK
1010 || errno == EINPROGRESS
1011 || errno == ENOTCONN)
1012 CONTINUE(tcp);
1013
1014 /* else failed */
1015 so->so_state = SS_NOFDREF;
1016 }
1017 /* else so->so_state &= ~SS_ISFCONNECTING; */
1018#endif
1019
1020 /*
1021 * Continue tcp_input
1022 */
1023 TCP_INPUT(pData, (struct mbuf *)NULL, sizeof(struct ip), so);
1024 /* continue; */
1025 }
1026 else
1027 SOWRITE(ret, pData, so);
1028 /*
1029 * XXX If we wrote something (a lot), there could be the need
1030 * for a window update. In the worst case, the remote will send
1031 * a window probe to get things going again.
1032 */
1033 }
1034
1035 /*
1036 * Probe a still-connecting, non-blocking socket
1037 * to check if it's still alive
1038 */
1039#ifdef PROBE_CONN
1040 if (so->so_state & SS_ISFCONNECTING)
1041 {
1042 ret = recv(so->s, (char *)&ret, 0, 0);
1043
1044 if (ret < 0)
1045 {
1046 /* XXX */
1047 if ( errno == EAGAIN
1048 || errno == EWOULDBLOCK
1049 || errno == EINPROGRESS
1050 || errno == ENOTCONN)
1051 {
1052 CONTINUE(tcp); /* Still connecting, continue */
1053 }
1054
1055 /* else failed */
1056 so->so_state = SS_NOFDREF;
1057
1058 /* tcp_input will take care of it */
1059 }
1060 else
1061 {
1062 ret = send(so->s, &ret, 0, 0);
1063 if (ret < 0)
1064 {
1065 /* XXX */
1066 if ( errno == EAGAIN
1067 || errno == EWOULDBLOCK
1068 || errno == EINPROGRESS
1069 || errno == ENOTCONN)
1070 {
1071 CONTINUE(tcp);
1072 }
1073 /* else failed */
1074 so->so_state = SS_NOFDREF;
1075 }
1076 else
1077 so->so_state &= ~SS_ISFCONNECTING;
1078
1079 }
1080 TCP_INPUT((struct mbuf *)NULL, sizeof(struct ip),so);
1081 } /* SS_ISFCONNECTING */
1082#endif
1083#ifndef RT_OS_WINDOWS
1084 if ( UNIX_CHECK_FD_SET(so, NetworkEvents, rdhup)
1085 && UNIX_CHECK_FD_SET(so, NetworkEvents, rderr))
1086 {
1087 if (so->so_state & SS_ISFCONNECTING)
1088 {
1089 so->so_state = SS_NOFDREF;
1090 TCP_INPUT(pData, (struct mbuf *)NULL, sizeof(struct ip), so);
1091 }
1092 /* Here should be other error handlings */
1093 }
1094#endif
1095 LOOP_LABEL(tcp, so, so_next);
1096 }
1097
1098 /*
1099 * Now UDP sockets.
1100 * Incoming packets are sent straight away, they're not buffered.
1101 * Incoming UDP data isn't buffered either.
1102 */
1103 QSOCKET_FOREACH(so, so_next, udp)
1104 /* { */
1105#ifdef VBOX_WITH_SLIRP_MT
1106 if ( so->so_state & SS_NOFDREF
1107 && so->so_deleted == 1)
1108 {
1109 struct socket *son, *sop = NULL;
1110 QSOCKET_LOCK(udb);
1111 if (so->so_next != NULL)
1112 {
1113 if (so->so_next != &udb)
1114 SOCKET_LOCK(so->so_next);
1115 son = so->so_next;
1116 }
1117 if ( so->so_prev != &udb
1118 && so->so_prev != NULL)
1119 {
1120 SOCKET_LOCK(so->so_prev);
1121 sop = so->so_prev;
1122 }
1123 QSOCKET_UNLOCK(udb);
1124 remque(pData, so);
1125 NSOCK_DEC();
1126 SOCKET_UNLOCK(so);
1127 SOCKET_LOCK_DESTROY(so);
1128 RTMemFree(so);
1129 so_next = son;
1130 if (sop != NULL)
1131 SOCKET_UNLOCK(sop);
1132 CONTINUE_NO_UNLOCK(udp);
1133 }
1134#endif
1135 POLL_UDP_EVENTS(rc, error, so, &NetworkEvents);
1136
1137 LOG_NAT_SOCK(so, UDP, &NetworkEvents, readfds, writefds, xfds);
1138
1139 if (so->s != -1 && CHECK_FD_SET(so, NetworkEvents, readfds))
1140 {
1141 SORECVFROM(pData, so);
1142 }
1143 LOOP_LABEL(udp, so, so_next);
1144 }
1145
1146 }
1147
1148#ifndef VBOX_WITH_SLIRP_MT
1149 /*
1150 * See if we can start outputting
1151 */
1152 if (if_queued && link_up)
1153 if_start(pData);
1154#endif
1155
1156 STAM_PROFILE_STOP(&pData->StatPoll, a);
1157}
1158
1159#define ETH_ALEN 6
1160#define ETH_HLEN 14
1161
1162#define ARPOP_REQUEST 1 /* ARP request */
1163#define ARPOP_REPLY 2 /* ARP reply */
1164
1165struct ethhdr
1166{
1167 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
1168 unsigned char h_source[ETH_ALEN]; /* source ether addr */
1169 unsigned short h_proto; /* packet type ID field */
1170};
1171
1172struct arphdr
1173{
1174 unsigned short ar_hrd; /* format of hardware address */
1175 unsigned short ar_pro; /* format of protocol address */
1176 unsigned char ar_hln; /* length of hardware address */
1177 unsigned char ar_pln; /* length of protocol address */
1178 unsigned short ar_op; /* ARP opcode (command) */
1179
1180 /*
1181 * Ethernet looks like this : This bit is variable sized however...
1182 */
1183 unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
1184 unsigned char ar_sip[4]; /* sender IP address */
1185 unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
1186 unsigned char ar_tip[4]; /* target IP address */
1187};
1188
1189static
1190#ifdef VBOX_WITH_SIMPLIFIED_SLIRP_SYNC
1191void arp_input(PNATState pData, struct mbuf *m)
1192#else
1193void arp_input(PNATState pData, const uint8_t *pkt, int pkt_len)
1194#endif
1195{
1196 struct ethhdr *eh;
1197 struct ethhdr *reh;
1198 struct arphdr *ah;
1199 struct arphdr *rah;
1200 int ar_op;
1201 struct ex_list *ex_ptr;
1202 uint32_t htip;
1203#ifndef VBOX_WITH_SIMPLIFIED_SLIRP_SYNC
1204 uint8_t arp_reply[sizeof(struct arphdr) + ETH_HLEN];
1205 eh = (struct ethhdr *)pkt;
1206#else
1207 struct mbuf *mr;
1208 eh = mtod(m, struct ethhdr *);
1209#endif
1210 ah = (struct arphdr *)&eh[1];
1211 htip = ntohl(*(uint32_t*)ah->ar_tip);
1212
1213#ifdef VBOX_WITH_SIMPLIFIED_SLIRP_SYNC
1214 mr = m_get(pData);
1215 mr->m_data += if_maxlinkhdr;
1216 mr->m_len = sizeof(struct arphdr);
1217 rah = mtod(mr, struct arphdr *);
1218#else
1219 reh = (struct ethhdr *)arp_reply;
1220 rah = (struct arphdr *)&reh[1];
1221#endif
1222
1223 ar_op = ntohs(ah->ar_op);
1224 switch(ar_op)
1225 {
1226 case ARPOP_REQUEST:
1227 if ((htip & pData->netmask) == ntohl(special_addr.s_addr))
1228 {
1229 if ( CTL_CHECK(htip,CTL_DNS)
1230 || CTL_CHECK(htip, CTL_ALIAS)
1231 || CTL_CHECK(htip, CTL_TFTP))
1232 goto arp_ok;
1233 for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
1234 {
1235 if ((htip & ~pData->netmask) == ex_ptr->ex_addr)
1236 goto arp_ok;
1237 }
1238 return;
1239 arp_ok:
1240
1241#ifndef VBOX_WITH_SIMPLIFIED_SLIRP_SYNC
1242 memcpy(reh->h_dest, eh->h_source, ETH_ALEN);
1243 memcpy(reh->h_source, &special_addr, ETH_ALEN);
1244 reh->h_source[5] = ah->ar_tip[3];
1245 reh->h_proto = htons(ETH_P_ARP);
1246#endif
1247 rah->ar_hrd = htons(1);
1248 rah->ar_pro = htons(ETH_P_IP);
1249 rah->ar_hln = ETH_ALEN;
1250 rah->ar_pln = 4;
1251 rah->ar_op = htons(ARPOP_REPLY);
1252 memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN);
1253
1254 switch (htip & ~pData->netmask)
1255 {
1256 case CTL_DNS:
1257 case CTL_ALIAS:
1258 rah->ar_sha[5] = (uint8_t)(htip & ~pData->netmask);
1259 break;
1260 default:;
1261 }
1262
1263 memcpy(rah->ar_sip, ah->ar_tip, 4);
1264 memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
1265 memcpy(rah->ar_tip, ah->ar_sip, 4);
1266#ifdef VBOX_WITH_SIMPLIFIED_SLIRP_SYNC
1267 if_encap(pData, ETH_P_ARP, mr);
1268 m_free(pData, m);
1269#else
1270 slirp_output(pData->pvUser, arp_reply, sizeof(arp_reply));
1271#endif
1272 }
1273 break;
1274 default:
1275 break;
1276 }
1277}
1278
1279void slirp_input(PNATState pData, const uint8_t *pkt, int pkt_len)
1280{
1281 struct mbuf *m;
1282 int proto;
1283 static bool fWarnedIpv6;
1284
1285 if (pkt_len < ETH_HLEN)
1286 {
1287 LogRel(("NAT: packet having size %d has been ingnored\n", pkt_len));
1288 return;
1289 }
1290
1291 m = m_get(pData);
1292 if (!m)
1293 {
1294 LogRel(("can't allocate new mbuf\n"));
1295 return;
1296 }
1297
1298 /* Note: we add to align the IP header */
1299
1300 if (M_FREEROOM(m) < pkt_len)
1301 m_inc(m, pkt_len);
1302
1303 m->m_len = pkt_len ;
1304 memcpy(m->m_data, pkt, pkt_len);
1305
1306 proto = ntohs(*(uint16_t *)(pkt + 12));
1307 switch(proto)
1308 {
1309 case ETH_P_ARP:
1310#ifdef VBOX_WITH_SIMPLIFIED_SLIRP_SYNC
1311 arp_input(pData, m);
1312#else
1313 arp_input(pData, pkt, pkt_len);
1314 m_free(pData, m);
1315#endif
1316 break;
1317 case ETH_P_IP:
1318 /* Update time. Important if the network is very quiet, as otherwise
1319 * the first outgoing connection gets an incorrect timestamp. */
1320 updtime(pData);
1321 m->m_data += ETH_HLEN;
1322 m->m_len -= ETH_HLEN;
1323 ip_input(pData, m);
1324 break;
1325 case ETH_P_IPV6:
1326 m_free(pData, m);
1327 if (!fWarnedIpv6)
1328 {
1329 LogRel(("NAT: IPv6 not supported\n"));
1330 fWarnedIpv6 = true;
1331 }
1332 break;
1333 default:
1334 LogRel(("NAT: Unsupported protocol %x\n", proto));
1335 m_free(pData, m);
1336 break;
1337 }
1338 RTMemFree((void *)pkt);
1339}
1340
1341/* output the IP packet to the ethernet device */
1342#ifdef VBOX_WITH_SIMPLIFIED_SLIRP_SYNC
1343void if_encap(PNATState pData, uint16_t eth_proto, struct mbuf *m)
1344#else
1345void if_encap(PNATState pData, uint8_t *ip_data, int ip_data_len)
1346#endif
1347{
1348#ifdef VBOX_WITH_SIMPLIFIED_SLIRP_SYNC
1349 struct ethhdr *eh;
1350 uint8_t *buf = RTMemAlloc(1600);
1351 m->m_data -= if_maxlinkhdr;
1352 m->m_len += ETH_HLEN;
1353 eh = mtod(m, struct ethhdr *);
1354#else
1355 uint8_t buf[1600];
1356 struct ethhdr *eh = (struct ethhdr *)buf;
1357
1358 if (ip_data_len + ETH_HLEN > sizeof(buf))
1359 return;
1360
1361 memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
1362#endif
1363
1364
1365 memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
1366 memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
1367 /* XXX: not correct */
1368 eh->h_source[5] = CTL_ALIAS;
1369#ifdef VBOX_WITH_SIMPLIFIED_SLIRP_SYNC
1370 eh->h_proto = htons(eth_proto);
1371#if 0
1372 slirp_output(pData->pvUser, m, mtod(m, uint8_t *), m->m_len);
1373#else
1374 memcpy(buf, mtod(m, uint8_t *), m->m_len);
1375 slirp_output(pData->pvUser, NULL, buf, m->m_len);
1376 m_free(pData, m);
1377#endif
1378#else
1379 eh->h_proto = htons(ETH_P_IP);
1380 slirp_output(pData->pvUser, buf, ip_data_len + ETH_HLEN);
1381#endif
1382}
1383
1384int slirp_redir(PNATState pData, int is_udp, int host_port,
1385 struct in_addr guest_addr, int guest_port)
1386{
1387 if (is_udp)
1388 {
1389 if (!udp_listen(pData, htons(host_port), guest_addr.s_addr,
1390 htons(guest_port), 0))
1391 return -1;
1392 }
1393 else
1394 {
1395 if (!solisten(pData, htons(host_port), guest_addr.s_addr,
1396 htons(guest_port), 0))
1397 return -1;
1398 }
1399 return 0;
1400}
1401
1402int slirp_add_exec(PNATState pData, int do_pty, const char *args, int addr_low_byte,
1403 int guest_port)
1404{
1405 return add_exec(&exec_list, do_pty, (char *)args,
1406 addr_low_byte, htons(guest_port));
1407}
1408
1409void slirp_set_ethaddr(PNATState pData, const uint8_t *ethaddr)
1410{
1411 memcpy(client_ethaddr, ethaddr, ETH_ALEN);
1412}
1413
1414#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
1415HANDLE *slirp_get_events(PNATState pData)
1416{
1417 return pData->phEvents;
1418}
1419void slirp_register_external_event(PNATState pData, HANDLE hEvent, int index)
1420{
1421 pData->phEvents[index] = hEvent;
1422}
1423#endif
1424
1425unsigned int slirp_get_timeout_ms(PNATState pData)
1426{
1427 if (link_up)
1428 {
1429 if (time_fasttimo)
1430 return 2;
1431 if (do_slowtimo)
1432 return 500; /* see PR_SLOWHZ */
1433 }
1434 return 0;
1435}
1436
1437#ifndef RT_OS_WINDOWS
1438int slirp_get_nsock(PNATState pData)
1439{
1440 return pData->nsock;
1441}
1442#endif
1443
1444/*
1445 * this function called from NAT thread
1446 */
1447void slirp_post_sent(PNATState pData, void *pvArg)
1448{
1449 struct socket *so = 0;
1450 struct tcpcb *tp = 0;
1451 struct mbuf *m = (struct mbuf *)pvArg;
1452 m_free(pData, m);
1453}
1454#ifdef VBOX_WITH_SLIRP_MT
1455void slirp_process_queue(PNATState pData)
1456{
1457 RTReqProcess(pData->pReqQueue, RT_INDEFINITE_WAIT);
1458}
1459void *slirp_get_queue(PNATState pData)
1460{
1461 return pData->pReqQueue;
1462}
1463#endif
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