VirtualBox

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

最後變更 在這個檔案從1048是 1039,由 vboxsync 提交於 18 年 前

Attempt to fix slirp build for 64 bit (also eliminated global variables)

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

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