VirtualBox

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

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

OS2 -> RT_OS_OS2 (for the sake of completeness).

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