VirtualBox

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

Last change on this file since 1033 was 1033, checked in by vboxsync, 18 years ago

Big change to make slirp fully instantiatable (replace all global
variables with local ones, passing a reference to the state/config
structure to all places which are interested). You can now have as many
cards in the guest configured for NAT networking as you want.

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