VirtualBox

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

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

removing freeing of inlined array

  • Property svn:eol-style set to native
File size: 34.7 KB
Line 
1#include "slirp.h"
2#ifdef RT_OS_OS2
3# include <paths.h>
4#endif
5
6/* disable these counters for the final release */
7/* #define VBOX_WITHOUT_RELEASE_STATISTICS */
8
9#include <VBox/err.h>
10#include <VBox/pdmdrv.h>
11#include <iprt/assert.h>
12
13static const uint8_t special_ethaddr[6] = {
14 0x52, 0x54, 0x00, 0x12, 0x35, 0x00
15};
16
17#ifdef _WIN32
18
19static int get_dns_addr_domain(PNATState pData, bool fVerbose,
20 struct in_addr *pdns_addr,
21 const char **ppszDomain)
22{
23 int rc = 0;
24 FIXED_INFO *FixedInfo=NULL;
25 ULONG BufLen;
26 DWORD ret;
27 IP_ADDR_STRING *pIPAddr;
28 struct in_addr tmp_addr;
29
30 FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
31 BufLen = sizeof(FIXED_INFO);
32
33 /** @todo: this API returns all DNS servers, no matter whether the
34 * corresponding network adapter is disabled or not. Maybe replace
35 * this by GetAdapterAddresses(), which is XP/Vista only though. */
36 if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
37 if (FixedInfo) {
38 GlobalFree(FixedInfo);
39 FixedInfo = NULL;
40 }
41 FixedInfo = GlobalAlloc(GPTR, BufLen);
42 }
43
44 if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
45 Log(("GetNetworkParams failed. ret = %08x\n", (u_int)ret ));
46 if (FixedInfo) {
47 GlobalFree(FixedInfo);
48 FixedInfo = NULL;
49 }
50 rc = -1;
51 goto get_dns_prefix;
52 }
53
54 pIPAddr = &(FixedInfo->DnsServerList);
55 inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
56 Log(("nat: DNS Servers:\n"));
57 if (fVerbose || pdns_addr->s_addr != tmp_addr.s_addr)
58 LogRel(("NAT: DNS address: %s\n", pIPAddr->IpAddress.String));
59 *pdns_addr = tmp_addr;
60
61 pIPAddr = FixedInfo -> DnsServerList.Next;
62 while ( pIPAddr )
63 {
64 if (fVerbose)
65 LogRel(("NAT: ignored DNS address: %s\n", pIPAddr ->IpAddress.String));
66 pIPAddr = pIPAddr ->Next;
67 }
68 if (FixedInfo) {
69 GlobalFree(FixedInfo);
70 FixedInfo = NULL;
71 }
72
73get_dns_prefix:
74 if (ppszDomain)
75 {
76 OSVERSIONINFO ver;
77 char szDnsDomain[256];
78 DWORD dwSize = sizeof(szDnsDomain);
79
80 *ppszDomain = NULL;
81 GetVersionEx(&ver);
82 if (ver.dwMajorVersion >= 5)
83 {
84 /* GetComputerNameEx exists in Windows versions starting with 2000. */
85 if (GetComputerNameEx(ComputerNameDnsDomain, szDnsDomain, &dwSize))
86 {
87 if (szDnsDomain[0])
88 {
89 /* Just non-empty strings are valid. */
90 *ppszDomain = RTStrDup(szDnsDomain);
91 if (pData->fPassDomain)
92 {
93 if (fVerbose)
94 LogRel(("NAT: passing domain name %s\n", szDnsDomain));
95 }
96 else
97 Log(("nat: ignoring domain %s\n", szDnsDomain));
98 }
99 }
100 else
101 Log(("nat: GetComputerNameEx failed (%d)\n", GetLastError()));
102 }
103 }
104 return rc;
105}
106
107#else
108
109static int get_dns_addr_domain(PNATState pData, bool fVerbose,
110 struct in_addr *pdns_addr,
111 const char **ppszDomain)
112{
113 char buff[512];
114 char buff2[256];
115 FILE *f;
116 int found = 0;
117 struct in_addr tmp_addr;
118
119#ifdef RT_OS_OS2
120 /* Try various locations. */
121 char *etc = getenv("ETC");
122 f = NULL;
123 if (etc)
124 {
125 snprintf(buff, sizeof(buff), "%s/RESOLV2", etc);
126 f = fopen(buff, "rt");
127 }
128 if (!f) {
129 snprintf(buff, sizeof(buff), "%s/RESOLV2", _PATH_ETC);
130 f = fopen(buff, "rt");
131 }
132 if (!f) {
133 snprintf(buff, sizeof(buff), "%s/resolv.conf", _PATH_ETC);
134 f = fopen(buff, "rt");
135 }
136#else
137 f = fopen("/etc/resolv.conf", "r");
138#endif
139 if (!f)
140 return -1;
141
142 if (ppszDomain)
143 *ppszDomain = NULL;
144 Log(("nat: DNS Servers:\n"));
145 while (fgets(buff, 512, f) != NULL) {
146 if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
147 if (!inet_aton(buff2, &tmp_addr))
148 continue;
149 if (tmp_addr.s_addr == loopback_addr.s_addr)
150 tmp_addr = our_addr;
151 /* If it's the first one, set it to dns_addr */
152 if (!found)
153 {
154 if (fVerbose || pdns_addr->s_addr != tmp_addr.s_addr)
155 LogRel(("NAT: DNS address: %s\n", buff2));
156 *pdns_addr = tmp_addr;
157 }
158 else
159 {
160 if (fVerbose)
161 LogRel(("NAT: ignored DNS address: %s\n", buff2));
162 }
163 found++;
164 }
165 if ( ppszDomain
166 && (!strncmp(buff, "domain", 6) || !strncmp(buff, "search", 6)))
167 {
168 /* Domain name/search list present. Pick first entry */
169 if (*ppszDomain == NULL)
170 {
171 char *tok;
172 char *saveptr;
173 tok = strtok_r(&buff[6], " \t\n", &saveptr);
174 if (tok)
175 {
176 *ppszDomain = RTStrDup(tok);
177 if (pData->fPassDomain)
178 {
179 if (fVerbose)
180 LogRel(("NAT: passing domain name %s\n", tok));
181 }
182 else
183 Log(("nat: ignoring domain %s\n", tok));
184 }
185 }
186 }
187 }
188 fclose(f);
189 if (!found)
190 return -1;
191 return 0;
192}
193
194#endif
195
196int get_dns_addr(PNATState pData, struct in_addr *pdns_addr)
197{
198 return get_dns_addr_domain(pData, false, pdns_addr, NULL);
199}
200
201int slirp_init(PNATState *ppData, const char *pszNetAddr, uint32_t u32Netmask,
202 bool fPassDomain, const char *pszTFTPPrefix,
203 const char *pszBootFile, void *pvUser)
204{
205 int fNATfailed = 0;
206 PNATState pData = malloc(sizeof(NATState));
207 *ppData = pData;
208 if (!pData)
209 return VERR_NO_MEMORY;
210 if (u32Netmask & 0x1f)
211 /* CTL is x.x.x.15, bootp passes up to 16 IPs (15..31) */
212 return VERR_INVALID_PARAMETER;
213 memset(pData, '\0', sizeof(NATState));
214 pData->fPassDomain = fPassDomain;
215 pData->pvUser = pvUser;
216#if ARCH_BITS == 64
217 pData->cpvHashUsed = 1;
218#endif
219 tftp_prefix = pszTFTPPrefix;
220 bootp_filename = pszBootFile;
221 pData->netmask = u32Netmask;
222
223#ifdef _WIN32
224 {
225 WSADATA Data;
226 WSAStartup(MAKEWORD(2,0), &Data);
227 }
228#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
229 pData->phEvents[VBOX_SOCKET_EVENT_INDEX] = CreateEvent(NULL, FALSE, FALSE, NULL);
230#endif
231#endif
232
233 Assert(sizeof(struct ip) == 20);
234 link_up = 1;
235
236 if_init(pData);
237 ip_init(pData);
238
239 /* Initialise mbufs *after* setting the MTU */
240 m_init(pData);
241
242 /* set default addresses */
243 inet_aton("127.0.0.1", &loopback_addr);
244 inet_aton("127.0.0.1", &dns_addr);
245
246 if (get_dns_addr_domain(pData, true, &dns_addr, &pData->pszDomain) < 0)
247 fNATfailed = 1;
248
249 inet_aton(pszNetAddr, &special_addr);
250 alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
251 getouraddr(pData);
252 return fNATfailed ? VINF_NAT_DNS : VINF_SUCCESS;
253}
254
255/**
256 * Statistics counters.
257 */
258void slirp_register_timers(PNATState pData, PPDMDRVINS pDrvIns)
259{
260#ifndef VBOX_WITHOUT_RELEASE_STATISTICS
261 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatFill, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS,
262 STAMUNIT_TICKS_PER_CALL, "Profiling slirp fills", "/Drivers/NAT%d/Fill", pDrvIns->iInstance);
263 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatPoll, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS,
264 STAMUNIT_TICKS_PER_CALL, "Profiling slirp polls", "/Drivers/NAT%d/Poll", pDrvIns->iInstance);
265 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatFastTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS,
266 STAMUNIT_TICKS_PER_CALL, "Profiling slirp fast timer", "/Drivers/NAT%d/TimerFast", pDrvIns->iInstance);
267 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatSlowTimer, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS,
268 STAMUNIT_TICKS_PER_CALL, "Profiling slirp slow timer", "/Drivers/NAT%d/TimerSlow", pDrvIns->iInstance);
269 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatTCP, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
270 STAMUNIT_COUNT, "TCP sockets", "/Drivers/NAT%d/SockTCP", pDrvIns->iInstance);
271 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatTCPHot, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
272 STAMUNIT_COUNT, "TCP sockets active", "/Drivers/NAT%d/SockTCPHot", pDrvIns->iInstance);
273 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatUDP, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
274 STAMUNIT_COUNT, "UDP sockets", "/Drivers/NAT%d/SockUDP", pDrvIns->iInstance);
275 PDMDrvHlpSTAMRegisterF(pDrvIns, &pData->StatUDPHot, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS,
276 STAMUNIT_COUNT, "UDP sockets active", "/Drivers/NAT%d/SockUDPHot", pDrvIns->iInstance);
277#endif /* VBOX_WITHOUT_RELEASE_STATISTICS */
278}
279
280/**
281 * Marks the link as up, making it possible to establish new connections.
282 */
283void slirp_link_up(PNATState pData)
284{
285 link_up = 1;
286}
287
288/**
289 * Marks the link as down and cleans up the current connections.
290 */
291void slirp_link_down(PNATState pData)
292{
293 struct socket *so;
294
295 while ((so = tcb.so_next) != &tcb)
296 {
297 if (so->so_state & SS_NOFDREF || so->s == -1)
298 sofree(pData, so);
299 else
300 tcp_drop(pData, sototcpcb(so), 0);
301 }
302
303 while ((so = udb.so_next) != &udb)
304 udp_detach(pData, so);
305
306 link_up = 0;
307}
308
309/**
310 * Terminates the slirp component.
311 */
312void slirp_term(PNATState pData)
313{
314 if (pData->pszDomain)
315 RTStrFree((char *)(void *)pData->pszDomain);
316
317#if ARCH_BITS == 64
318 LogRel(("NAT: cpvHashUsed=%RU32 cpvHashCollisions=%RU32 cpvHashInserts=%RU64 cpvHashDone=%RU64\n",
319 pData->cpvHashUsed, pData->cpvHashCollisions, pData->cpvHashInserts, pData->cpvHashDone));
320#endif
321
322 slirp_link_down(pData);
323#ifdef WIN32
324 WSACleanup();
325#endif
326#ifdef LOG_ENABLED
327 Log(("\n"
328 "NAT statistics\n"
329 "--------------\n"
330 "\n"));
331 ipstats(pData);
332 tcpstats(pData);
333 udpstats(pData);
334 icmpstats(pData);
335 mbufstats(pData);
336 sockstats(pData);
337 Log(("\n"
338 "\n"
339 "\n"));
340#endif
341 free(pData);
342}
343
344
345#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
346#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
347#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
348
349/*
350 * curtime kept to an accuracy of 1ms
351 */
352#ifdef _WIN32
353static void updtime(PNATState pData)
354{
355 struct _timeb tb;
356
357 _ftime(&tb);
358 curtime = (u_int)tb.time * (u_int)1000;
359 curtime += (u_int)tb.millitm;
360}
361#else
362static void updtime(PNATState pData)
363{
364 gettimeofday(&tt, 0);
365
366 curtime = (u_int)tt.tv_sec * (u_int)1000;
367 curtime += (u_int)tt.tv_usec / (u_int)1000;
368
369 if ((tt.tv_usec % 1000) >= 500)
370 curtime++;
371}
372#endif
373
374void slirp_select_fill(PNATState pData, int *pnfds,
375 fd_set *readfds, fd_set *writefds, fd_set *xfds)
376{
377 struct socket *so, *so_next;
378 int nfds;
379#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
380 int rc;
381 int error;
382#endif
383#ifdef VBOX_WITH_BSD_REASS
384 int i;
385#endif /* VBOX_WITH_BSD_REASS */
386
387 STAM_REL_PROFILE_START(&pData->StatFill, a);
388
389 nfds = *pnfds;
390 /*
391 * First, TCP sockets
392 */
393 do_slowtimo = 0;
394 if (link_up) {
395 /*
396 * *_slowtimo needs calling if there are IP fragments
397 * in the fragment queue, or there are TCP connections active
398 */
399#ifndef VBOX_WITH_BSD_REASS
400 do_slowtimo = ((tcb.so_next != &tcb) ||
401 ((struct ipasfrag *)&ipq != u32_to_ptr(pData, ipq.next, struct ipasfrag *)));
402#else /* !VBOX_WITH_BSD_REASS */
403 /* XXX: triggering of fragment expiration should be the same but use
404 * new macroses
405 */
406 for (i = 0; i < IPREASS_NHASH; i++) {
407 if (!TAILQ_EMPTY(&ipq[i])) {
408 do_slowtimo = 1;
409 break;
410 }
411 }
412 do_slowtimo |= (tcb.so_next != &tcb);
413#endif /* VBOX_WITH_BSD_REASS */
414
415 STAM_REL_COUNTER_RESET(&pData->StatTCP);
416 STAM_REL_COUNTER_RESET(&pData->StatTCPHot);
417
418 for (so = tcb.so_next; so != &tcb; so = so_next) {
419 so_next = so->so_next;
420
421 STAM_REL_COUNTER_INC(&pData->StatTCP);
422
423 /*
424 * See if we need a tcp_fasttimo
425 */
426 if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
427 time_fasttimo = curtime; /* Flag when we want a fasttimo */
428
429 /*
430 * NOFDREF can include still connecting to local-host,
431 * newly socreated() sockets etc. Don't want to select these.
432 */
433 if (so->so_state & SS_NOFDREF || so->s == -1)
434 continue;
435
436 /*
437 * Set for reading sockets which are accepting
438 */
439 if (so->so_state & SS_FACCEPTCONN) {
440 STAM_REL_COUNTER_INC(&pData->StatTCPHot);
441#if !defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
442 FD_SET(so->s, readfds);
443 UPD_NFDS(so->s);
444#else
445 rc = WSAEventSelect(so->s, VBOX_SOCKET_EVENT, FD_READ|FD_WRITE|FD_ACCEPT|FD_CONNECT|FD_OOB);
446 if (rc == SOCKET_ERROR)
447 {
448socket_error:
449 error = WSAGetLastError();
450 LogRel(("WSAEventSelector error %d (so=%x, socket=%s, event=%x)\n", error, so, so->s, VBOX_SOCKET_EVENT));
451 }
452#endif
453 continue;
454 }
455
456 /*
457 * Set for writing sockets which are connecting
458 */
459 if (so->so_state & SS_ISFCONNECTING) {
460 STAM_REL_COUNTER_INC(&pData->StatTCPHot);
461#if !defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
462 FD_SET(so->s, writefds);
463 UPD_NFDS(so->s);
464#else
465 rc = WSAEventSelect(so->s, VBOX_SOCKET_EVENT, FD_READ|FD_WRITE|FD_ACCEPT|FD_CONNECT|FD_OOB);
466 if (rc == SOCKET_ERROR)
467 goto socket_error;
468#endif
469 continue;
470 }
471
472 /*
473 * Set for writing if we are connected, can send more, and
474 * we have something to send
475 */
476 if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
477 STAM_REL_COUNTER_INC(&pData->StatTCPHot);
478#if !defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
479 FD_SET(so->s, writefds);
480 UPD_NFDS(so->s);
481#else
482 rc = WSAEventSelect(so->s, VBOX_SOCKET_EVENT, FD_READ|FD_WRITE|FD_ACCEPT|FD_CONNECT|FD_OOB);
483 if (rc == SOCKET_ERROR)
484 goto socket_error;
485 continue; /*XXX: we're using the widest mask for event*/
486#endif
487 }
488
489 /*
490 * Set for reading (and urgent data) if we are connected, can
491 * receive more, and we have room for it XXX /2 ?
492 */
493 if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
494 STAM_REL_COUNTER_INC(&pData->StatTCPHot);
495#if !defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
496 FD_SET(so->s, readfds);
497 FD_SET(so->s, xfds);
498 UPD_NFDS(so->s);
499#else
500 rc = WSAEventSelect(so->s, VBOX_SOCKET_EVENT, FD_OOB|FD_READ|FD_WRITE|FD_ACCEPT|FD_CONNECT);
501 if (rc == SOCKET_ERROR)
502 goto socket_error;
503 continue; /*XXX: we're using the widest mask for event*/
504#endif
505 }
506#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
507 rc = WSAEventSelect(so->s, NULL, 0);
508 if (rc == SOCKET_ERROR)
509 goto socket_error;
510#endif
511 }
512
513 /*
514 * UDP sockets
515 */
516 STAM_REL_COUNTER_RESET(&pData->StatUDP);
517 STAM_REL_COUNTER_RESET(&pData->StatUDPHot);
518
519 for (so = udb.so_next; so != &udb; so = so_next) {
520 so_next = so->so_next;
521
522 STAM_REL_COUNTER_INC(&pData->StatUDP);
523
524 /*
525 * See if it's timed out
526 */
527 if (so->so_expire) {
528 if (so->so_expire <= curtime) {
529 udp_detach(pData, so);
530 continue;
531 } else
532 do_slowtimo = 1; /* Let socket expire */
533 }
534
535 /*
536 * When UDP packets are received from over the
537 * link, they're sendto()'d straight away, so
538 * no need for setting for writing
539 * Limit the number of packets queued by this session
540 * to 4. Note that even though we try and limit this
541 * to 4 packets, the session could have more queued
542 * if the packets needed to be fragmented
543 * (XXX <= 4 ?)
544 */
545 if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
546 STAM_REL_COUNTER_INC(&pData->StatUDPHot);
547#if !defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
548 FD_SET(so->s, readfds);
549 UPD_NFDS(so->s);
550#else
551 rc = WSAEventSelect(so->s, VBOX_SOCKET_EVENT, FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT);
552 if (rc == SOCKET_ERROR)
553 goto socket_error;
554 continue;
555#endif
556 }
557#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
558 else
559 {
560 rc = WSAEventSelect(so->s, NULL, 0);
561 if (rc != SOCKET_ERROR)
562 goto socket_error;
563 }
564#endif
565 }
566 }
567
568#if !defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
569 *pnfds = nfds;
570#else
571 *pnfds = VBOX_EVENT_COUNT;
572#endif
573
574 STAM_REL_PROFILE_STOP(&pData->StatFill, a);
575}
576
577void slirp_select_poll(PNATState pData, fd_set *readfds, fd_set *writefds, fd_set *xfds)
578{
579 struct socket *so, *so_next;
580 int ret;
581#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
582 WSANETWORKEVENTS NetworkEvents;
583 int rc;
584 int error;
585 int timer_update = (readfds == NULL && writefds == NULL && xfds == NULL);
586#endif
587 STAM_REL_PROFILE_START(&pData->StatPoll, a);
588
589 /* Update time */
590 updtime(pData);
591
592 /*
593 * See if anything has timed out
594 */
595 if (link_up) {
596 if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
597 STAM_REL_PROFILE_START(&pData->StatFastTimer, a);
598 tcp_fasttimo(pData);
599 time_fasttimo = 0;
600 STAM_REL_PROFILE_STOP(&pData->StatFastTimer, a);
601 }
602 if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
603 STAM_REL_PROFILE_START(&pData->StatSlowTimer, a);
604 ip_slowtimo(pData);
605 tcp_slowtimo(pData);
606 last_slowtimo = curtime;
607 STAM_REL_PROFILE_STOP(&pData->StatSlowTimer, a);
608 }
609 }
610#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
611 if (timer_update) return;
612#endif
613
614 /*
615 * Check sockets
616 */
617 if (link_up) {
618 /*
619 * Check TCP sockets
620 */
621 for (so = tcb.so_next; so != &tcb; so = so_next) {
622 so_next = so->so_next;
623
624 /*
625 * FD_ISSET is meaningless on these sockets
626 * (and they can crash the program)
627 */
628 if (so->so_state & SS_NOFDREF || so->s == -1)
629 continue;
630#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
631 rc = WSAEnumNetworkEvents(so->s, VBOX_SOCKET_EVENT, &NetworkEvents);
632 if (rc == SOCKET_ERROR)
633 {
634 error = WSAGetLastError();
635 LogRel(("WSAEnumNetworkEvents TCP error %d\n", error));
636 continue;
637 }
638#endif
639
640 /*
641 * Check for URG data
642 * This will soread as well, so no need to
643 * test for readfds below if this succeeds
644 */
645#if !defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
646 if (FD_ISSET(so->s, xfds))
647#else
648 /* out-of-band data */
649 if ((NetworkEvents.lNetworkEvents & FD_OOB) && NetworkEvents.iErrorCode[FD_OOB_BIT] == 0)
650#endif
651 sorecvoob(pData, so);
652 /*
653 * Check sockets for reading
654 */
655#if !defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
656 else if (FD_ISSET(so->s, readfds)) {
657#else
658 else if ((NetworkEvents.lNetworkEvents & FD_READ) && (NetworkEvents.iErrorCode[FD_READ_BIT] == 0)) {
659#endif
660 /*
661 * Check for incoming connections
662 */
663 if (so->so_state & SS_FACCEPTCONN) {
664 tcp_connect(pData, so);
665 continue;
666 } /* else */
667 ret = soread(pData, so);
668
669 /* Output it if we read something */
670 if (ret > 0)
671 tcp_output(pData, sototcpcb(so));
672 }
673
674 /*
675 * Check sockets for writing
676 */
677#if !defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
678 if (FD_ISSET(so->s, writefds)) {
679#else
680 if ((NetworkEvents.lNetworkEvents & FD_WRITE) && (NetworkEvents.iErrorCode[FD_WRITE_BIT] == 0)) {
681#endif
682 /*
683 * Check for non-blocking, still-connecting sockets
684 */
685 if (so->so_state & SS_ISFCONNECTING) {
686 /* Connected */
687 so->so_state &= ~SS_ISFCONNECTING;
688
689 /*
690 * This should be probably guarded by PROBE_CONN too. Anyway,
691 * we disable it on OS/2 because the below send call returns
692 * EFAULT which causes the opened TCP socket to close right
693 * after it has been opened and connected.
694 */
695#ifndef RT_OS_OS2
696 ret = send(so->s, (const char *)&ret, 0, 0);
697 if (ret < 0) {
698 /* XXXXX Must fix, zero bytes is a NOP */
699 if (errno == EAGAIN || errno == EWOULDBLOCK ||
700 errno == EINPROGRESS || errno == ENOTCONN) {
701 continue;
702 }
703
704 /* else failed */
705 so->so_state = SS_NOFDREF;
706 }
707 /* else so->so_state &= ~SS_ISFCONNECTING; */
708#endif
709
710 /*
711 * Continue tcp_input
712 */
713 tcp_input(pData, (struct mbuf *)NULL, sizeof(struct ip), so);
714 /* continue; */
715 } else
716 ret = sowrite(pData, so);
717 /*
718 * XXXXX If we wrote something (a lot), there
719 * could be a need for a window update.
720 * In the worst case, the remote will send
721 * a window probe to get things going again
722 */
723 }
724
725 /*
726 * Probe a still-connecting, non-blocking socket
727 * to check if it's still alive
728 */
729#ifdef PROBE_CONN
730 if (so->so_state & SS_ISFCONNECTING) {
731 ret = recv(so->s, (char *)&ret, 0,0);
732
733 if (ret < 0) {
734 /* XXX */
735 if (errno == EAGAIN || errno == EWOULDBLOCK ||
736 errno == EINPROGRESS || errno == ENOTCONN) {
737 continue; /* Still connecting, continue */
738 }
739
740 /* else failed */
741 so->so_state = SS_NOFDREF;
742
743 /* tcp_input will take care of it */
744 } else {
745 ret = send(so->s, &ret, 0,0);
746 if (ret < 0) {
747 /* XXX */
748 if (errno == EAGAIN || errno == EWOULDBLOCK ||
749 errno == EINPROGRESS || errno == ENOTCONN) {
750 continue;
751 }
752 /* else failed */
753 so->so_state = SS_NOFDREF;
754 } else
755 so->so_state &= ~SS_ISFCONNECTING;
756
757 }
758 tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
759 } /* SS_ISFCONNECTING */
760#endif
761 }
762
763 /*
764 * Now UDP sockets.
765 * Incoming packets are sent straight away, they're not buffered.
766 * Incoming UDP data isn't buffered either.
767 */
768 for (so = udb.so_next; so != &udb; so = so_next) {
769 so_next = so->so_next;
770
771#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
772 rc = WSAEnumNetworkEvents(so->s, VBOX_SOCKET_EVENT, &NetworkEvents);
773 if (rc == SOCKET_ERROR)
774 {
775 error = WSAGetLastError();
776 LogRel(("WSAEnumNetworkEvents TCP error %d\n", error));
777 continue;
778 }
779#endif
780#if !defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
781 if (so->s != -1 && FD_ISSET(so->s, readfds)) {
782#else
783 if ((NetworkEvents.lNetworkEvents & FD_READ) && (NetworkEvents.iErrorCode[FD_READ_BIT] == 0)) {
784#endif
785 sorecvfrom(pData, so);
786 }
787 }
788 }
789
790 /*
791 * See if we can start outputting
792 */
793 if (if_queued && link_up)
794 if_start(pData);
795
796 STAM_REL_PROFILE_STOP(&pData->StatPoll, a);
797}
798
799#define ETH_ALEN 6
800#define ETH_HLEN 14
801
802#define ETH_P_IP 0x0800 /* Internet Protocol packet */
803#define ETH_P_ARP 0x0806 /* Address Resolution packet */
804
805#define ARPOP_REQUEST 1 /* ARP request */
806#define ARPOP_REPLY 2 /* ARP reply */
807
808struct ethhdr
809{
810 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
811 unsigned char h_source[ETH_ALEN]; /* source ether addr */
812 unsigned short h_proto; /* packet type ID field */
813};
814
815struct arphdr
816{
817 unsigned short ar_hrd; /* format of hardware address */
818 unsigned short ar_pro; /* format of protocol address */
819 unsigned char ar_hln; /* length of hardware address */
820 unsigned char ar_pln; /* length of protocol address */
821 unsigned short ar_op; /* ARP opcode (command) */
822
823 /*
824 * Ethernet looks like this : This bit is variable sized however...
825 */
826 unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
827 unsigned char ar_sip[4]; /* sender IP address */
828 unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
829 unsigned char ar_tip[4]; /* target IP address */
830};
831
832static
833void arp_input(PNATState pData, const uint8_t *pkt, int pkt_len)
834{
835 struct ethhdr *eh = (struct ethhdr *)pkt;
836 struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
837 uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
838 struct ethhdr *reh = (struct ethhdr *)arp_reply;
839 struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
840 int ar_op;
841 struct ex_list *ex_ptr;
842 uint32_t htip = ntohl(*(uint32_t*)ah->ar_tip);
843
844 ar_op = ntohs(ah->ar_op);
845 switch(ar_op) {
846 case ARPOP_REQUEST:
847 if ((htip & pData->netmask) == ntohl(special_addr.s_addr)) {
848 if ( (htip & ~pData->netmask) == CTL_DNS
849 || (htip & ~pData->netmask) == CTL_ALIAS)
850 goto arp_ok;
851 for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
852 if ((htip & ~pData->netmask) == ex_ptr->ex_addr)
853 goto arp_ok;
854 }
855 return;
856 arp_ok:
857 /* XXX: make an ARP request to have the client address */
858 memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
859
860 /* ARP request for alias/dns mac address */
861 memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
862 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
863 reh->h_source[5] = ah->ar_tip[3];
864 reh->h_proto = htons(ETH_P_ARP);
865
866 rah->ar_hrd = htons(1);
867 rah->ar_pro = htons(ETH_P_IP);
868 rah->ar_hln = ETH_ALEN;
869 rah->ar_pln = 4;
870 rah->ar_op = htons(ARPOP_REPLY);
871 memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
872 memcpy(rah->ar_sip, ah->ar_tip, 4);
873 memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
874 memcpy(rah->ar_tip, ah->ar_sip, 4);
875 slirp_output(pData->pvUser, arp_reply, sizeof(arp_reply));
876 }
877 break;
878 default:
879 break;
880 }
881}
882
883void slirp_input(PNATState pData, const uint8_t *pkt, int pkt_len)
884{
885 struct mbuf *m;
886 int proto;
887
888 if (pkt_len < ETH_HLEN)
889 return;
890
891 proto = ntohs(*(uint16_t *)(pkt + 12));
892 switch(proto) {
893 case ETH_P_ARP:
894 arp_input(pData, pkt, pkt_len);
895 break;
896 case ETH_P_IP:
897 /* Update time. Important if the network is very quiet, as otherwise
898 * the first outgoing connection gets an incorrect timestamp. */
899 updtime(pData);
900
901 m = m_get(pData);
902 if (!m)
903 return;
904 /* Note: we add to align the IP header */
905 if (M_FREEROOM(m) < pkt_len + 2) {
906 m_inc(m, pkt_len + 2);
907 }
908 m->m_len = pkt_len + 2;
909 memcpy(m->m_data + 2, pkt, pkt_len);
910
911 m->m_data += 2 + ETH_HLEN;
912 m->m_len -= 2 + ETH_HLEN;
913
914 ip_input(pData, m);
915 break;
916 default:
917 break;
918 }
919}
920
921/* output the IP packet to the ethernet device */
922void if_encap(PNATState pData, const uint8_t *ip_data, int ip_data_len)
923{
924 uint8_t buf[1600];
925 struct ethhdr *eh = (struct ethhdr *)buf;
926
927 if (ip_data_len + ETH_HLEN > sizeof(buf))
928 return;
929
930 memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
931 memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
932 /* XXX: not correct */
933 eh->h_source[5] = CTL_ALIAS;
934 eh->h_proto = htons(ETH_P_IP);
935 memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
936 slirp_output(pData->pvUser, buf, ip_data_len + ETH_HLEN);
937}
938
939int slirp_redir(PNATState pData, int is_udp, int host_port,
940 struct in_addr guest_addr, int guest_port)
941{
942 if (is_udp) {
943 if (!udp_listen(pData, htons(host_port), guest_addr.s_addr,
944 htons(guest_port), 0))
945 return -1;
946 } else {
947 if (!solisten(pData, htons(host_port), guest_addr.s_addr,
948 htons(guest_port), 0))
949 return -1;
950 }
951 return 0;
952}
953
954int slirp_add_exec(PNATState pData, int do_pty, const char *args, int addr_low_byte,
955 int guest_port)
956{
957 return add_exec(&exec_list, do_pty, (char *)args,
958 addr_low_byte, htons(guest_port));
959}
960
961void slirp_set_ethaddr(PNATState pData, const uint8_t *ethaddr)
962{
963 memcpy(client_ethaddr, ethaddr, ETH_ALEN);
964}
965
966#if defined(VBOX_WITH_SIMPLIFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
967HANDLE *slirp_get_events(PNATState pData)
968{
969 return pData->phEvents;
970}
971void slirp_register_external_event(PNATState pData, HANDLE hEvent, int index)
972{
973 pData->phEvents[index] = hEvent;
974}
975#endif
976
977unsigned int slirp_get_timeout_ms(PNATState pData)
978{
979 if (link_up)
980 {
981 if (time_fasttimo)
982 return 2;
983 if (do_slowtimo)
984 return 500;
985 }
986 return 0;
987}
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