VirtualBox

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

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

registered log formatter prining IPv4 addresses on %R[IP4]

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette