]> git.proxmox.com Git - qemu.git/blame - slirp/slirp.c
vhost build fix for i386
[qemu.git] / slirp / slirp.c
CommitLineData
d75a0b97
FB
1/*
2 * libslirp glue
3 *
4 * Copyright (c) 2004-2008 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
e1c5a2b3 24#include "qemu-common.h"
aaf10d9d 25#include "qemu-timer.h"
0580ac91 26#include "qemu-char.h"
f0cbd3ec 27#include "slirp.h"
062e5527 28#include "hw/hw.h"
f0cbd3ec 29
f0cbd3ec
FB
30/* host loopback address */
31struct in_addr loopback_addr;
32
a13a4126 33/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
9634d903 34static const uint8_t special_ethaddr[6] = {
a13a4126 35 0x52, 0x55, 0x00, 0x00, 0x00, 0x00
f0cbd3ec
FB
36};
37
de806f07 38static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
f0cbd3ec 39
f0cbd3ec
FB
40/* XXX: suppress those select globals */
41fd_set *global_readfds, *global_writefds, *global_xfds;
42
f1d99bbd
JK
43u_int curtime;
44static u_int time_fasttimo, last_slowtimo;
45static int do_slowtimo;
46
72cf2d4f
BS
47static QTAILQ_HEAD(slirp_instances, Slirp) slirp_instances =
48 QTAILQ_HEAD_INITIALIZER(slirp_instances);
115defd1 49
9e3a95ef
SW
50static struct in_addr dns_addr;
51static u_int dns_addr_time;
df7a86ed 52
f0cbd3ec
FB
53#ifdef _WIN32
54
df7a86ed 55int get_dns_addr(struct in_addr *pdns_addr)
f0cbd3ec 56{
379ff53d
FB
57 FIXED_INFO *FixedInfo=NULL;
58 ULONG BufLen;
59 DWORD ret;
60 IP_ADDR_STRING *pIPAddr;
61 struct in_addr tmp_addr;
3b46e624 62
df7a86ed
ES
63 if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < 1000) {
64 *pdns_addr = dns_addr;
65 return 0;
66 }
67
379ff53d
FB
68 FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
69 BufLen = sizeof(FIXED_INFO);
3b46e624 70
379ff53d
FB
71 if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
72 if (FixedInfo) {
73 GlobalFree(FixedInfo);
74 FixedInfo = NULL;
75 }
76 FixedInfo = GlobalAlloc(GPTR, BufLen);
77 }
5fafdf24 78
379ff53d
FB
79 if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
80 printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
81 if (FixedInfo) {
82 GlobalFree(FixedInfo);
83 FixedInfo = NULL;
84 }
85 return -1;
86 }
3b46e624 87
379ff53d
FB
88 pIPAddr = &(FixedInfo->DnsServerList);
89 inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
90 *pdns_addr = tmp_addr;
df7a86ed
ES
91 dns_addr = tmp_addr;
92 dns_addr_time = curtime;
379ff53d
FB
93 if (FixedInfo) {
94 GlobalFree(FixedInfo);
95 FixedInfo = NULL;
96 }
97 return 0;
f0cbd3ec
FB
98}
99
df461894
JK
100static void winsock_cleanup(void)
101{
102 WSACleanup();
103}
104
f0cbd3ec
FB
105#else
106
1e6eec8b 107static struct stat dns_addr_stat;
df7a86ed
ES
108
109int get_dns_addr(struct in_addr *pdns_addr)
f0cbd3ec
FB
110{
111 char buff[512];
363a37d5 112 char buff2[257];
f0cbd3ec
FB
113 FILE *f;
114 int found = 0;
115 struct in_addr tmp_addr;
3b46e624 116
df7a86ed
ES
117 if (dns_addr.s_addr != 0) {
118 struct stat old_stat;
119 if ((curtime - dns_addr_time) < 1000) {
120 *pdns_addr = dns_addr;
121 return 0;
122 }
123 old_stat = dns_addr_stat;
124 if (stat("/etc/resolv.conf", &dns_addr_stat) != 0)
125 return -1;
126 if ((dns_addr_stat.st_dev == old_stat.st_dev)
127 && (dns_addr_stat.st_ino == old_stat.st_ino)
128 && (dns_addr_stat.st_size == old_stat.st_size)
129 && (dns_addr_stat.st_mtime == old_stat.st_mtime)) {
130 *pdns_addr = dns_addr;
131 return 0;
132 }
133 }
134
f0cbd3ec
FB
135 f = fopen("/etc/resolv.conf", "r");
136 if (!f)
137 return -1;
138
31a60e22 139#ifdef DEBUG
f0cbd3ec 140 lprint("IP address of your DNS(s): ");
31a60e22 141#endif
f0cbd3ec
FB
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;
f0cbd3ec 146 /* If it's the first one, set it to dns_addr */
df7a86ed 147 if (!found) {
f0cbd3ec 148 *pdns_addr = tmp_addr;
df7a86ed
ES
149 dns_addr = tmp_addr;
150 dns_addr_time = curtime;
151 }
31a60e22 152#ifdef DEBUG
f0cbd3ec
FB
153 else
154 lprint(", ");
31a60e22 155#endif
f0cbd3ec 156 if (++found > 3) {
31a60e22 157#ifdef DEBUG
f0cbd3ec 158 lprint("(more)");
31a60e22 159#endif
f0cbd3ec 160 break;
31a60e22
BS
161 }
162#ifdef DEBUG
163 else
f0cbd3ec 164 lprint("%s", inet_ntoa(tmp_addr));
31a60e22 165#endif
f0cbd3ec
FB
166 }
167 }
1d43a717 168 fclose(f);
f0cbd3ec
FB
169 if (!found)
170 return -1;
171 return 0;
172}
173
174#endif
175
df461894 176static void slirp_init_once(void)
379ff53d 177{
df461894 178 static int initialized;
df461894
JK
179#ifdef _WIN32
180 WSADATA Data;
379ff53d
FB
181#endif
182
df461894
JK
183 if (initialized) {
184 return;
185 }
186 initialized = 1;
187
188#ifdef _WIN32
189 WSAStartup(MAKEWORD(2,0), &Data);
190 atexit(winsock_cleanup);
191#endif
192
193 loopback_addr.s_addr = htonl(INADDR_LOOPBACK);
df461894
JK
194}
195
062e5527
AL
196static void slirp_state_save(QEMUFile *f, void *opaque);
197static int slirp_state_load(QEMUFile *f, void *opaque, int version_id);
198
9f8bd042
JK
199Slirp *slirp_init(int restricted, struct in_addr vnetwork,
200 struct in_addr vnetmask, struct in_addr vhost,
201 const char *vhostname, const char *tftp_path,
202 const char *bootfile, struct in_addr vdhcp_start,
203 struct in_addr vnameserver, void *opaque)
f0cbd3ec 204{
ad0d8c4c 205 Slirp *slirp = qemu_mallocz(sizeof(Slirp));
460fec67 206
df461894 207 slirp_init_once();
379ff53d 208
460fec67 209 slirp->restricted = restricted;
f0cbd3ec 210
460fec67
JK
211 if_init(slirp);
212 ip_init(slirp);
f0cbd3ec
FB
213
214 /* Initialise mbufs *after* setting the MTU */
460fec67 215 m_init(slirp);
f0cbd3ec 216
460fec67
JK
217 slirp->vnetwork_addr = vnetwork;
218 slirp->vnetwork_mask = vnetmask;
219 slirp->vhost_addr = vhost;
c92ef6a2 220 if (vhostname) {
460fec67
JK
221 pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
222 vhostname);
a13a4126 223 }
ad196a9d 224 if (tftp_path) {
460fec67 225 slirp->tftp_prefix = qemu_strdup(tftp_path);
ad196a9d 226 }
ad196a9d 227 if (bootfile) {
460fec67 228 slirp->bootp_filename = qemu_strdup(bootfile);
ad196a9d 229 }
460fec67
JK
230 slirp->vdhcp_startaddr = vdhcp_start;
231 slirp->vnameserver_addr = vnameserver;
ad196a9d 232
9f8bd042
JK
233 slirp->opaque = opaque;
234
0be71e32
AW
235 register_savevm(NULL, "slirp", 0, 3,
236 slirp_state_save, slirp_state_load, slirp);
9f8bd042 237
72cf2d4f 238 QTAILQ_INSERT_TAIL(&slirp_instances, slirp, entry);
ad0d8c4c 239
9f8bd042 240 return slirp;
f0cbd3ec
FB
241}
242
ad0d8c4c
JK
243void slirp_cleanup(Slirp *slirp)
244{
72cf2d4f 245 QTAILQ_REMOVE(&slirp_instances, slirp, entry);
b1c99fcd 246
0be71e32 247 unregister_savevm(NULL, "slirp", slirp);
ad0d8c4c
JK
248
249 qemu_free(slirp->tftp_prefix);
250 qemu_free(slirp->bootp_filename);
251 qemu_free(slirp);
ad0d8c4c
JK
252}
253
f0cbd3ec
FB
254#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
255#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
256#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
257
5fafdf24 258void slirp_select_fill(int *pnfds,
f0cbd3ec
FB
259 fd_set *readfds, fd_set *writefds, fd_set *xfds)
260{
b1c99fcd 261 Slirp *slirp;
f0cbd3ec 262 struct socket *so, *so_next;
f0cbd3ec 263 int nfds;
f0cbd3ec 264
72cf2d4f 265 if (QTAILQ_EMPTY(&slirp_instances)) {
d918f23e
JK
266 return;
267 }
268
f0cbd3ec
FB
269 /* fail safe */
270 global_readfds = NULL;
271 global_writefds = NULL;
272 global_xfds = NULL;
3b46e624 273
f0cbd3ec
FB
274 nfds = *pnfds;
275 /*
276 * First, TCP sockets
277 */
278 do_slowtimo = 0;
d918f23e 279
72cf2d4f 280 QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
5fafdf24 281 /*
f0cbd3ec
FB
282 * *_slowtimo needs calling if there are IP fragments
283 * in the fragment queue, or there are TCP connections active
284 */
b1c99fcd 285 do_slowtimo |= ((slirp->tcb.so_next != &slirp->tcb) ||
460fec67 286 (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
3b46e624 287
460fec67
JK
288 for (so = slirp->tcb.so_next; so != &slirp->tcb;
289 so = so_next) {
f0cbd3ec 290 so_next = so->so_next;
3b46e624 291
f0cbd3ec
FB
292 /*
293 * See if we need a tcp_fasttimo
294 */
295 if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
296 time_fasttimo = curtime; /* Flag when we want a fasttimo */
3b46e624 297
f0cbd3ec
FB
298 /*
299 * NOFDREF can include still connecting to local-host,
300 * newly socreated() sockets etc. Don't want to select these.
301 */
302 if (so->so_state & SS_NOFDREF || so->s == -1)
303 continue;
3b46e624 304
f0cbd3ec
FB
305 /*
306 * Set for reading sockets which are accepting
307 */
308 if (so->so_state & SS_FACCEPTCONN) {
309 FD_SET(so->s, readfds);
310 UPD_NFDS(so->s);
311 continue;
312 }
3b46e624 313
f0cbd3ec
FB
314 /*
315 * Set for writing sockets which are connecting
316 */
317 if (so->so_state & SS_ISFCONNECTING) {
318 FD_SET(so->s, writefds);
319 UPD_NFDS(so->s);
320 continue;
321 }
3b46e624 322
f0cbd3ec
FB
323 /*
324 * Set for writing if we are connected, can send more, and
325 * we have something to send
326 */
327 if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
328 FD_SET(so->s, writefds);
329 UPD_NFDS(so->s);
330 }
3b46e624 331
f0cbd3ec
FB
332 /*
333 * Set for reading (and urgent data) if we are connected, can
334 * receive more, and we have room for it XXX /2 ?
335 */
336 if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
337 FD_SET(so->s, readfds);
338 FD_SET(so->s, xfds);
339 UPD_NFDS(so->s);
340 }
341 }
3b46e624 342
f0cbd3ec
FB
343 /*
344 * UDP sockets
345 */
460fec67
JK
346 for (so = slirp->udb.so_next; so != &slirp->udb;
347 so = so_next) {
f0cbd3ec 348 so_next = so->so_next;
3b46e624 349
f0cbd3ec
FB
350 /*
351 * See if it's timed out
352 */
353 if (so->so_expire) {
354 if (so->so_expire <= curtime) {
355 udp_detach(so);
356 continue;
357 } else
358 do_slowtimo = 1; /* Let socket expire */
359 }
3b46e624 360
f0cbd3ec
FB
361 /*
362 * When UDP packets are received from over the
363 * link, they're sendto()'d straight away, so
364 * no need for setting for writing
365 * Limit the number of packets queued by this session
366 * to 4. Note that even though we try and limit this
367 * to 4 packets, the session could have more queued
368 * if the packets needed to be fragmented
369 * (XXX <= 4 ?)
370 */
371 if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
372 FD_SET(so->s, readfds);
373 UPD_NFDS(so->s);
374 }
375 }
e6d43cfb
JK
376
377 /*
378 * ICMP sockets
379 */
380 for (so = slirp->icmp.so_next; so != &slirp->icmp;
381 so = so_next) {
382 so_next = so->so_next;
383
384 /*
385 * See if it's timed out
386 */
387 if (so->so_expire) {
388 if (so->so_expire <= curtime) {
389 icmp_detach(so);
390 continue;
391 } else {
392 do_slowtimo = 1; /* Let socket expire */
393 }
394 }
395
396 if (so->so_state & SS_ISFCONNECTED) {
397 FD_SET(so->s, readfds);
398 UPD_NFDS(so->s);
399 }
400 }
b1c99fcd 401 }
5fafdf24 402
f0cbd3ec 403 *pnfds = nfds;
5fafdf24 404}
f0cbd3ec 405
d918f23e
JK
406void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
407 int select_error)
f0cbd3ec 408{
b1c99fcd 409 Slirp *slirp;
f0cbd3ec
FB
410 struct socket *so, *so_next;
411 int ret;
412
72cf2d4f 413 if (QTAILQ_EMPTY(&slirp_instances)) {
d918f23e
JK
414 return;
415 }
416
f0cbd3ec
FB
417 global_readfds = readfds;
418 global_writefds = writefds;
419 global_xfds = xfds;
420
7bd427d8 421 curtime = qemu_get_clock_ms(rt_clock);
5fafdf24 422
72cf2d4f 423 QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
f0cbd3ec 424 /*
5fafdf24 425 * See if anything has timed out
f0cbd3ec 426 */
df5f8956 427 if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
460fec67 428 tcp_fasttimo(slirp);
f0cbd3ec
FB
429 time_fasttimo = 0;
430 }
431 if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
460fec67
JK
432 ip_slowtimo(slirp);
433 tcp_slowtimo(slirp);
f0cbd3ec
FB
434 last_slowtimo = curtime;
435 }
5fafdf24 436
f0cbd3ec
FB
437 /*
438 * Check sockets
439 */
d918f23e 440 if (!select_error) {
f0cbd3ec
FB
441 /*
442 * Check TCP sockets
443 */
460fec67
JK
444 for (so = slirp->tcb.so_next; so != &slirp->tcb;
445 so = so_next) {
f0cbd3ec 446 so_next = so->so_next;
3b46e624 447
f0cbd3ec
FB
448 /*
449 * FD_ISSET is meaningless on these sockets
450 * (and they can crash the program)
451 */
452 if (so->so_state & SS_NOFDREF || so->s == -1)
453 continue;
3b46e624 454
f0cbd3ec
FB
455 /*
456 * Check for URG data
457 * This will soread as well, so no need to
458 * test for readfds below if this succeeds
459 */
460 if (FD_ISSET(so->s, xfds))
461 sorecvoob(so);
462 /*
463 * Check sockets for reading
464 */
465 else if (FD_ISSET(so->s, readfds)) {
466 /*
467 * Check for incoming connections
468 */
469 if (so->so_state & SS_FACCEPTCONN) {
470 tcp_connect(so);
471 continue;
472 } /* else */
473 ret = soread(so);
3b46e624 474
f0cbd3ec
FB
475 /* Output it if we read something */
476 if (ret > 0)
477 tcp_output(sototcpcb(so));
478 }
3b46e624 479
f0cbd3ec
FB
480 /*
481 * Check sockets for writing
482 */
483 if (FD_ISSET(so->s, writefds)) {
484 /*
485 * Check for non-blocking, still-connecting sockets
486 */
487 if (so->so_state & SS_ISFCONNECTING) {
488 /* Connected */
489 so->so_state &= ~SS_ISFCONNECTING;
3b46e624 490
0a656f5f 491 ret = send(so->s, (const void *) &ret, 0, 0);
f0cbd3ec
FB
492 if (ret < 0) {
493 /* XXXXX Must fix, zero bytes is a NOP */
494 if (errno == EAGAIN || errno == EWOULDBLOCK ||
495 errno == EINPROGRESS || errno == ENOTCONN)
496 continue;
3b46e624 497
f0cbd3ec 498 /* else failed */
f932b6ce
JK
499 so->so_state &= SS_PERSISTENT_MASK;
500 so->so_state |= SS_NOFDREF;
f0cbd3ec
FB
501 }
502 /* else so->so_state &= ~SS_ISFCONNECTING; */
3b46e624 503
f0cbd3ec
FB
504 /*
505 * Continue tcp_input
506 */
507 tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
508 /* continue; */
509 } else
510 ret = sowrite(so);
511 /*
5fafdf24 512 * XXXXX If we wrote something (a lot), there
f0cbd3ec
FB
513 * could be a need for a window update.
514 * In the worst case, the remote will send
515 * a window probe to get things going again
516 */
517 }
3b46e624 518
f0cbd3ec
FB
519 /*
520 * Probe a still-connecting, non-blocking socket
521 * to check if it's still alive
522 */
523#ifdef PROBE_CONN
524 if (so->so_state & SS_ISFCONNECTING) {
00aa0040 525 ret = qemu_recv(so->s, &ret, 0,0);
3b46e624 526
f0cbd3ec
FB
527 if (ret < 0) {
528 /* XXX */
529 if (errno == EAGAIN || errno == EWOULDBLOCK ||
530 errno == EINPROGRESS || errno == ENOTCONN)
531 continue; /* Still connecting, continue */
3b46e624 532
f0cbd3ec 533 /* else failed */
f932b6ce
JK
534 so->so_state &= SS_PERSISTENT_MASK;
535 so->so_state |= SS_NOFDREF;
3b46e624 536
f0cbd3ec
FB
537 /* tcp_input will take care of it */
538 } else {
02d2c54c 539 ret = send(so->s, &ret, 0,0);
f0cbd3ec
FB
540 if (ret < 0) {
541 /* XXX */
542 if (errno == EAGAIN || errno == EWOULDBLOCK ||
543 errno == EINPROGRESS || errno == ENOTCONN)
544 continue;
545 /* else failed */
f932b6ce
JK
546 so->so_state &= SS_PERSISTENT_MASK;
547 so->so_state |= SS_NOFDREF;
f0cbd3ec
FB
548 } else
549 so->so_state &= ~SS_ISFCONNECTING;
3b46e624 550
f0cbd3ec
FB
551 }
552 tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
553 } /* SS_ISFCONNECTING */
554#endif
555 }
3b46e624 556
f0cbd3ec
FB
557 /*
558 * Now UDP sockets.
559 * Incoming packets are sent straight away, they're not buffered.
560 * Incoming UDP data isn't buffered either.
561 */
460fec67
JK
562 for (so = slirp->udb.so_next; so != &slirp->udb;
563 so = so_next) {
f0cbd3ec 564 so_next = so->so_next;
3b46e624 565
f0cbd3ec
FB
566 if (so->s != -1 && FD_ISSET(so->s, readfds)) {
567 sorecvfrom(so);
568 }
569 }
e6d43cfb
JK
570
571 /*
572 * Check incoming ICMP relies.
573 */
574 for (so = slirp->icmp.so_next; so != &slirp->icmp;
575 so = so_next) {
576 so_next = so->so_next;
577
578 if (so->s != -1 && FD_ISSET(so->s, readfds)) {
579 icmp_receive(so);
580 }
581 }
f0cbd3ec 582 }
5fafdf24 583
f0cbd3ec
FB
584 /*
585 * See if we can start outputting
586 */
460fec67
JK
587 if (slirp->if_queued) {
588 if_start(slirp);
589 }
b1c99fcd 590 }
02d2c54c
FB
591
592 /* clear global file descriptor sets.
593 * these reside on the stack in vl.c
594 * so they're unusable if we're not in
595 * slirp_select_fill or slirp_select_poll.
596 */
597 global_readfds = NULL;
598 global_writefds = NULL;
599 global_xfds = NULL;
f0cbd3ec
FB
600}
601
602#define ETH_ALEN 6
603#define ETH_HLEN 14
604
605#define ETH_P_IP 0x0800 /* Internet Protocol packet */
606#define ETH_P_ARP 0x0806 /* Address Resolution packet */
607
608#define ARPOP_REQUEST 1 /* ARP request */
609#define ARPOP_REPLY 2 /* ARP reply */
610
5fafdf24 611struct ethhdr
f0cbd3ec
FB
612{
613 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
614 unsigned char h_source[ETH_ALEN]; /* source ether addr */
615 unsigned short h_proto; /* packet type ID field */
616};
617
618struct arphdr
619{
620 unsigned short ar_hrd; /* format of hardware address */
621 unsigned short ar_pro; /* format of protocol address */
622 unsigned char ar_hln; /* length of hardware address */
623 unsigned char ar_pln; /* length of protocol address */
624 unsigned short ar_op; /* ARP opcode (command) */
625
626 /*
627 * Ethernet looks like this : This bit is variable sized however...
628 */
629 unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
a13a4126 630 uint32_t ar_sip; /* sender IP address */
f0cbd3ec 631 unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
a13a4126
JK
632 uint32_t ar_tip ; /* target IP address */
633} __attribute__((packed));
f0cbd3ec 634
460fec67 635static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
f0cbd3ec
FB
636{
637 struct ethhdr *eh = (struct ethhdr *)pkt;
638 struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
dbf3c4b4 639 uint8_t arp_reply[max(ETH_HLEN + sizeof(struct arphdr), 64)];
f0cbd3ec
FB
640 struct ethhdr *reh = (struct ethhdr *)arp_reply;
641 struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
642 int ar_op;
a3d4af03 643 struct ex_list *ex_ptr;
f0cbd3ec
FB
644
645 ar_op = ntohs(ah->ar_op);
646 switch(ar_op) {
647 case ARPOP_REQUEST:
460fec67
JK
648 if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) ==
649 slirp->vnetwork_addr.s_addr) {
650 if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
651 ah->ar_tip == slirp->vhost_addr.s_addr)
a3d4af03 652 goto arp_ok;
460fec67 653 for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
a13a4126 654 if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
a3d4af03
FB
655 goto arp_ok;
656 }
657 return;
658 arp_ok:
dbf3c4b4 659 memset(arp_reply, 0, sizeof(arp_reply));
f0cbd3ec 660 /* XXX: make an ARP request to have the client address */
460fec67 661 memcpy(slirp->client_ethaddr, eh->h_source, ETH_ALEN);
f0cbd3ec
FB
662
663 /* ARP request for alias/dns mac address */
664 memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
a13a4126
JK
665 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
666 memcpy(&reh->h_source[2], &ah->ar_tip, 4);
f0cbd3ec
FB
667 reh->h_proto = htons(ETH_P_ARP);
668
669 rah->ar_hrd = htons(1);
670 rah->ar_pro = htons(ETH_P_IP);
671 rah->ar_hln = ETH_ALEN;
672 rah->ar_pln = 4;
673 rah->ar_op = htons(ARPOP_REPLY);
674 memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
a13a4126 675 rah->ar_sip = ah->ar_tip;
f0cbd3ec 676 memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
a13a4126 677 rah->ar_tip = ah->ar_sip;
9f8bd042 678 slirp_output(slirp->opaque, arp_reply, sizeof(arp_reply));
f0cbd3ec
FB
679 }
680 break;
de806f07
FB
681 case ARPOP_REPLY:
682 /* reply to request of client mac address ? */
460fec67
JK
683 if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN) &&
684 ah->ar_sip == slirp->client_ipaddr.s_addr) {
685 memcpy(slirp->client_ethaddr, ah->ar_sha, ETH_ALEN);
de806f07
FB
686 }
687 break;
f0cbd3ec
FB
688 default:
689 break;
690 }
691}
692
9f8bd042 693void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
f0cbd3ec
FB
694{
695 struct mbuf *m;
696 int proto;
697
698 if (pkt_len < ETH_HLEN)
699 return;
3b46e624 700
f0cbd3ec
FB
701 proto = ntohs(*(uint16_t *)(pkt + 12));
702 switch(proto) {
703 case ETH_P_ARP:
460fec67 704 arp_input(slirp, pkt, pkt_len);
f0cbd3ec
FB
705 break;
706 case ETH_P_IP:
460fec67 707 m = m_get(slirp);
f0cbd3ec
FB
708 if (!m)
709 return;
38f3e7c2 710 /* Note: we add to align the IP header */
e8e880a7
AJ
711 if (M_FREEROOM(m) < pkt_len + 2) {
712 m_inc(m, pkt_len + 2);
713 }
38f3e7c2
FB
714 m->m_len = pkt_len + 2;
715 memcpy(m->m_data + 2, pkt, pkt_len);
f0cbd3ec 716
38f3e7c2
FB
717 m->m_data += 2 + ETH_HLEN;
718 m->m_len -= 2 + ETH_HLEN;
f0cbd3ec
FB
719
720 ip_input(m);
721 break;
722 default:
723 break;
724 }
725}
726
727/* output the IP packet to the ethernet device */
460fec67 728void if_encap(Slirp *slirp, const uint8_t *ip_data, int ip_data_len)
f0cbd3ec
FB
729{
730 uint8_t buf[1600];
731 struct ethhdr *eh = (struct ethhdr *)buf;
732
733 if (ip_data_len + ETH_HLEN > sizeof(buf))
734 return;
de806f07 735
460fec67 736 if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN)) {
de806f07
FB
737 uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
738 struct ethhdr *reh = (struct ethhdr *)arp_req;
739 struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
740 const struct ip *iph = (const struct ip *)ip_data;
741
742 /* If the client addr is not known, there is no point in
743 sending the packet to it. Normally the sender should have
744 done an ARP request to get its MAC address. Here we do it
745 in place of sending the packet and we hope that the sender
746 will retry sending its packet. */
747 memset(reh->h_dest, 0xff, ETH_ALEN);
a13a4126 748 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
460fec67 749 memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
de806f07
FB
750 reh->h_proto = htons(ETH_P_ARP);
751 rah->ar_hrd = htons(1);
752 rah->ar_pro = htons(ETH_P_IP);
753 rah->ar_hln = ETH_ALEN;
754 rah->ar_pln = 4;
755 rah->ar_op = htons(ARPOP_REQUEST);
756 /* source hw addr */
a13a4126 757 memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
460fec67 758 memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
de806f07 759 /* source IP */
460fec67 760 rah->ar_sip = slirp->vhost_addr.s_addr;
de806f07
FB
761 /* target hw addr (none) */
762 memset(rah->ar_tha, 0, ETH_ALEN);
763 /* target IP */
a13a4126 764 rah->ar_tip = iph->ip_dst.s_addr;
460fec67 765 slirp->client_ipaddr = iph->ip_dst;
9f8bd042 766 slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
de806f07 767 } else {
460fec67 768 memcpy(eh->h_dest, slirp->client_ethaddr, ETH_ALEN);
a13a4126 769 memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
de806f07 770 /* XXX: not correct */
460fec67 771 memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
de806f07
FB
772 eh->h_proto = htons(ETH_P_IP);
773 memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
9f8bd042 774 slirp_output(slirp->opaque, buf, ip_data_len + ETH_HLEN);
de806f07 775 }
f0cbd3ec 776}
9bf05444 777
9c12a6f2 778/* Drop host forwarding rule, return 0 if found. */
9f8bd042
JK
779int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
780 int host_port)
c1261d8d
AG
781{
782 struct socket *so;
460fec67 783 struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb);
2ad82cf9
JK
784 struct sockaddr_in addr;
785 int port = htons(host_port);
786 socklen_t addr_len;
c1261d8d 787
c1261d8d 788 for (so = head->so_next; so != head; so = so->so_next) {
2ad82cf9 789 addr_len = sizeof(addr);
9c12a6f2
JK
790 if ((so->so_state & SS_HOSTFWD) &&
791 getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
3c6a0580 792 addr.sin_addr.s_addr == host_addr.s_addr &&
2ad82cf9 793 addr.sin_port == port) {
c1261d8d
AG
794 close(so->s);
795 sofree(so);
9c12a6f2 796 return 0;
c1261d8d
AG
797 }
798 }
799
9c12a6f2 800 return -1;
c1261d8d
AG
801}
802
9f8bd042
JK
803int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
804 int host_port, struct in_addr guest_addr, int guest_port)
9bf05444 805{
a13a4126 806 if (!guest_addr.s_addr) {
460fec67 807 guest_addr = slirp->vdhcp_startaddr;
a13a4126 808 }
9bf05444 809 if (is_udp) {
460fec67
JK
810 if (!udp_listen(slirp, host_addr.s_addr, htons(host_port),
811 guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
9bf05444
FB
812 return -1;
813 } else {
460fec67
JK
814 if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port),
815 guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
9bf05444
FB
816 return -1;
817 }
818 return 0;
819}
a3d4af03 820
9f8bd042 821int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
bb53fc53 822 struct in_addr *guest_addr, int guest_port)
a3d4af03 823{
bb53fc53
JK
824 if (!guest_addr->s_addr) {
825 guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
460fec67 826 (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
c92ef6a2 827 }
bb53fc53 828 if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
460fec67 829 slirp->vnetwork_addr.s_addr ||
bb53fc53
JK
830 guest_addr->s_addr == slirp->vhost_addr.s_addr ||
831 guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
a13a4126
JK
832 return -1;
833 }
bb53fc53 834 return add_exec(&slirp->exec_list, do_pty, (char *)args, *guest_addr,
a13a4126 835 htons(guest_port));
a3d4af03 836}
e1c5a2b3
AL
837
838ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
839{
840 if (so->s == -1 && so->extra) {
841 qemu_chr_write(so->extra, buf, len);
842 return len;
843 }
844
845 return send(so->s, buf, len, flags);
846}
847
a13a4126 848static struct socket *
460fec67 849slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port)
e1c5a2b3 850{
a13a4126 851 struct socket *so;
e1c5a2b3 852
460fec67 853 for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
a13a4126
JK
854 if (so->so_faddr.s_addr == guest_addr.s_addr &&
855 htons(so->so_fport) == guest_port) {
856 return so;
857 }
858 }
859 return NULL;
e1c5a2b3
AL
860}
861
9f8bd042
JK
862size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
863 int guest_port)
e1c5a2b3
AL
864{
865 struct iovec iov[2];
866 struct socket *so;
867
460fec67 868 so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
e1c5a2b3
AL
869
870 if (!so || so->so_state & SS_NOFDREF)
871 return 0;
872
873 if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2))
874 return 0;
875
876 return sopreprbuf(so, iov, NULL);
877}
878
9f8bd042 879void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
c92ef6a2 880 const uint8_t *buf, int size)
e1c5a2b3
AL
881{
882 int ret;
460fec67 883 struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
a13a4126 884
e1c5a2b3
AL
885 if (!so)
886 return;
887
0580ac91 888 ret = soreadbuf(so, (const char *)buf, size);
e1c5a2b3
AL
889
890 if (ret > 0)
891 tcp_output(sototcpcb(so));
892}
062e5527
AL
893
894static void slirp_tcp_save(QEMUFile *f, struct tcpcb *tp)
895{
896 int i;
897
898 qemu_put_sbe16(f, tp->t_state);
899 for (i = 0; i < TCPT_NTIMERS; i++)
900 qemu_put_sbe16(f, tp->t_timer[i]);
901 qemu_put_sbe16(f, tp->t_rxtshift);
902 qemu_put_sbe16(f, tp->t_rxtcur);
903 qemu_put_sbe16(f, tp->t_dupacks);
904 qemu_put_be16(f, tp->t_maxseg);
905 qemu_put_sbyte(f, tp->t_force);
906 qemu_put_be16(f, tp->t_flags);
907 qemu_put_be32(f, tp->snd_una);
908 qemu_put_be32(f, tp->snd_nxt);
909 qemu_put_be32(f, tp->snd_up);
910 qemu_put_be32(f, tp->snd_wl1);
911 qemu_put_be32(f, tp->snd_wl2);
912 qemu_put_be32(f, tp->iss);
913 qemu_put_be32(f, tp->snd_wnd);
914 qemu_put_be32(f, tp->rcv_wnd);
915 qemu_put_be32(f, tp->rcv_nxt);
916 qemu_put_be32(f, tp->rcv_up);
917 qemu_put_be32(f, tp->irs);
918 qemu_put_be32(f, tp->rcv_adv);
919 qemu_put_be32(f, tp->snd_max);
920 qemu_put_be32(f, tp->snd_cwnd);
921 qemu_put_be32(f, tp->snd_ssthresh);
922 qemu_put_sbe16(f, tp->t_idle);
923 qemu_put_sbe16(f, tp->t_rtt);
924 qemu_put_be32(f, tp->t_rtseq);
925 qemu_put_sbe16(f, tp->t_srtt);
926 qemu_put_sbe16(f, tp->t_rttvar);
927 qemu_put_be16(f, tp->t_rttmin);
928 qemu_put_be32(f, tp->max_sndwnd);
929 qemu_put_byte(f, tp->t_oobflags);
930 qemu_put_byte(f, tp->t_iobc);
931 qemu_put_sbe16(f, tp->t_softerror);
932 qemu_put_byte(f, tp->snd_scale);
933 qemu_put_byte(f, tp->rcv_scale);
934 qemu_put_byte(f, tp->request_r_scale);
935 qemu_put_byte(f, tp->requested_s_scale);
936 qemu_put_be32(f, tp->ts_recent);
937 qemu_put_be32(f, tp->ts_recent_age);
938 qemu_put_be32(f, tp->last_ack_sent);
939}
940
941static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf)
942{
943 uint32_t off;
944
945 qemu_put_be32(f, sbuf->sb_cc);
946 qemu_put_be32(f, sbuf->sb_datalen);
947 off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data);
948 qemu_put_sbe32(f, off);
949 off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data);
950 qemu_put_sbe32(f, off);
951 qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
952}
953
954static void slirp_socket_save(QEMUFile *f, struct socket *so)
955{
956 qemu_put_be32(f, so->so_urgc);
957 qemu_put_be32(f, so->so_faddr.s_addr);
958 qemu_put_be32(f, so->so_laddr.s_addr);
959 qemu_put_be16(f, so->so_fport);
960 qemu_put_be16(f, so->so_lport);
961 qemu_put_byte(f, so->so_iptos);
962 qemu_put_byte(f, so->so_emu);
963 qemu_put_byte(f, so->so_type);
964 qemu_put_be32(f, so->so_state);
965 slirp_sbuf_save(f, &so->so_rcv);
966 slirp_sbuf_save(f, &so->so_snd);
967 slirp_tcp_save(f, so->so_tcpcb);
968}
969
0a1f851e
JK
970static void slirp_bootp_save(QEMUFile *f, Slirp *slirp)
971{
972 int i;
973
974 for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
975 qemu_put_be16(f, slirp->bootp_clients[i].allocated);
976 qemu_put_buffer(f, slirp->bootp_clients[i].macaddr, 6);
977 }
978}
979
062e5527
AL
980static void slirp_state_save(QEMUFile *f, void *opaque)
981{
460fec67 982 Slirp *slirp = opaque;
062e5527
AL
983 struct ex_list *ex_ptr;
984
460fec67 985 for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
062e5527
AL
986 if (ex_ptr->ex_pty == 3) {
987 struct socket *so;
460fec67
JK
988 so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
989 ntohs(ex_ptr->ex_fport));
062e5527
AL
990 if (!so)
991 continue;
992
993 qemu_put_byte(f, 42);
994 slirp_socket_save(f, so);
995 }
996 qemu_put_byte(f, 0);
285f7a62 997
460fec67 998 qemu_put_be16(f, slirp->ip_id);
0a1f851e
JK
999
1000 slirp_bootp_save(f, slirp);
062e5527
AL
1001}
1002
1003static void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp)
1004{
1005 int i;
1006
1007 tp->t_state = qemu_get_sbe16(f);
1008 for (i = 0; i < TCPT_NTIMERS; i++)
1009 tp->t_timer[i] = qemu_get_sbe16(f);
1010 tp->t_rxtshift = qemu_get_sbe16(f);
1011 tp->t_rxtcur = qemu_get_sbe16(f);
1012 tp->t_dupacks = qemu_get_sbe16(f);
1013 tp->t_maxseg = qemu_get_be16(f);
1014 tp->t_force = qemu_get_sbyte(f);
1015 tp->t_flags = qemu_get_be16(f);
1016 tp->snd_una = qemu_get_be32(f);
1017 tp->snd_nxt = qemu_get_be32(f);
1018 tp->snd_up = qemu_get_be32(f);
1019 tp->snd_wl1 = qemu_get_be32(f);
1020 tp->snd_wl2 = qemu_get_be32(f);
1021 tp->iss = qemu_get_be32(f);
1022 tp->snd_wnd = qemu_get_be32(f);
1023 tp->rcv_wnd = qemu_get_be32(f);
1024 tp->rcv_nxt = qemu_get_be32(f);
1025 tp->rcv_up = qemu_get_be32(f);
1026 tp->irs = qemu_get_be32(f);
1027 tp->rcv_adv = qemu_get_be32(f);
1028 tp->snd_max = qemu_get_be32(f);
1029 tp->snd_cwnd = qemu_get_be32(f);
1030 tp->snd_ssthresh = qemu_get_be32(f);
1031 tp->t_idle = qemu_get_sbe16(f);
1032 tp->t_rtt = qemu_get_sbe16(f);
1033 tp->t_rtseq = qemu_get_be32(f);
1034 tp->t_srtt = qemu_get_sbe16(f);
1035 tp->t_rttvar = qemu_get_sbe16(f);
1036 tp->t_rttmin = qemu_get_be16(f);
1037 tp->max_sndwnd = qemu_get_be32(f);
1038 tp->t_oobflags = qemu_get_byte(f);
1039 tp->t_iobc = qemu_get_byte(f);
1040 tp->t_softerror = qemu_get_sbe16(f);
1041 tp->snd_scale = qemu_get_byte(f);
1042 tp->rcv_scale = qemu_get_byte(f);
1043 tp->request_r_scale = qemu_get_byte(f);
1044 tp->requested_s_scale = qemu_get_byte(f);
1045 tp->ts_recent = qemu_get_be32(f);
1046 tp->ts_recent_age = qemu_get_be32(f);
1047 tp->last_ack_sent = qemu_get_be32(f);
1048 tcp_template(tp);
1049}
1050
1051static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf)
1052{
1053 uint32_t off, sb_cc, sb_datalen;
1054
1055 sb_cc = qemu_get_be32(f);
1056 sb_datalen = qemu_get_be32(f);
1057
1058 sbreserve(sbuf, sb_datalen);
1059
1060 if (sbuf->sb_datalen != sb_datalen)
1061 return -ENOMEM;
1062
1063 sbuf->sb_cc = sb_cc;
1064
1065 off = qemu_get_sbe32(f);
1066 sbuf->sb_wptr = sbuf->sb_data + off;
1067 off = qemu_get_sbe32(f);
1068 sbuf->sb_rptr = sbuf->sb_data + off;
1069 qemu_get_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
1070
1071 return 0;
1072}
1073
1074static int slirp_socket_load(QEMUFile *f, struct socket *so)
1075{
1076 if (tcp_attach(so) < 0)
1077 return -ENOMEM;
1078
1079 so->so_urgc = qemu_get_be32(f);
1080 so->so_faddr.s_addr = qemu_get_be32(f);
1081 so->so_laddr.s_addr = qemu_get_be32(f);
1082 so->so_fport = qemu_get_be16(f);
1083 so->so_lport = qemu_get_be16(f);
1084 so->so_iptos = qemu_get_byte(f);
1085 so->so_emu = qemu_get_byte(f);
1086 so->so_type = qemu_get_byte(f);
1087 so->so_state = qemu_get_be32(f);
1088 if (slirp_sbuf_load(f, &so->so_rcv) < 0)
1089 return -ENOMEM;
1090 if (slirp_sbuf_load(f, &so->so_snd) < 0)
1091 return -ENOMEM;
1092 slirp_tcp_load(f, so->so_tcpcb);
1093
1094 return 0;
1095}
1096
0a1f851e
JK
1097static void slirp_bootp_load(QEMUFile *f, Slirp *slirp)
1098{
1099 int i;
1100
1101 for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
1102 slirp->bootp_clients[i].allocated = qemu_get_be16(f);
1103 qemu_get_buffer(f, slirp->bootp_clients[i].macaddr, 6);
1104 }
1105}
1106
062e5527
AL
1107static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
1108{
460fec67 1109 Slirp *slirp = opaque;
062e5527 1110 struct ex_list *ex_ptr;
062e5527 1111
b0e04867 1112 while (qemu_get_byte(f)) {
062e5527 1113 int ret;
460fec67 1114 struct socket *so = socreate(slirp);
062e5527
AL
1115
1116 if (!so)
1117 return -ENOMEM;
1118
1119 ret = slirp_socket_load(f, so);
1120
1121 if (ret < 0)
1122 return ret;
1123
460fec67
JK
1124 if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) !=
1125 slirp->vnetwork_addr.s_addr) {
062e5527 1126 return -EINVAL;
a13a4126 1127 }
460fec67 1128 for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
062e5527 1129 if (ex_ptr->ex_pty == 3 &&
a13a4126
JK
1130 so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
1131 so->so_fport == ex_ptr->ex_fport) {
062e5527 1132 break;
a13a4126
JK
1133 }
1134 }
062e5527
AL
1135 if (!ex_ptr)
1136 return -EINVAL;
1137
0580ac91 1138 so->extra = (void *)ex_ptr->ex_exec;
062e5527
AL
1139 }
1140
285f7a62 1141 if (version_id >= 2) {
460fec67 1142 slirp->ip_id = qemu_get_be16(f);
285f7a62
JK
1143 }
1144
0a1f851e
JK
1145 if (version_id >= 3) {
1146 slirp_bootp_load(f, slirp);
1147 }
1148
062e5527
AL
1149 return 0;
1150}