VirtualBox

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

Last change on this file since 512 was 1, checked in by vboxsync, 55 years ago

import

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