VirtualBox

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

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

Synchronized slirp was inroduced

  • Property svn:eol-style set to native
File size: 26.4 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#ifdef VBOX_WITH_SYNC_SLIRP
206 int rc = 0;
207#endif
208 PNATState pData = malloc(sizeof(NATState));
209 *ppData = pData;
210 if (!pData)
211 return VERR_NO_MEMORY;
212 if (u32Netmask & 0x1f)
213 /* CTL is x.x.x.15, bootp passes up to 16 IPs (15..31) */
214 return VERR_INVALID_PARAMETER;
215 memset(pData, '\0', sizeof(NATState));
216 pData->fPassDomain = fPassDomain;
217 pData->pvUser = pvUser;
218#if ARCH_BITS == 64
219 pData->cpvHashUsed = 1;
220#endif
221 tftp_prefix = pszTFTPPrefix;
222 bootp_filename = pszBootFile;
223 pData->netmask = u32Netmask;
224
225#ifdef _WIN32
226 {
227 WSADATA Data;
228 WSAStartup(MAKEWORD(2,0), &Data);
229 }
230#endif
231
232#ifdef VBOX_WITH_SYNC_SLIRP
233 rc = RTSemMutexCreate(&pData->tcb_mutex);
234 AssertReleaseRC(rc);
235 rc = RTSemMutexCreate(&pData->udb_mutex);
236 AssertReleaseRC(rc);
237 rc = RTSemMutexCreate(&pData->if_queued_mutex);
238 AssertReleaseRC(rc);
239 rc = RTSemMutexCreate(&pData->next_m_mutex);
240 AssertReleaseRC(rc);
241#endif
242
243 Assert(sizeof(struct ip) == 20);
244 link_up = 1;
245
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 * Marks the link as up, making it possible to establish new connections.
267 */
268void slirp_link_up(PNATState pData)
269{
270 link_up = 1;
271}
272
273/**
274 * Marks the link as down and cleans up the current connections.
275 */
276void slirp_link_down(PNATState pData)
277{
278 struct socket *so;
279
280 while ((so = tcb.so_next) != &tcb)
281 {
282 if (so->so_state & SS_NOFDREF || so->s == -1)
283 sofree(pData, so);
284 else
285 tcp_drop(pData, sototcpcb(so), 0);
286 }
287
288 while ((so = udb.so_next) != &udb)
289 udp_detach(pData, so);
290
291 link_up = 0;
292}
293
294/**
295 * Terminates the slirp component.
296 */
297void slirp_term(PNATState pData)
298{
299 if (pData->pszDomain)
300 RTStrFree((char *)(void *)pData->pszDomain);
301
302#if ARCH_BITS == 64
303 LogRel(("NAT: cpvHashUsed=%RU32 cpvHashCollisions=%RU32 cpvHashInserts=%RU64 cpvHashDone=%RU64\n",
304 pData->cpvHashUsed, pData->cpvHashCollisions, pData->cpvHashInserts, pData->cpvHashDone));
305#endif
306
307 slirp_link_down(pData);
308#ifdef WIN32
309 WSACleanup();
310#endif
311#ifdef LOG_ENABLED
312 Log(("\n"
313 "NAT statistics\n"
314 "--------------\n"
315 "\n"));
316 ipstats(pData);
317 tcpstats(pData);
318 udpstats(pData);
319 icmpstats(pData);
320 mbufstats(pData);
321 sockstats(pData);
322 Log(("\n"
323 "\n"
324 "\n"));
325#endif
326 free(pData);
327}
328
329
330#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
331#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
332#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
333
334/*
335 * curtime kept to an accuracy of 1ms
336 */
337#ifdef _WIN32
338static void updtime(PNATState pData)
339{
340 struct _timeb tb;
341
342 _ftime(&tb);
343 curtime = (u_int)tb.time * (u_int)1000;
344 curtime += (u_int)tb.millitm;
345}
346#else
347static void updtime(PNATState pData)
348{
349 gettimeofday(&tt, 0);
350
351 curtime = (u_int)tt.tv_sec * (u_int)1000;
352 curtime += (u_int)tt.tv_usec / (u_int)1000;
353
354 if ((tt.tv_usec % 1000) >= 500)
355 curtime++;
356}
357#endif
358
359void slirp_select_fill(PNATState pData, int *pnfds,
360 fd_set *readfds, fd_set *writefds, fd_set *xfds)
361{
362 struct socket *so, *so_next;
363 struct timeval timeout;
364 int nfds;
365 int tmp_time;
366
367 nfds = *pnfds;
368 /*
369 * First, TCP sockets
370 */
371 do_slowtimo = 0;
372 if (link_up) {
373 /*
374 * *_slowtimo needs calling if there are IP fragments
375 * in the fragment queue, or there are TCP connections active
376 */
377#ifndef VBOX_WITH_SYNC_SLIRP
378 do_slowtimo = ((tcb.so_next != &tcb) ||
379 ((struct ipasfrag *)&ipq != u32_to_ptr(pData, ipq.next, struct ipasfrag *)));
380
381 for (so = tcb.so_next; so != &tcb; so = so_next) {
382 so_next = so->so_next;
383#else
384 RTSemMutexRequest(pData->tcb_mutex, RT_INDEFINITE_WAIT);
385 so = tcb.so_next;
386 do_slowtimo = ((so != &tcb) ||
387 ((struct ipasfrag *)&ipq != u32_to_ptr(pData, ipq.next, struct ipasfrag *)));
388 while (1) {
389 if (so == &tcb) {
390 RTSemMutexRelease(pData->tcb_mutex);
391 break;
392 }
393 so_next = so->so_next;
394 RTSemMutexRequest(so->so_mutex, RT_INDEFINITE_WAIT);
395 RTSemMutexRelease(pData->tcb_mutex);
396#endif
397
398 /*
399 * See if we need a tcp_fasttimo
400 */
401 if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
402 time_fasttimo = curtime; /* Flag when we want a fasttimo */
403
404 /*
405 * NOFDREF can include still connecting to local-host,
406 * newly socreated() sockets etc. Don't want to select these.
407 */
408 if (so->so_state & SS_NOFDREF || so->s == -1)
409#ifndef VBOX_WITH_SYNC_SLIRP
410 continue;
411#else
412 goto before_loop_ends;
413#endif
414
415 /*
416 * Set for reading sockets which are accepting
417 */
418 if (so->so_state & SS_FACCEPTCONN) {
419 FD_SET(so->s, readfds);
420 UPD_NFDS(so->s);
421#ifndef VBOX_WITH_SYNC_SLIRP
422 continue;
423#else
424 goto before_loop_ends;
425#endif
426 }
427
428 /*
429 * Set for writing sockets which are connecting
430 */
431 if (so->so_state & SS_ISFCONNECTING) {
432 FD_SET(so->s, writefds);
433 UPD_NFDS(so->s);
434#ifndef VBOX_WITH_SYNC_SLIRP
435 continue;
436#else
437 goto before_loop_ends;
438#endif
439 }
440
441 /*
442 * Set for writing if we are connected, can send more, and
443 * we have something to send
444 */
445 if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
446 FD_SET(so->s, writefds);
447 UPD_NFDS(so->s);
448 }
449
450 /*
451 * Set for reading (and urgent data) if we are connected, can
452 * receive more, and we have room for it XXX /2 ?
453 */
454 if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
455 FD_SET(so->s, readfds);
456 FD_SET(so->s, xfds);
457 UPD_NFDS(so->s);
458 }
459#ifdef VBOX_WITH_SYNC_SLIRP
460 before_loop_ends:
461 /*Release of global tcb mutex happens in the head of loop*/
462 RTSemMutexRequest(pData->tcb_mutex, RT_INDEFINITE_WAIT);
463 RTSemMutexRelease(so->so_mutex);
464 so = so_next;
465#endif
466 }
467
468 /*
469 * UDP sockets
470 */
471#ifndef VBOX_WITH_SYNC_SLIRP
472 for (so = udb.so_next; so != &udb; so = so_next) {
473 so_next = so->so_next;
474#else
475 RTSemMutexRequest(pData->udb_mutex, RT_INDEFINITE_WAIT);
476 so = udb.so_next;
477 while(1) {
478 if (so == &udb) {
479 RTSemMutexRelease(pData->udb_mutex);
480 break;
481 }
482 so_next = so->so_next;
483 RTSemMutexRequest(so->so_mutex, RT_INDEFINITE_WAIT);
484 RTSemMutexRelease(pData->udb_mutex);
485#endif
486
487 /*
488 * See if it's timed out
489 */
490 if (so->so_expire) {
491 if (so->so_expire <= curtime) {
492 udp_detach(pData, so);
493#ifndef VBOX_WITH_SYNC_SLIRP
494 continue;
495#else
496 goto before_udp_loop_end;
497#endif
498 } else
499 do_slowtimo = 1; /* Let socket expire */
500 }
501
502 /*
503 * When UDP packets are received from over the
504 * link, they're sendto()'d straight away, so
505 * no need for setting for writing
506 * Limit the number of packets queued by this session
507 * to 4. Note that even though we try and limit this
508 * to 4 packets, the session could have more queued
509 * if the packets needed to be fragmented
510 * (XXX <= 4 ?)
511 */
512 if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
513 FD_SET(so->s, readfds);
514 UPD_NFDS(so->s);
515 }
516#ifdef VBOX_WITH_SYNC_SLIRP
517 before_udp_loop_end:
518 RTSemMutexRequest(pData->udb_mutex, RT_INDEFINITE_WAIT);
519 RTSemMutexRelease(so->so_mutex);
520 so = so_next;
521#endif
522 }
523 }
524
525 /*
526 * Setup timeout to use minimum CPU usage, especially when idle
527 */
528
529 /*
530 * First, see the timeout needed by *timo
531 */
532 timeout.tv_sec = 0;
533 timeout.tv_usec = -1;
534 /*
535 * If a slowtimo is needed, set timeout to 500ms from the last
536 * slow timeout. If a fast timeout is needed, set timeout within
537 * 200ms of when it was requested.
538 */
539 if (do_slowtimo) {
540 /* XXX + 10000 because some select()'s aren't that accurate */
541 timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
542 if (timeout.tv_usec < 0)
543 timeout.tv_usec = 0;
544 else if (timeout.tv_usec > 510000)
545 timeout.tv_usec = 510000;
546
547 /* Can only fasttimo if we also slowtimo */
548 if (time_fasttimo) {
549 tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
550 if (tmp_time < 0)
551 tmp_time = 0;
552
553 /* Choose the smallest of the 2 */
554 if (tmp_time < timeout.tv_usec)
555 timeout.tv_usec = (u_int)tmp_time;
556 }
557 }
558 *pnfds = nfds;
559}
560
561void slirp_select_poll(PNATState pData, fd_set *readfds, fd_set *writefds, fd_set *xfds)
562{
563 struct socket *so, *so_next;
564 int ret;
565
566 /* Update time */
567 updtime(pData);
568
569 /*
570 * See if anything has timed out
571 */
572 if (link_up) {
573 if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
574 tcp_fasttimo(pData);
575 time_fasttimo = 0;
576 }
577 if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
578 ip_slowtimo(pData);
579 tcp_slowtimo(pData);
580 last_slowtimo = curtime;
581 }
582 }
583
584 /*
585 * Check sockets
586 */
587 if (link_up) {
588 /*
589 * Check TCP sockets
590 */
591#ifndef VBOX_WITH_SYNC_SLIRP
592 for (so = tcb.so_next; so != &tcb; so = so_next) {
593 so_next = so->so_next;
594#else
595 RTSemMutexRequest(pData->tcb_mutex, RT_INDEFINITE_WAIT);
596 so = tcb.so_next;
597 while (1) {
598 if (so == &tcb) {
599 RTSemMutexRelease(pData->tcb_mutex);
600 break;
601 }
602 so_next = so->so_next;
603 RTSemMutexRequest(so->so_mutex, RT_INDEFINITE_WAIT);
604 RTSemMutexRelease(pData->tcb_mutex);
605#endif
606
607 /*
608 * FD_ISSET is meaningless on these sockets
609 * (and they can crash the program)
610 */
611 if (so->so_state & SS_NOFDREF || so->s == -1)
612#ifndef VBOX_WITH_SYNC_SLIRP
613 continue;
614#else
615 goto before_loop_ends;
616#endif
617
618 /*
619 * Check for URG data
620 * This will soread as well, so no need to
621 * test for readfds below if this succeeds
622 */
623 if (FD_ISSET(so->s, xfds))
624 sorecvoob(pData, so);
625 /*
626 * Check sockets for reading
627 */
628 else if (FD_ISSET(so->s, readfds)) {
629 /*
630 * Check for incoming connections
631 */
632 if (so->so_state & SS_FACCEPTCONN) {
633 tcp_connect(pData, so);
634#ifndef VBOX_WITH_SYNC_SLIRP
635 continue;
636#else
637 goto before_loop_ends;
638#endif
639 } /* else */
640 ret = soread(pData, so);
641
642 /* Output it if we read something */
643 if (ret > 0)
644 tcp_output(pData, sototcpcb(so));
645 }
646
647 /*
648 * Check sockets for writing
649 */
650 if (FD_ISSET(so->s, writefds)) {
651 /*
652 * Check for non-blocking, still-connecting sockets
653 */
654 if (so->so_state & SS_ISFCONNECTING) {
655 /* Connected */
656 so->so_state &= ~SS_ISFCONNECTING;
657
658 /*
659 * This should be probably guarded by PROBE_CONN too. Anyway,
660 * we disable it on OS/2 because the below send call returns
661 * EFAULT which causes the opened TCP socket to close right
662 * after it has been opened and connected.
663 */
664#ifndef RT_OS_OS2
665 ret = send(so->s, (const char *)&ret, 0, 0);
666 if (ret < 0) {
667 /* XXXXX Must fix, zero bytes is a NOP */
668 if (errno == EAGAIN || errno == EWOULDBLOCK ||
669 errno == EINPROGRESS || errno == ENOTCONN)
670#ifndef VBOX_WITH_SYNC_SLIRP
671 continue;
672#else
673 goto before_loop_ends;
674#endif
675
676 /* else failed */
677 so->so_state = SS_NOFDREF;
678 }
679 /* else so->so_state &= ~SS_ISFCONNECTING; */
680#endif
681
682 /*
683 * Continue tcp_input
684 */
685 tcp_input(pData, (struct mbuf *)NULL, sizeof(struct ip), so);
686 /* continue; */
687 } else
688 ret = sowrite(pData, so);
689 /*
690 * XXXXX If we wrote something (a lot), there
691 * could be a need for a window update.
692 * In the worst case, the remote will send
693 * a window probe to get things going again
694 */
695 }
696
697 /*
698 * Probe a still-connecting, non-blocking socket
699 * to check if it's still alive
700 */
701#ifdef PROBE_CONN
702 if (so->so_state & SS_ISFCONNECTING) {
703 ret = recv(so->s, (char *)&ret, 0,0);
704
705 if (ret < 0) {
706 /* XXX */
707 if (errno == EAGAIN || errno == EWOULDBLOCK ||
708 errno == EINPROGRESS || errno == ENOTCONN)
709#ifndef VBOX_WITH_SYNC_SLIRP
710 continue;/* Still connecting, continue */
711#else
712 goto before_loop_ends;
713#endif
714
715 /* else failed */
716 so->so_state = SS_NOFDREF;
717
718 /* tcp_input will take care of it */
719 } else {
720 ret = send(so->s, &ret, 0,0);
721 if (ret < 0) {
722 /* XXX */
723 if (errno == EAGAIN || errno == EWOULDBLOCK ||
724 errno == EINPROGRESS || errno == ENOTCONN)
725#ifndef VBOX_WITH_SYNC_SLIRP
726 continue;
727#else
728 goto before_loop_ends;
729#endif
730 /* else failed */
731 so->so_state = SS_NOFDREF;
732 } else
733 so->so_state &= ~SS_ISFCONNECTING;
734
735 }
736 tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
737 } /* SS_ISFCONNECTING */
738#endif
739#ifdef VBOX_WITH_SYNC_SLIRP
740 before_loop_ends:
741 RTSemMutexRequest(pData->tcb_mutex, RT_INDEFINITE_WAIT);
742 RTSemMutexRelease(so->so_mutex);
743 so = so_next;
744#endif
745 }
746
747 /*
748 * Now UDP sockets.
749 * Incoming packets are sent straight away, they're not buffered.
750 * Incoming UDP data isn't buffered either.
751 */
752#ifndef VBOX_WITH_SYNC_SLIRP
753 for (so = udb.so_next; so != &udb; so = so_next) {
754 so_next = so->so_next;
755#else
756 RTSemMutexRequest(pData->udb_mutex, RT_INDEFINITE_WAIT);
757 so = udb.so_next;
758 while(1) {
759 if (so == &udb) {
760 RTSemMutexRelease(pData->udb_mutex);
761 break;
762 }
763 so_next = so->so_next;
764 RTSemMutexRequest(so->so_mutex, RT_INDEFINITE_WAIT);
765 RTSemMutexRelease(pData->udb_mutex);
766#endif
767
768 if (so->s != -1 && FD_ISSET(so->s, readfds)) {
769 sorecvfrom(pData, so);
770 }
771#ifdef VBOX_WITH_SYNC_SLIRP
772 RTSemMutexRequest(pData->udb_mutex, RT_INDEFINITE_WAIT);
773 RTSemMutexRelease(so->so_mutex);
774 so = so_next;
775#endif
776 }
777 }
778
779 /*
780 * See if we can start outputting
781 */
782#ifndef VBOX_WITH_SYNC_SLIRP
783 if (if_queued && link_up)
784 if_start(pData);
785#else
786#if 0
787 if (link_up) {
788 RTSemMutexRequest(pData->if_queued_mutex, RT_INDEFINITE_WAIT);
789 if (if_queued > 0){
790 RTSemMutexRelease(pData->if_queued_mutex);
791 if_start(pData);
792 }
793 else {
794 RTSemMutexRelease(pData->if_queued_mutex);
795 }
796 }
797#endif
798#endif
799}
800
801#define ETH_ALEN 6
802#define ETH_HLEN 14
803
804#define ETH_P_IP 0x0800 /* Internet Protocol packet */
805#define ETH_P_ARP 0x0806 /* Address Resolution packet */
806
807#define ARPOP_REQUEST 1 /* ARP request */
808#define ARPOP_REPLY 2 /* ARP reply */
809
810struct ethhdr
811{
812 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
813 unsigned char h_source[ETH_ALEN]; /* source ether addr */
814 unsigned short h_proto; /* packet type ID field */
815};
816
817struct arphdr
818{
819 unsigned short ar_hrd; /* format of hardware address */
820 unsigned short ar_pro; /* format of protocol address */
821 unsigned char ar_hln; /* length of hardware address */
822 unsigned char ar_pln; /* length of protocol address */
823 unsigned short ar_op; /* ARP opcode (command) */
824
825 /*
826 * Ethernet looks like this : This bit is variable sized however...
827 */
828 unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
829 unsigned char ar_sip[4]; /* sender IP address */
830 unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
831 unsigned char ar_tip[4]; /* target IP address */
832};
833
834static
835void arp_input(PNATState pData, const uint8_t *pkt, int pkt_len)
836{
837 struct ethhdr *eh = (struct ethhdr *)pkt;
838 struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
839 uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
840 struct ethhdr *reh = (struct ethhdr *)arp_reply;
841 struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
842 int ar_op;
843 struct ex_list *ex_ptr;
844 uint32_t htip = ntohl(*(uint32_t*)ah->ar_tip);
845
846 ar_op = ntohs(ah->ar_op);
847 switch(ar_op) {
848 case ARPOP_REQUEST:
849 if ((htip & pData->netmask) == ntohl(special_addr.s_addr)) {
850 if ( (htip & ~pData->netmask) == CTL_DNS
851 || (htip & ~pData->netmask) == CTL_ALIAS)
852 goto arp_ok;
853 for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
854 if ((htip & ~pData->netmask) == ex_ptr->ex_addr)
855 goto arp_ok;
856 }
857 return;
858 arp_ok:
859 /* XXX: make an ARP request to have the client address */
860 memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
861
862 /* ARP request for alias/dns mac address */
863 memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
864 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1);
865 reh->h_source[5] = ah->ar_tip[3];
866 reh->h_proto = htons(ETH_P_ARP);
867
868 rah->ar_hrd = htons(1);
869 rah->ar_pro = htons(ETH_P_IP);
870 rah->ar_hln = ETH_ALEN;
871 rah->ar_pln = 4;
872 rah->ar_op = htons(ARPOP_REPLY);
873 memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
874 memcpy(rah->ar_sip, ah->ar_tip, 4);
875 memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
876 memcpy(rah->ar_tip, ah->ar_sip, 4);
877 slirp_output(pData->pvUser, arp_reply, sizeof(arp_reply));
878 }
879 break;
880 default:
881 break;
882 }
883}
884
885void slirp_input(PNATState pData, const uint8_t *pkt, int pkt_len)
886{
887 struct mbuf *m;
888 int proto;
889
890 if (pkt_len < ETH_HLEN)
891 return;
892
893 proto = ntohs(*(uint16_t *)(pkt + 12));
894 switch(proto) {
895 case ETH_P_ARP:
896 arp_input(pData, pkt, pkt_len);
897 break;
898 case ETH_P_IP:
899 /* Update time. Important if the network is very quiet, as otherwise
900 * the first outgoing connection gets an incorrect timestamp. */
901 updtime(pData);
902
903 m = m_get(pData);
904 if (!m)
905 return;
906 /* Note: we add to align the IP header */
907 if (M_FREEROOM(m) < pkt_len + 2) {
908 m_inc(m, pkt_len + 2);
909 }
910 m->m_len = pkt_len + 2;
911 memcpy(m->m_data + 2, pkt, pkt_len);
912
913 m->m_data += 2 + ETH_HLEN;
914 m->m_len -= 2 + ETH_HLEN;
915
916 ip_input(pData, m);
917 break;
918 default:
919 break;
920 }
921}
922
923/* output the IP packet to the ethernet device */
924void if_encap(PNATState pData, const uint8_t *ip_data, int ip_data_len)
925{
926 uint8_t buf[1600];
927 struct ethhdr *eh = (struct ethhdr *)buf;
928
929 if (ip_data_len + ETH_HLEN > sizeof(buf))
930 return;
931
932 memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
933 memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1);
934 /* XXX: not correct */
935 eh->h_source[5] = CTL_ALIAS;
936 eh->h_proto = htons(ETH_P_IP);
937 memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
938 slirp_output(pData->pvUser, buf, ip_data_len + ETH_HLEN);
939}
940
941int slirp_redir(PNATState pData, int is_udp, int host_port,
942 struct in_addr guest_addr, int guest_port)
943{
944 if (is_udp) {
945 if (!udp_listen(pData, htons(host_port), guest_addr.s_addr,
946 htons(guest_port), 0))
947 return -1;
948 } else {
949 if (!solisten(pData, htons(host_port), guest_addr.s_addr,
950 htons(guest_port), 0))
951 return -1;
952 }
953 return 0;
954}
955
956int slirp_add_exec(PNATState pData, int do_pty, const char *args, int addr_low_byte,
957 int guest_port)
958{
959 return add_exec(&exec_list, do_pty, (char *)args,
960 addr_low_byte, htons(guest_port));
961}
962
963void slirp_set_ethaddr(PNATState pData, const uint8_t *ethaddr)
964{
965 memcpy(client_ethaddr, ethaddr, ETH_ALEN);
966}
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