VirtualBox

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

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

fixed win build for 38966

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