Statistics
| Branch: | Revision:

root / slirp / slirp.c @ 1e6eec8b

History | View | Annotate | Download (30.5 kB)

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