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