VirtualBox

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

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

try to fix the slirp build (PVM define on Mac)

  • Property svn:eol-style set to native
File size: 29.9 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_SIMPLEFIED_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->StatTCPHot, 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#if defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
342 free(pData->phEvents);
343#endif
344 free(pData);
345}
346
347
348#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
349#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
350#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
351
352/*
353 * curtime kept to an accuracy of 1ms
354 */
355#ifdef _WIN32
356static void updtime(PNATState pData)
357{
358 struct _timeb tb;
359
360 _ftime(&tb);
361 curtime = (u_int)tb.time * (u_int)1000;
362 curtime += (u_int)tb.millitm;
363}
364#else
365static void updtime(PNATState pData)
366{
367 gettimeofday(&tt, 0);
368
369 curtime = (u_int)tt.tv_sec * (u_int)1000;
370 curtime += (u_int)tt.tv_usec / (u_int)1000;
371
372 if ((tt.tv_usec % 1000) >= 500)
373 curtime++;
374}
375#endif
376
377void slirp_select_fill(PNATState pData, int *pnfds,
378 fd_set *readfds, fd_set *writefds, fd_set *xfds)
379{
380 struct socket *so, *so_next;
381 struct timeval timeout;
382 int nfds;
383 int tmp_time;
384#if defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
385 int rc;
386 int error;
387#endif
388
389 STAM_REL_PROFILE_START(&pData->StatFill, a);
390
391 nfds = *pnfds;
392 /*
393 * First, TCP sockets
394 */
395 do_slowtimo = 0;
396 if (link_up) {
397 /*
398 * *_slowtimo needs calling if there are IP fragments
399 * in the fragment queue, or there are TCP connections active
400 */
401 do_slowtimo = ((tcb.so_next != &tcb) ||
402 ((struct ipasfrag *)&ipq != u32_to_ptr(pData, ipq.next, struct ipasfrag *)));
403
404 STAM_REL_COUNTER_RESET(&pData->StatTCP);
405 STAM_REL_COUNTER_RESET(&pData->StatTCPHot);
406
407 for (so = tcb.so_next; so != &tcb; so = so_next) {
408 so_next = so->so_next;
409
410 STAM_REL_COUNTER_INC(&pData->StatTCP);
411
412 /*
413 * See if we need a tcp_fasttimo
414 */
415 if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
416 time_fasttimo = curtime; /* Flag when we want a fasttimo */
417
418 /*
419 * NOFDREF can include still connecting to local-host,
420 * newly socreated() sockets etc. Don't want to select these.
421 */
422 if (so->so_state & SS_NOFDREF || so->s == -1)
423 continue;
424
425 /*
426 * Set for reading sockets which are accepting
427 */
428 if (so->so_state & SS_FACCEPTCONN) {
429 STAM_REL_COUNTER_INC(&pData->StatTCPHot);
430#if !defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
431 FD_SET(so->s, readfds);
432 UPD_NFDS(so->s);
433#else
434 rc = WSAEventSelect(so->s, VBOX_SOCKET_EVENT, FD_READ|FD_WRITE|FD_ACCEPT|FD_CONNECT|FD_OOB);
435 if (rc == SOCKET_ERROR)
436 {
437socket_error:
438 error = WSAGetLastError();
439 LogRel(("WSAEventSelector error %d (so=%x, socket=%s, event=%x)\n", error, so, so->s, VBOX_SOCKET_EVENT));
440 }
441#endif
442 continue;
443 }
444
445 /*
446 * Set for writing sockets which are connecting
447 */
448 if (so->so_state & SS_ISFCONNECTING) {
449 STAM_REL_COUNTER_INC(&pData->StatTCPHot);
450#if !defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
451 FD_SET(so->s, writefds);
452 UPD_NFDS(so->s);
453#else
454 rc = WSAEventSelect(so->s, VBOX_SOCKET_EVENT, FD_READ|FD_WRITE|FD_ACCEPT|FD_CONNECT|FD_OOB);
455 if (rc == SOCKET_ERROR)
456 goto socket_error;
457#endif
458 continue;
459 }
460
461 /*
462 * Set for writing if we are connected, can send more, and
463 * we have something to send
464 */
465 if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
466 STAM_REL_COUNTER_INC(&pData->StatTCPHot);
467#if !defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
468 FD_SET(so->s, writefds);
469 UPD_NFDS(so->s);
470#else
471 rc = WSAEventSelect(so->s, VBOX_SOCKET_EVENT, FD_READ|FD_WRITE|FD_ACCEPT|FD_CONNECT|FD_OOB);
472 if (rc == SOCKET_ERROR)
473 goto socket_error;
474 continue; /*XXX: we're using the widest mask for event*/
475#endif
476 }
477
478 /*
479 * Set for reading (and urgent data) if we are connected, can
480 * receive more, and we have room for it XXX /2 ?
481 */
482 if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
483 STAM_REL_COUNTER_INC(&pData->StatTCPHot);
484#if !defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
485 FD_SET(so->s, readfds);
486 FD_SET(so->s, xfds);
487 UPD_NFDS(so->s);
488#else
489 rc = WSAEventSelect(so->s, VBOX_SOCKET_EVENT, FD_OOB|FD_READ|FD_WRITE|FD_ACCEPT|FD_CONNECT);
490 if (rc == SOCKET_ERROR)
491 goto socket_error;
492 continue; /*XXX: we're using the widest mask for event*/
493#endif
494 }
495#if defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
496 rc = WSAEventSelect(so->s, NULL, 0);
497 if (rc == SOCKET_ERROR)
498 goto socket_error;
499#endif
500 }
501
502 /*
503 * UDP sockets
504 */
505 STAM_REL_COUNTER_RESET(&pData->StatUDP);
506 STAM_REL_COUNTER_RESET(&pData->StatUDPHot);
507
508 for (so = udb.so_next; so != &udb; so = so_next) {
509 so_next = so->so_next;
510
511 STAM_REL_COUNTER_INC(&pData->StatUDP);
512
513 /*
514 * See if it's timed out
515 */
516 if (so->so_expire) {
517 if (so->so_expire <= curtime) {
518 udp_detach(pData, so);
519 continue;
520 } else
521 do_slowtimo = 1; /* Let socket expire */
522 }
523
524 /*
525 * When UDP packets are received from over the
526 * link, they're sendto()'d straight away, so
527 * no need for setting for writing
528 * Limit the number of packets queued by this session
529 * to 4. Note that even though we try and limit this
530 * to 4 packets, the session could have more queued
531 * if the packets needed to be fragmented
532 * (XXX <= 4 ?)
533 */
534 if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
535 STAM_REL_COUNTER_INC(&pData->StatUDPHot);
536#if !defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
537 FD_SET(so->s, readfds);
538 UPD_NFDS(so->s);
539#else
540 rc = WSAEventSelect(so->s, VBOX_SOCKET_EVENT, FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT);
541 if (rc == SOCKET_ERROR)
542 goto socket_error;
543 continue;
544#endif
545 STAM_REL_COUNTER_INC(&pData->StatUDPHot);
546 }
547#if defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
548 else
549 {
550 rc = WSAEventSelect(so->s, NULL, 0);
551 if (rc != SOCKET_ERROR)
552 goto socket_error;
553 }
554#endif
555 }
556 }
557
558 /*
559 * Setup timeout to use minimum CPU usage, especially when idle
560 */
561
562 /*
563 * First, see the timeout needed by *timo
564 */
565 timeout.tv_sec = 0;
566 timeout.tv_usec = -1;
567 /*
568 * If a slowtimo is needed, set timeout to 500ms from the last
569 * slow timeout. If a fast timeout is needed, set timeout within
570 * 200ms of when it was requested.
571 */
572 if (do_slowtimo) {
573 /* XXX + 10000 because some select()'s aren't that accurate */
574 timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
575 if (timeout.tv_usec < 0)
576 timeout.tv_usec = 0;
577 else if (timeout.tv_usec > 510000)
578 timeout.tv_usec = 510000;
579
580 /* Can only fasttimo if we also slowtimo */
581 if (time_fasttimo) {
582 tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
583 if (tmp_time < 0)
584 tmp_time = 0;
585
586 /* Choose the smallest of the 2 */
587 if (tmp_time < timeout.tv_usec)
588 timeout.tv_usec = (u_int)tmp_time;
589 }
590 }
591#if !defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
592 *pnfds = nfds;
593#else
594 *pnfds = VBOX_EVENT_COUNT;
595#endif
596
597 STAM_REL_PROFILE_STOP(&pData->StatFill, a);
598}
599
600void slirp_select_poll(PNATState pData, fd_set *readfds, fd_set *writefds, fd_set *xfds)
601{
602 struct socket *so, *so_next;
603 int ret;
604#if defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
605 WSANETWORKEVENTS NetworkEvents;
606 int rc;
607 int error;
608 int timer_update = (readfds == NULL && writefds == NULL && xfds == NULL);
609#endif
610 STAM_REL_PROFILE_START(&pData->StatPoll, a);
611
612 /* Update time */
613 updtime(pData);
614
615 /*
616 * See if anything has timed out
617 */
618 if (link_up) {
619 if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
620 STAM_REL_PROFILE_START(&pData->StatFastTimer, a);
621 tcp_fasttimo(pData);
622 time_fasttimo = 0;
623 STAM_REL_PROFILE_STOP(&pData->StatFastTimer, a);
624 }
625 if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
626 STAM_REL_PROFILE_START(&pData->StatSlowTimer, a);
627 ip_slowtimo(pData);
628 tcp_slowtimo(pData);
629 last_slowtimo = curtime;
630 STAM_REL_PROFILE_STOP(&pData->StatSlowTimer, a);
631 }
632 }
633#if defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
634 if (timer_update) return;
635#endif
636
637 /*
638 * Check sockets
639 */
640 if (link_up) {
641 /*
642 * Check TCP sockets
643 */
644 for (so = tcb.so_next; so != &tcb; so = so_next) {
645 so_next = so->so_next;
646
647 /*
648 * FD_ISSET is meaningless on these sockets
649 * (and they can crash the program)
650 */
651 if (so->so_state & SS_NOFDREF || so->s == -1)
652 continue;
653#if defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
654 rc = WSAEnumNetworkEvents(so->s, VBOX_SOCKET_EVENT, &NetworkEvents);
655 if (rc == SOCKET_ERROR)
656 {
657 error = WSAGetLastError();
658 LogRel(("WSAEnumNetworkEvents TCP error %d\n", error));
659 continue;
660 }
661#endif
662
663 /*
664 * Check for URG data
665 * This will soread as well, so no need to
666 * test for readfds below if this succeeds
667 */
668#if !defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
669 if (FD_ISSET(so->s, xfds))
670#else
671 /* out-of-band data */
672 if ((NetworkEvents.lNetworkEvents & FD_OOB) && NetworkEvents.iErrorCode[FD_OOB_BIT] == 0)
673#endif
674 sorecvoob(pData, so);
675 /*
676 * Check sockets for reading
677 */
678#if !defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
679 else if (FD_ISSET(so->s, readfds)) {
680#else
681 else if ((NetworkEvents.lNetworkEvents & FD_READ) && (NetworkEvents.iErrorCode[FD_READ_BIT] == 0)) {
682#endif
683 /*
684 * Check for incoming connections
685 */
686 if (so->so_state & SS_FACCEPTCONN) {
687 tcp_connect(pData, so);
688 continue;
689 } /* else */
690 ret = soread(pData, so);
691
692 /* Output it if we read something */
693 if (ret > 0)
694 tcp_output(pData, sototcpcb(so));
695 }
696
697 /*
698 * Check sockets for writing
699 */
700#if !defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
701 if (FD_ISSET(so->s, writefds)) {
702#else
703 if ((NetworkEvents.lNetworkEvents & FD_WRITE) && (NetworkEvents.iErrorCode[FD_WRITE_BIT] == 0)) {
704#endif
705 /*
706 * Check for non-blocking, still-connecting sockets
707 */
708 if (so->so_state & SS_ISFCONNECTING) {
709 /* Connected */
710 so->so_state &= ~SS_ISFCONNECTING;
711
712 /*
713 * This should be probably guarded by PROBE_CONN too. Anyway,
714 * we disable it on OS/2 because the below send call returns
715 * EFAULT which causes the opened TCP socket to close right
716 * after it has been opened and connected.
717 */
718#ifndef RT_OS_OS2
719 ret = send(so->s, (const char *)&ret, 0, 0);
720 if (ret < 0) {
721 /* XXXXX Must fix, zero bytes is a NOP */
722 if (errno == EAGAIN || errno == EWOULDBLOCK ||
723 errno == EINPROGRESS || errno == ENOTCONN) {
724 continue;
725 }
726
727 /* else failed */
728 so->so_state = SS_NOFDREF;
729 }
730 /* else so->so_state &= ~SS_ISFCONNECTING; */
731#endif
732
733 /*
734 * Continue tcp_input
735 */
736 tcp_input(pData, (struct mbuf *)NULL, sizeof(struct ip), so);
737 /* continue; */
738 } else
739 ret = sowrite(pData, so);
740 /*
741 * XXXXX If we wrote something (a lot), there
742 * could be a need for a window update.
743 * In the worst case, the remote will send
744 * a window probe to get things going again
745 */
746 }
747
748 /*
749 * Probe a still-connecting, non-blocking socket
750 * to check if it's still alive
751 */
752#ifdef PROBE_CONN
753 if (so->so_state & SS_ISFCONNECTING) {
754 ret = recv(so->s, (char *)&ret, 0,0);
755
756 if (ret < 0) {
757 /* XXX */
758 if (errno == EAGAIN || errno == EWOULDBLOCK ||
759 errno == EINPROGRESS || errno == ENOTCONN) {
760 continue; /* Still connecting, continue */
761 }
762
763 /* else failed */
764 so->so_state = SS_NOFDREF;
765
766 /* tcp_input will take care of it */
767 } else {
768 ret = send(so->s, &ret, 0,0);
769 if (ret < 0) {
770 /* XXX */
771 if (errno == EAGAIN || errno == EWOULDBLOCK ||
772 errno == EINPROGRESS || errno == ENOTCONN) {
773 continue;
774 }
775 /* else failed */
776 so->so_state = SS_NOFDREF;
777 } else
778 so->so_state &= ~SS_ISFCONNECTING;
779
780 }
781 tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
782 } /* SS_ISFCONNECTING */
783#endif
784 }
785
786 /*
787 * Now UDP sockets.
788 * Incoming packets are sent straight away, they're not buffered.
789 * Incoming UDP data isn't buffered either.
790 */
791 for (so = udb.so_next; so != &udb; so = so_next) {
792 so_next = so->so_next;
793
794#if defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
795 rc = WSAEnumNetworkEvents(so->s, VBOX_SOCKET_EVENT, &NetworkEvents);
796 if (rc == SOCKET_ERROR)
797 {
798 error = WSAGetLastError();
799 LogRel(("WSAEnumNetworkEvents TCP error %d\n", error));
800 continue;
801 }
802#endif
803#if !defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) || !defined(RT_OS_WINDOWS)
804 if (so->s != -1 && FD_ISSET(so->s, readfds)) {
805#else
806 if ((NetworkEvents.lNetworkEvents & FD_READ) && (NetworkEvents.iErrorCode[FD_READ_BIT] == 0)) {
807#endif
808 sorecvfrom(pData, so);
809 }
810 }
811 }
812
813 /*
814 * See if we can start outputting
815 */
816 if (if_queued && link_up)
817 if_start(pData);
818
819 STAM_REL_PROFILE_STOP(&pData->StatPoll, a);
820}
821
822#define ETH_ALEN 6
823#define ETH_HLEN 14
824
825#define ETH_P_IP 0x0800 /* Internet Protocol packet */
826#define ETH_P_ARP 0x0806 /* Address Resolution packet */
827
828#define ARPOP_REQUEST 1 /* ARP request */
829#define ARPOP_REPLY 2 /* ARP reply */
830
831struct ethhdr
832{
833 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
834 unsigned char h_source[ETH_ALEN]; /* source ether addr */
835 unsigned short h_proto; /* packet type ID field */
836};
837
838struct arphdr
839{
840 unsigned short ar_hrd; /* format of hardware address */
841 unsigned short ar_pro; /* format of protocol address */
842 unsigned char ar_hln; /* length of hardware address */
843 unsigned char ar_pln; /* length of protocol address */
844 unsigned short ar_op; /* ARP opcode (command) */
845
846 /*
847 * Ethernet looks like this : This bit is variable sized however...
848 */
849 unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
850 unsigned char ar_sip[4]; /* sender IP address */
851 unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
852 unsigned char ar_tip[4]; /* target IP address */
853};
854
855static
856void arp_input(PNATState pData, const uint8_t *pkt, int pkt_len)
857{
858 struct ethhdr *eh = (struct ethhdr *)pkt;
859 struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
860 uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
861 struct ethhdr *reh = (struct ethhdr *)arp_reply;
862 struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
863 int ar_op;
864 struct ex_list *ex_ptr;
865 uint32_t htip = ntohl(*(uint32_t*)ah->ar_tip);
866
867 ar_op = ntohs(ah->ar_op);
868 switch(ar_op) {
869 case ARPOP_REQUEST:
870 if ((htip & pData->netmask) == ntohl(special_addr.s_addr)) {
871 if ( (htip & ~pData->netmask) == CTL_DNS
872 || (htip & ~pData->netmask) == CTL_ALIAS)
873 goto arp_ok;
874 for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
875 if ((htip & ~pData->netmask) == ex_ptr->ex_addr)
876 goto arp_ok;
877 }
878 return;
879 arp_ok:
880 /* XXX: make an ARP request to have the client address */
881 memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
882
883 /* ARP request for alias/dns mac address */
884 memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
885 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
886 reh->h_source[5] = ah->ar_tip[3];
887 reh->h_proto = htons(ETH_P_ARP);
888
889 rah->ar_hrd = htons(1);
890 rah->ar_pro = htons(ETH_P_IP);
891 rah->ar_hln = ETH_ALEN;
892 rah->ar_pln = 4;
893 rah->ar_op = htons(ARPOP_REPLY);
894 memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
895 memcpy(rah->ar_sip, ah->ar_tip, 4);
896 memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
897 memcpy(rah->ar_tip, ah->ar_sip, 4);
898 slirp_output(pData->pvUser, arp_reply, sizeof(arp_reply));
899 }
900 break;
901 default:
902 break;
903 }
904}
905
906void slirp_input(PNATState pData, const uint8_t *pkt, int pkt_len)
907{
908 struct mbuf *m;
909 int proto;
910
911 if (pkt_len < ETH_HLEN)
912 return;
913
914 proto = ntohs(*(uint16_t *)(pkt + 12));
915 switch(proto) {
916 case ETH_P_ARP:
917 arp_input(pData, pkt, pkt_len);
918 break;
919 case ETH_P_IP:
920 /* Update time. Important if the network is very quiet, as otherwise
921 * the first outgoing connection gets an incorrect timestamp. */
922 updtime(pData);
923
924 m = m_get(pData);
925 if (!m)
926 return;
927 /* Note: we add to align the IP header */
928 if (M_FREEROOM(m) < pkt_len + 2) {
929 m_inc(m, pkt_len + 2);
930 }
931 m->m_len = pkt_len + 2;
932 memcpy(m->m_data + 2, pkt, pkt_len);
933
934 m->m_data += 2 + ETH_HLEN;
935 m->m_len -= 2 + ETH_HLEN;
936
937 ip_input(pData, m);
938 break;
939 default:
940 break;
941 }
942}
943
944/* output the IP packet to the ethernet device */
945void if_encap(PNATState pData, const uint8_t *ip_data, int ip_data_len)
946{
947 uint8_t buf[1600];
948 struct ethhdr *eh = (struct ethhdr *)buf;
949
950 if (ip_data_len + ETH_HLEN > sizeof(buf))
951 return;
952
953 memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
954 memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
955 /* XXX: not correct */
956 eh->h_source[5] = CTL_ALIAS;
957 eh->h_proto = htons(ETH_P_IP);
958 memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
959 slirp_output(pData->pvUser, buf, ip_data_len + ETH_HLEN);
960}
961
962int slirp_redir(PNATState pData, int is_udp, int host_port,
963 struct in_addr guest_addr, int guest_port)
964{
965 if (is_udp) {
966 if (!udp_listen(pData, htons(host_port), guest_addr.s_addr,
967 htons(guest_port), 0))
968 return -1;
969 } else {
970 if (!solisten(pData, htons(host_port), guest_addr.s_addr,
971 htons(guest_port), 0))
972 return -1;
973 }
974 return 0;
975}
976
977int slirp_add_exec(PNATState pData, int do_pty, const char *args, int addr_low_byte,
978 int guest_port)
979{
980 return add_exec(&exec_list, do_pty, (char *)args,
981 addr_low_byte, htons(guest_port));
982}
983
984void slirp_set_ethaddr(PNATState pData, const uint8_t *ethaddr)
985{
986 memcpy(client_ethaddr, ethaddr, ETH_ALEN);
987}
988
989#if defined(VBOX_WITH_SIMPLEFIED_SLIRP_SYNC) && defined(RT_OS_WINDOWS)
990HANDLE *slirp_get_events(PNATState pData)
991{
992 return pData->phEvents;
993}
994void slirp_register_external_event(PNATState pData, HANDLE hEvent, int index)
995{
996 pData->phEvents[index] = hEvent;
997}
998#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