|
|
1.1.1.5 root 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: */
24: #include "qemu-common.h"
1.1.1.6 root 25: #include "qemu-timer.h"
1.1.1.5 root 26: #include "qemu-char.h"
1.1 root 27: #include "slirp.h"
1.1.1.5 root 28: #include "hw/hw.h"
1.1 root 29:
30: /* host loopback address */
31: struct in_addr loopback_addr;
32:
1.1.1.6 root 33: /* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
1.1.1.4 root 34: static const uint8_t special_ethaddr[6] = {
1.1.1.6 root 35: 0x52, 0x55, 0x00, 0x00, 0x00, 0x00
1.1 root 36: };
37:
1.1.1.5 root 38: static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
1.1 root 39:
40: /* XXX: suppress those select globals */
41: fd_set *global_readfds, *global_writefds, *global_xfds;
42:
1.1.1.6 root 43: u_int curtime;
44: static u_int time_fasttimo, last_slowtimo;
45: static int do_slowtimo;
46:
1.1.1.7 root 47: static QTAILQ_HEAD(slirp_instances, Slirp) slirp_instances =
48: QTAILQ_HEAD_INITIALIZER(slirp_instances);
49:
50: static struct in_addr dns_addr;
51: static u_int dns_addr_time;
1.1.1.2 root 52:
1.1 root 53: #ifdef _WIN32
54:
1.1.1.7 root 55: int get_dns_addr(struct in_addr *pdns_addr)
1.1 root 56: {
57: FIXED_INFO *FixedInfo=NULL;
58: ULONG BufLen;
59: DWORD ret;
60: IP_ADDR_STRING *pIPAddr;
61: struct in_addr tmp_addr;
1.1.1.4 root 62:
1.1.1.7 root 63: if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < 1000) {
64: *pdns_addr = dns_addr;
65: return 0;
66: }
67:
1.1 root 68: FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
69: BufLen = sizeof(FIXED_INFO);
1.1.1.4 root 70:
1.1 root 71: if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
72: if (FixedInfo) {
73: GlobalFree(FixedInfo);
74: FixedInfo = NULL;
75: }
76: FixedInfo = GlobalAlloc(GPTR, BufLen);
77: }
1.1.1.4 root 78:
1.1 root 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: }
1.1.1.4 root 87:
1.1 root 88: pIPAddr = &(FixedInfo->DnsServerList);
89: inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
90: *pdns_addr = tmp_addr;
1.1.1.7 root 91: dns_addr = tmp_addr;
92: dns_addr_time = curtime;
1.1 root 93: if (FixedInfo) {
94: GlobalFree(FixedInfo);
95: FixedInfo = NULL;
96: }
97: return 0;
98: }
99:
1.1.1.6 root 100: static void winsock_cleanup(void)
101: {
102: WSACleanup();
103: }
104:
1.1 root 105: #else
106:
1.1.1.7 root 107: static struct stat dns_addr_stat;
108:
109: int get_dns_addr(struct in_addr *pdns_addr)
1.1 root 110: {
111: char buff[512];
1.1.1.5 root 112: char buff2[257];
1.1 root 113: FILE *f;
114: int found = 0;
115: struct in_addr tmp_addr;
1.1.1.4 root 116:
1.1.1.7 root 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:
1.1 root 135: f = fopen("/etc/resolv.conf", "r");
136: if (!f)
137: return -1;
138:
1.1.1.4 root 139: #ifdef DEBUG
1.1 root 140: lprint("IP address of your DNS(s): ");
1.1.1.4 root 141: #endif
1.1 root 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 it's the first one, set it to dns_addr */
1.1.1.7 root 147: if (!found) {
1.1 root 148: *pdns_addr = tmp_addr;
1.1.1.7 root 149: dns_addr = tmp_addr;
150: dns_addr_time = curtime;
151: }
1.1.1.4 root 152: #ifdef DEBUG
1.1 root 153: else
154: lprint(", ");
1.1.1.4 root 155: #endif
1.1 root 156: if (++found > 3) {
1.1.1.4 root 157: #ifdef DEBUG
1.1 root 158: lprint("(more)");
1.1.1.4 root 159: #endif
1.1 root 160: break;
1.1.1.4 root 161: }
162: #ifdef DEBUG
163: else
1.1 root 164: lprint("%s", inet_ntoa(tmp_addr));
1.1.1.4 root 165: #endif
1.1 root 166: }
167: }
168: fclose(f);
169: if (!found)
170: return -1;
171: return 0;
172: }
173:
174: #endif
175:
1.1.1.6 root 176: static void slirp_init_once(void)
1.1 root 177: {
1.1.1.6 root 178: static int initialized;
179: #ifdef _WIN32
180: WSADATA Data;
1.1 root 181: #endif
182:
1.1.1.6 root 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);
194: }
195:
1.1.1.5 root 196: static void slirp_state_save(QEMUFile *f, void *opaque);
197: static int slirp_state_load(QEMUFile *f, void *opaque, int version_id);
198:
1.1.1.6 root 199: Slirp *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)
1.1 root 204: {
1.1.1.6 root 205: Slirp *slirp = qemu_mallocz(sizeof(Slirp));
1.1.1.4 root 206:
1.1.1.6 root 207: slirp_init_once();
1.1 root 208:
1.1.1.6 root 209: slirp->restricted = restricted;
1.1 root 210:
1.1.1.6 root 211: if_init(slirp);
212: ip_init(slirp);
1.1 root 213:
214: /* Initialise mbufs *after* setting the MTU */
1.1.1.6 root 215: m_init(slirp);
1.1 root 216:
1.1.1.6 root 217: slirp->vnetwork_addr = vnetwork;
218: slirp->vnetwork_mask = vnetmask;
219: slirp->vhost_addr = vhost;
220: if (vhostname) {
221: pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
222: vhostname);
223: }
224: if (tftp_path) {
225: slirp->tftp_prefix = qemu_strdup(tftp_path);
1.1 root 226: }
1.1.1.6 root 227: if (bootfile) {
228: slirp->bootp_filename = qemu_strdup(bootfile);
229: }
230: slirp->vdhcp_startaddr = vdhcp_start;
231: slirp->vnameserver_addr = vnameserver;
1.1 root 232:
1.1.1.6 root 233: slirp->opaque = opaque;
1.1.1.5 root 234:
1.1.1.8 root 235: register_savevm(NULL, "slirp", 0, 3,
236: slirp_state_save, slirp_state_load, slirp);
1.1 root 237:
1.1.1.7 root 238: QTAILQ_INSERT_TAIL(&slirp_instances, slirp, entry);
1.1 root 239:
1.1.1.6 root 240: return slirp;
1.1 root 241: }
1.1.1.6 root 242:
243: void slirp_cleanup(Slirp *slirp)
1.1 root 244: {
1.1.1.7 root 245: QTAILQ_REMOVE(&slirp_instances, slirp, entry);
1.1.1.4 root 246:
1.1.1.8 root 247: unregister_savevm(NULL, "slirp", slirp);
1.1.1.4 root 248:
1.1.1.6 root 249: qemu_free(slirp->tftp_prefix);
250: qemu_free(slirp->bootp_filename);
251: qemu_free(slirp);
1.1 root 252: }
1.1.1.6 root 253:
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)
1.1 root 257:
1.1.1.4 root 258: void slirp_select_fill(int *pnfds,
1.1 root 259: fd_set *readfds, fd_set *writefds, fd_set *xfds)
260: {
1.1.1.6 root 261: Slirp *slirp;
1.1 root 262: struct socket *so, *so_next;
263: int nfds;
1.1.1.6 root 264:
1.1.1.7 root 265: if (QTAILQ_EMPTY(&slirp_instances)) {
1.1.1.6 root 266: return;
267: }
1.1 root 268:
269: /* fail safe */
270: global_readfds = NULL;
271: global_writefds = NULL;
272: global_xfds = NULL;
1.1.1.4 root 273:
1.1 root 274: nfds = *pnfds;
275: /*
276: * First, TCP sockets
277: */
278: do_slowtimo = 0;
1.1.1.6 root 279:
1.1.1.7 root 280: QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
1.1.1.4 root 281: /*
1.1 root 282: * *_slowtimo needs calling if there are IP fragments
283: * in the fragment queue, or there are TCP connections active
284: */
1.1.1.6 root 285: do_slowtimo |= ((slirp->tcb.so_next != &slirp->tcb) ||
286: (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
1.1.1.4 root 287:
1.1.1.6 root 288: for (so = slirp->tcb.so_next; so != &slirp->tcb;
289: so = so_next) {
1.1 root 290: so_next = so->so_next;
1.1.1.4 root 291:
1.1 root 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 */
1.1.1.4 root 297:
1.1 root 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;
1.1.1.4 root 304:
1.1 root 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: }
1.1.1.4 root 313:
1.1 root 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: }
1.1.1.4 root 322:
1.1 root 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: }
1.1.1.4 root 331:
1.1 root 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: }
1.1.1.4 root 342:
1.1 root 343: /*
344: * UDP sockets
345: */
1.1.1.6 root 346: for (so = slirp->udb.so_next; so != &slirp->udb;
347: so = so_next) {
1.1 root 348: so_next = so->so_next;
1.1.1.4 root 349:
1.1 root 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: }
1.1.1.4 root 360:
1.1 root 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: }
1.1.1.10! root 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: }
1.1 root 401: }
1.1.1.4 root 402:
1.1 root 403: *pnfds = nfds;
1.1.1.4 root 404: }
1.1 root 405:
1.1.1.6 root 406: void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
407: int select_error)
1.1 root 408: {
1.1.1.6 root 409: Slirp *slirp;
1.1 root 410: struct socket *so, *so_next;
411: int ret;
412:
1.1.1.7 root 413: if (QTAILQ_EMPTY(&slirp_instances)) {
1.1.1.6 root 414: return;
415: }
416:
1.1 root 417: global_readfds = readfds;
418: global_writefds = writefds;
419: global_xfds = xfds;
420:
1.1.1.10! root 421: curtime = qemu_get_clock_ms(rt_clock);
1.1.1.4 root 422:
1.1.1.7 root 423: QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
1.1 root 424: /*
1.1.1.4 root 425: * See if anything has timed out
1.1 root 426: */
427: if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
1.1.1.6 root 428: tcp_fasttimo(slirp);
1.1 root 429: time_fasttimo = 0;
430: }
431: if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
1.1.1.6 root 432: ip_slowtimo(slirp);
433: tcp_slowtimo(slirp);
1.1 root 434: last_slowtimo = curtime;
435: }
1.1.1.4 root 436:
1.1 root 437: /*
438: * Check sockets
439: */
1.1.1.6 root 440: if (!select_error) {
1.1 root 441: /*
442: * Check TCP sockets
443: */
1.1.1.6 root 444: for (so = slirp->tcb.so_next; so != &slirp->tcb;
445: so = so_next) {
1.1 root 446: so_next = so->so_next;
1.1.1.4 root 447:
1.1 root 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;
1.1.1.4 root 454:
1.1 root 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);
1.1.1.4 root 474:
1.1 root 475: /* Output it if we read something */
476: if (ret > 0)
477: tcp_output(sototcpcb(so));
478: }
1.1.1.4 root 479:
1.1 root 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;
1.1.1.4 root 490:
1.1.1.6 root 491: ret = send(so->s, (const void *) &ret, 0, 0);
1.1 root 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;
1.1.1.4 root 497:
1.1 root 498: /* else failed */
1.1.1.6 root 499: so->so_state &= SS_PERSISTENT_MASK;
500: so->so_state |= SS_NOFDREF;
1.1 root 501: }
502: /* else so->so_state &= ~SS_ISFCONNECTING; */
1.1.1.4 root 503:
1.1 root 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: /*
1.1.1.4 root 512: * XXXXX If we wrote something (a lot), there
1.1 root 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: }
1.1.1.4 root 518:
1.1 root 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) {
1.1.1.10! root 525: ret = qemu_recv(so->s, &ret, 0,0);
1.1.1.4 root 526:
1.1 root 527: if (ret < 0) {
528: /* XXX */
529: if (errno == EAGAIN || errno == EWOULDBLOCK ||
530: errno == EINPROGRESS || errno == ENOTCONN)
531: continue; /* Still connecting, continue */
1.1.1.4 root 532:
1.1 root 533: /* else failed */
1.1.1.6 root 534: so->so_state &= SS_PERSISTENT_MASK;
535: so->so_state |= SS_NOFDREF;
1.1.1.4 root 536:
1.1 root 537: /* tcp_input will take care of it */
538: } else {
539: ret = send(so->s, &ret, 0,0);
540: if (ret < 0) {
541: /* XXX */
542: if (errno == EAGAIN || errno == EWOULDBLOCK ||
543: errno == EINPROGRESS || errno == ENOTCONN)
544: continue;
545: /* else failed */
1.1.1.6 root 546: so->so_state &= SS_PERSISTENT_MASK;
547: so->so_state |= SS_NOFDREF;
1.1 root 548: } else
549: so->so_state &= ~SS_ISFCONNECTING;
1.1.1.4 root 550:
1.1 root 551: }
552: tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
553: } /* SS_ISFCONNECTING */
554: #endif
555: }
1.1.1.4 root 556:
1.1 root 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: */
1.1.1.6 root 562: for (so = slirp->udb.so_next; so != &slirp->udb;
563: so = so_next) {
1.1 root 564: so_next = so->so_next;
1.1.1.4 root 565:
1.1 root 566: if (so->s != -1 && FD_ISSET(so->s, readfds)) {
567: sorecvfrom(so);
568: }
569: }
1.1.1.10! root 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: }
1.1 root 582: }
1.1.1.4 root 583:
1.1 root 584: /*
585: * See if we can start outputting
586: */
1.1.1.6 root 587: if (slirp->if_queued) {
588: if_start(slirp);
589: }
590: }
1.1 root 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;
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:
1.1.1.4 root 611: struct ethhdr
1.1 root 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:
618: struct 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 */
1.1.1.6 root 630: uint32_t ar_sip; /* sender IP address */
1.1 root 631: unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
1.1.1.6 root 632: uint32_t ar_tip ; /* target IP address */
633: } __attribute__((packed));
1.1 root 634:
1.1.1.6 root 635: static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
1.1 root 636: {
637: struct ethhdr *eh = (struct ethhdr *)pkt;
638: struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
1.1.1.9 root 639: uint8_t arp_reply[max(ETH_HLEN + sizeof(struct arphdr), 64)];
1.1 root 640: struct ethhdr *reh = (struct ethhdr *)arp_reply;
641: struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
642: int ar_op;
643: struct ex_list *ex_ptr;
644:
645: ar_op = ntohs(ah->ar_op);
646: switch(ar_op) {
647: case ARPOP_REQUEST:
1.1.1.6 root 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)
1.1 root 652: goto arp_ok;
1.1.1.6 root 653: for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
654: if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
1.1 root 655: goto arp_ok;
656: }
657: return;
658: arp_ok:
1.1.1.9 root 659: memset(arp_reply, 0, sizeof(arp_reply));
1.1 root 660: /* XXX: make an ARP request to have the client address */
1.1.1.6 root 661: memcpy(slirp->client_ethaddr, eh->h_source, ETH_ALEN);
1.1 root 662:
663: /* ARP request for alias/dns mac address */
664: memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
1.1.1.6 root 665: memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
666: memcpy(&reh->h_source[2], &ah->ar_tip, 4);
1.1 root 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);
1.1.1.6 root 675: rah->ar_sip = ah->ar_tip;
1.1 root 676: memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
1.1.1.6 root 677: rah->ar_tip = ah->ar_sip;
678: slirp_output(slirp->opaque, arp_reply, sizeof(arp_reply));
1.1 root 679: }
680: break;
1.1.1.5 root 681: case ARPOP_REPLY:
682: /* reply to request of client mac address ? */
1.1.1.6 root 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);
1.1.1.5 root 686: }
687: break;
1.1 root 688: default:
689: break;
690: }
691: }
692:
1.1.1.6 root 693: void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
1.1 root 694: {
695: struct mbuf *m;
696: int proto;
697:
698: if (pkt_len < ETH_HLEN)
699: return;
1.1.1.4 root 700:
1.1 root 701: proto = ntohs(*(uint16_t *)(pkt + 12));
702: switch(proto) {
703: case ETH_P_ARP:
1.1.1.6 root 704: arp_input(slirp, pkt, pkt_len);
1.1 root 705: break;
706: case ETH_P_IP:
1.1.1.6 root 707: m = m_get(slirp);
1.1 root 708: if (!m)
709: return;
1.1.1.3 root 710: /* Note: we add to align the IP header */
1.1.1.5 root 711: if (M_FREEROOM(m) < pkt_len + 2) {
712: m_inc(m, pkt_len + 2);
713: }
1.1.1.3 root 714: m->m_len = pkt_len + 2;
715: memcpy(m->m_data + 2, pkt, pkt_len);
1.1 root 716:
1.1.1.3 root 717: m->m_data += 2 + ETH_HLEN;
718: m->m_len -= 2 + ETH_HLEN;
1.1 root 719:
720: ip_input(m);
721: break;
722: default:
723: break;
724: }
725: }
726:
727: /* output the IP packet to the ethernet device */
1.1.1.6 root 728: void if_encap(Slirp *slirp, const uint8_t *ip_data, int ip_data_len)
1.1 root 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;
1.1.1.5 root 735:
1.1.1.6 root 736: if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN)) {
1.1.1.5 root 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);
1.1.1.6 root 748: memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
749: memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
1.1.1.5 root 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 */
1.1.1.6 root 757: memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
758: memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
1.1.1.5 root 759: /* source IP */
1.1.1.6 root 760: rah->ar_sip = slirp->vhost_addr.s_addr;
1.1.1.5 root 761: /* target hw addr (none) */
762: memset(rah->ar_tha, 0, ETH_ALEN);
763: /* target IP */
1.1.1.6 root 764: rah->ar_tip = iph->ip_dst.s_addr;
765: slirp->client_ipaddr = iph->ip_dst;
766: slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
1.1.1.5 root 767: } else {
1.1.1.6 root 768: memcpy(eh->h_dest, slirp->client_ethaddr, ETH_ALEN);
769: memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
1.1.1.5 root 770: /* XXX: not correct */
1.1.1.6 root 771: memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
1.1.1.5 root 772: eh->h_proto = htons(ETH_P_IP);
773: memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
1.1.1.6 root 774: slirp_output(slirp->opaque, buf, ip_data_len + ETH_HLEN);
1.1.1.5 root 775: }
1.1 root 776: }
777:
1.1.1.6 root 778: /* Drop host forwarding rule, return 0 if found. */
779: int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
780: int host_port)
781: {
782: struct socket *so;
783: struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb);
784: struct sockaddr_in addr;
785: int port = htons(host_port);
786: socklen_t addr_len;
787:
788: for (so = head->so_next; so != head; so = so->so_next) {
789: addr_len = sizeof(addr);
790: if ((so->so_state & SS_HOSTFWD) &&
791: getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
792: addr.sin_addr.s_addr == host_addr.s_addr &&
793: addr.sin_port == port) {
794: close(so->s);
795: sofree(so);
796: return 0;
797: }
798: }
799:
800: return -1;
801: }
802:
803: int 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)
1.1 root 805: {
1.1.1.6 root 806: if (!guest_addr.s_addr) {
807: guest_addr = slirp->vdhcp_startaddr;
808: }
1.1 root 809: if (is_udp) {
1.1.1.6 root 810: if (!udp_listen(slirp, host_addr.s_addr, htons(host_port),
811: guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
1.1 root 812: return -1;
813: } else {
1.1.1.6 root 814: if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port),
815: guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
1.1 root 816: return -1;
817: }
818: return 0;
819: }
820:
1.1.1.6 root 821: int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
822: struct in_addr *guest_addr, int guest_port)
1.1 root 823: {
1.1.1.6 root 824: if (!guest_addr->s_addr) {
825: guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
826: (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
827: }
828: if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
829: slirp->vnetwork_addr.s_addr ||
830: guest_addr->s_addr == slirp->vhost_addr.s_addr ||
831: guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
832: return -1;
833: }
834: return add_exec(&slirp->exec_list, do_pty, (char *)args, *guest_addr,
835: htons(guest_port));
1.1 root 836: }
1.1.1.5 root 837:
838: ssize_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:
1.1.1.6 root 848: static struct socket *
849: slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port)
1.1.1.5 root 850: {
1.1.1.6 root 851: struct socket *so;
1.1.1.5 root 852:
1.1.1.6 root 853: for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
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;
1.1.1.5 root 860: }
861:
1.1.1.6 root 862: size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
863: int guest_port)
1.1.1.5 root 864: {
865: struct iovec iov[2];
866: struct socket *so;
867:
1.1.1.6 root 868: so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
1.1.1.5 root 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:
1.1.1.6 root 879: void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
880: const uint8_t *buf, int size)
1.1.1.5 root 881: {
882: int ret;
1.1.1.6 root 883: struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
884:
1.1.1.5 root 885: if (!so)
886: return;
887:
888: ret = soreadbuf(so, (const char *)buf, size);
889:
890: if (ret > 0)
891: tcp_output(sototcpcb(so));
892: }
893:
894: static 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:
941: static 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:
954: static 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:
1.1.1.6 root 970: static 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:
1.1.1.5 root 980: static void slirp_state_save(QEMUFile *f, void *opaque)
981: {
1.1.1.6 root 982: Slirp *slirp = opaque;
1.1.1.5 root 983: struct ex_list *ex_ptr;
984:
1.1.1.6 root 985: for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
1.1.1.5 root 986: if (ex_ptr->ex_pty == 3) {
987: struct socket *so;
1.1.1.6 root 988: so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
989: ntohs(ex_ptr->ex_fport));
1.1.1.5 root 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);
1.1.1.6 root 997:
998: qemu_put_be16(f, slirp->ip_id);
999:
1000: slirp_bootp_save(f, slirp);
1.1.1.5 root 1001: }
1002:
1003: static 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:
1051: static 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:
1074: static 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:
1.1.1.6 root 1097: static 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:
1.1.1.5 root 1107: static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
1108: {
1.1.1.6 root 1109: Slirp *slirp = opaque;
1.1.1.5 root 1110: struct ex_list *ex_ptr;
1111:
1.1.1.8 root 1112: while (qemu_get_byte(f)) {
1.1.1.5 root 1113: int ret;
1.1.1.6 root 1114: struct socket *so = socreate(slirp);
1.1.1.5 root 1115:
1116: if (!so)
1117: return -ENOMEM;
1118:
1119: ret = slirp_socket_load(f, so);
1120:
1121: if (ret < 0)
1122: return ret;
1123:
1.1.1.6 root 1124: if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) !=
1125: slirp->vnetwork_addr.s_addr) {
1.1.1.5 root 1126: return -EINVAL;
1.1.1.6 root 1127: }
1128: for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
1.1.1.5 root 1129: if (ex_ptr->ex_pty == 3 &&
1.1.1.6 root 1130: so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
1131: so->so_fport == ex_ptr->ex_fport) {
1.1.1.5 root 1132: break;
1.1.1.6 root 1133: }
1134: }
1.1.1.5 root 1135: if (!ex_ptr)
1136: return -EINVAL;
1137:
1138: so->extra = (void *)ex_ptr->ex_exec;
1139: }
1140:
1.1.1.6 root 1141: if (version_id >= 2) {
1142: slirp->ip_id = qemu_get_be16(f);
1143: }
1144:
1145: if (version_id >= 3) {
1146: slirp_bootp_load(f, slirp);
1147: }
1148:
1.1.1.5 root 1149: return 0;
1150: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.