Statistics
| Branch: | Revision:

root / slirp / slirp.c @ 7267c094

History | View | Annotate | Download (30.7 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 1a0ca1e1 Fabien Chouteau
static const uint8_t special_ethaddr[ETH_ALEN] = {
35 a13a4126 Jan Kiszka
    0x52, 0x55, 0x00, 0x00, 0x00, 0x00
36 f0cbd3ec bellard
};
37 f0cbd3ec bellard
38 1a0ca1e1 Fabien Chouteau
static const uint8_t zero_ethaddr[ETH_ALEN] = { 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 72cf2d4f Blue Swirl
static QTAILQ_HEAD(slirp_instances, Slirp) slirp_instances =
48 72cf2d4f Blue Swirl
    QTAILQ_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 7267c094 Anthony Liguori
    Slirp *slirp = g_malloc0(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 7267c094 Anthony Liguori
        slirp->tftp_prefix = g_strdup(tftp_path);
226 ad196a9d Jan Kiszka
    }
227 ad196a9d Jan Kiszka
    if (bootfile) {
228 7267c094 Anthony Liguori
        slirp->bootp_filename = g_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 0be71e32 Alex Williamson
    register_savevm(NULL, "slirp", 0, 3,
236 0be71e32 Alex Williamson
                    slirp_state_save, slirp_state_load, slirp);
237 9f8bd042 Jan Kiszka
238 72cf2d4f Blue Swirl
    QTAILQ_INSERT_TAIL(&slirp_instances, slirp, entry);
239 ad0d8c4c Jan Kiszka
240 9f8bd042 Jan Kiszka
    return slirp;
241 f0cbd3ec bellard
}
242 f0cbd3ec bellard
243 ad0d8c4c Jan Kiszka
void slirp_cleanup(Slirp *slirp)
244 ad0d8c4c Jan Kiszka
{
245 72cf2d4f Blue Swirl
    QTAILQ_REMOVE(&slirp_instances, slirp, entry);
246 b1c99fcd Jan Kiszka
247 0be71e32 Alex Williamson
    unregister_savevm(NULL, "slirp", slirp);
248 ad0d8c4c Jan Kiszka
249 7267c094 Anthony Liguori
    g_free(slirp->tftp_prefix);
250 7267c094 Anthony Liguori
    g_free(slirp->bootp_filename);
251 7267c094 Anthony Liguori
    g_free(slirp);
252 ad0d8c4c Jan Kiszka
}
253 ad0d8c4c Jan Kiszka
254 f0cbd3ec bellard
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
255 f0cbd3ec bellard
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
256 f0cbd3ec bellard
#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
257 f0cbd3ec bellard
258 5fafdf24 ths
void slirp_select_fill(int *pnfds,
259 f0cbd3ec bellard
                       fd_set *readfds, fd_set *writefds, fd_set *xfds)
260 f0cbd3ec bellard
{
261 b1c99fcd Jan Kiszka
    Slirp *slirp;
262 f0cbd3ec bellard
    struct socket *so, *so_next;
263 f0cbd3ec bellard
    int nfds;
264 f0cbd3ec bellard
265 72cf2d4f Blue Swirl
    if (QTAILQ_EMPTY(&slirp_instances)) {
266 d918f23e Jan Kiszka
        return;
267 d918f23e Jan Kiszka
    }
268 d918f23e Jan Kiszka
269 f0cbd3ec bellard
    /* fail safe */
270 f0cbd3ec bellard
    global_readfds = NULL;
271 f0cbd3ec bellard
    global_writefds = NULL;
272 f0cbd3ec bellard
    global_xfds = NULL;
273 3b46e624 ths
274 f0cbd3ec bellard
    nfds = *pnfds;
275 f0cbd3ec bellard
        /*
276 f0cbd3ec bellard
         * First, TCP sockets
277 f0cbd3ec bellard
         */
278 f0cbd3ec bellard
        do_slowtimo = 0;
279 d918f23e Jan Kiszka
280 72cf2d4f Blue Swirl
        QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
281 5fafdf24 ths
                /*
282 f0cbd3ec bellard
                 * *_slowtimo needs calling if there are IP fragments
283 f0cbd3ec bellard
                 * in the fragment queue, or there are TCP connections active
284 f0cbd3ec bellard
                 */
285 b1c99fcd Jan Kiszka
                do_slowtimo |= ((slirp->tcb.so_next != &slirp->tcb) ||
286 460fec67 Jan Kiszka
                    (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
287 3b46e624 ths
288 460fec67 Jan Kiszka
                for (so = slirp->tcb.so_next; so != &slirp->tcb;
289 460fec67 Jan Kiszka
                     so = so_next) {
290 f0cbd3ec bellard
                        so_next = so->so_next;
291 3b46e624 ths
292 f0cbd3ec bellard
                        /*
293 f0cbd3ec bellard
                         * See if we need a tcp_fasttimo
294 f0cbd3ec bellard
                         */
295 f0cbd3ec bellard
                        if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
296 f0cbd3ec bellard
                           time_fasttimo = curtime; /* Flag when we want a fasttimo */
297 3b46e624 ths
298 f0cbd3ec bellard
                        /*
299 f0cbd3ec bellard
                         * NOFDREF can include still connecting to local-host,
300 f0cbd3ec bellard
                         * newly socreated() sockets etc. Don't want to select these.
301 f0cbd3ec bellard
                          */
302 f0cbd3ec bellard
                        if (so->so_state & SS_NOFDREF || so->s == -1)
303 f0cbd3ec bellard
                           continue;
304 3b46e624 ths
305 f0cbd3ec bellard
                        /*
306 f0cbd3ec bellard
                         * Set for reading sockets which are accepting
307 f0cbd3ec bellard
                         */
308 f0cbd3ec bellard
                        if (so->so_state & SS_FACCEPTCONN) {
309 f0cbd3ec bellard
                                FD_SET(so->s, readfds);
310 f0cbd3ec bellard
                                UPD_NFDS(so->s);
311 f0cbd3ec bellard
                                continue;
312 f0cbd3ec bellard
                        }
313 3b46e624 ths
314 f0cbd3ec bellard
                        /*
315 f0cbd3ec bellard
                         * Set for writing sockets which are connecting
316 f0cbd3ec bellard
                         */
317 f0cbd3ec bellard
                        if (so->so_state & SS_ISFCONNECTING) {
318 f0cbd3ec bellard
                                FD_SET(so->s, writefds);
319 f0cbd3ec bellard
                                UPD_NFDS(so->s);
320 f0cbd3ec bellard
                                continue;
321 f0cbd3ec bellard
                        }
322 3b46e624 ths
323 f0cbd3ec bellard
                        /*
324 f0cbd3ec bellard
                         * Set for writing if we are connected, can send more, and
325 f0cbd3ec bellard
                         * we have something to send
326 f0cbd3ec bellard
                         */
327 f0cbd3ec bellard
                        if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
328 f0cbd3ec bellard
                                FD_SET(so->s, writefds);
329 f0cbd3ec bellard
                                UPD_NFDS(so->s);
330 f0cbd3ec bellard
                        }
331 3b46e624 ths
332 f0cbd3ec bellard
                        /*
333 f0cbd3ec bellard
                         * Set for reading (and urgent data) if we are connected, can
334 f0cbd3ec bellard
                         * receive more, and we have room for it XXX /2 ?
335 f0cbd3ec bellard
                         */
336 f0cbd3ec bellard
                        if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
337 f0cbd3ec bellard
                                FD_SET(so->s, readfds);
338 f0cbd3ec bellard
                                FD_SET(so->s, xfds);
339 f0cbd3ec bellard
                                UPD_NFDS(so->s);
340 f0cbd3ec bellard
                        }
341 f0cbd3ec bellard
                }
342 3b46e624 ths
343 f0cbd3ec bellard
                /*
344 f0cbd3ec bellard
                 * UDP sockets
345 f0cbd3ec bellard
                 */
346 460fec67 Jan Kiszka
                for (so = slirp->udb.so_next; so != &slirp->udb;
347 460fec67 Jan Kiszka
                     so = so_next) {
348 f0cbd3ec bellard
                        so_next = so->so_next;
349 3b46e624 ths
350 f0cbd3ec bellard
                        /*
351 f0cbd3ec bellard
                         * See if it's timed out
352 f0cbd3ec bellard
                         */
353 f0cbd3ec bellard
                        if (so->so_expire) {
354 f0cbd3ec bellard
                                if (so->so_expire <= curtime) {
355 f0cbd3ec bellard
                                        udp_detach(so);
356 f0cbd3ec bellard
                                        continue;
357 f0cbd3ec bellard
                                } else
358 f0cbd3ec bellard
                                        do_slowtimo = 1; /* Let socket expire */
359 f0cbd3ec bellard
                        }
360 3b46e624 ths
361 f0cbd3ec bellard
                        /*
362 f0cbd3ec bellard
                         * When UDP packets are received from over the
363 f0cbd3ec bellard
                         * link, they're sendto()'d straight away, so
364 f0cbd3ec bellard
                         * no need for setting for writing
365 f0cbd3ec bellard
                         * Limit the number of packets queued by this session
366 f0cbd3ec bellard
                         * to 4.  Note that even though we try and limit this
367 f0cbd3ec bellard
                         * to 4 packets, the session could have more queued
368 f0cbd3ec bellard
                         * if the packets needed to be fragmented
369 f0cbd3ec bellard
                         * (XXX <= 4 ?)
370 f0cbd3ec bellard
                         */
371 f0cbd3ec bellard
                        if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
372 f0cbd3ec bellard
                                FD_SET(so->s, readfds);
373 f0cbd3ec bellard
                                UPD_NFDS(so->s);
374 f0cbd3ec bellard
                        }
375 f0cbd3ec bellard
                }
376 e6d43cfb Jan Kiszka
377 e6d43cfb Jan Kiszka
                /*
378 e6d43cfb Jan Kiszka
                 * ICMP sockets
379 e6d43cfb Jan Kiszka
                 */
380 e6d43cfb Jan Kiszka
                for (so = slirp->icmp.so_next; so != &slirp->icmp;
381 e6d43cfb Jan Kiszka
                     so = so_next) {
382 e6d43cfb Jan Kiszka
                    so_next = so->so_next;
383 e6d43cfb Jan Kiszka
384 e6d43cfb Jan Kiszka
                    /*
385 e6d43cfb Jan Kiszka
                     * See if it's timed out
386 e6d43cfb Jan Kiszka
                     */
387 e6d43cfb Jan Kiszka
                    if (so->so_expire) {
388 e6d43cfb Jan Kiszka
                        if (so->so_expire <= curtime) {
389 e6d43cfb Jan Kiszka
                            icmp_detach(so);
390 e6d43cfb Jan Kiszka
                            continue;
391 e6d43cfb Jan Kiszka
                        } else {
392 e6d43cfb Jan Kiszka
                            do_slowtimo = 1; /* Let socket expire */
393 e6d43cfb Jan Kiszka
                        }
394 e6d43cfb Jan Kiszka
                    }
395 e6d43cfb Jan Kiszka
396 e6d43cfb Jan Kiszka
                    if (so->so_state & SS_ISFCONNECTED) {
397 e6d43cfb Jan Kiszka
                        FD_SET(so->s, readfds);
398 e6d43cfb Jan Kiszka
                        UPD_NFDS(so->s);
399 e6d43cfb Jan Kiszka
                    }
400 e6d43cfb Jan Kiszka
                }
401 b1c99fcd Jan Kiszka
        }
402 5fafdf24 ths
403 f0cbd3ec bellard
        *pnfds = nfds;
404 5fafdf24 ths
}
405 f0cbd3ec bellard
406 d918f23e Jan Kiszka
void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
407 d918f23e Jan Kiszka
                       int select_error)
408 f0cbd3ec bellard
{
409 b1c99fcd Jan Kiszka
    Slirp *slirp;
410 f0cbd3ec bellard
    struct socket *so, *so_next;
411 f0cbd3ec bellard
    int ret;
412 f0cbd3ec bellard
413 72cf2d4f Blue Swirl
    if (QTAILQ_EMPTY(&slirp_instances)) {
414 d918f23e Jan Kiszka
        return;
415 d918f23e Jan Kiszka
    }
416 d918f23e Jan Kiszka
417 f0cbd3ec bellard
    global_readfds = readfds;
418 f0cbd3ec bellard
    global_writefds = writefds;
419 f0cbd3ec bellard
    global_xfds = xfds;
420 f0cbd3ec bellard
421 7bd427d8 Paolo Bonzini
    curtime = qemu_get_clock_ms(rt_clock);
422 5fafdf24 ths
423 72cf2d4f Blue Swirl
    QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
424 f0cbd3ec bellard
        /*
425 5fafdf24 ths
         * See if anything has timed out
426 f0cbd3ec bellard
         */
427 df5f8956 bellard
                if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
428 460fec67 Jan Kiszka
                        tcp_fasttimo(slirp);
429 f0cbd3ec bellard
                        time_fasttimo = 0;
430 f0cbd3ec bellard
                }
431 f0cbd3ec bellard
                if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
432 460fec67 Jan Kiszka
                        ip_slowtimo(slirp);
433 460fec67 Jan Kiszka
                        tcp_slowtimo(slirp);
434 f0cbd3ec bellard
                        last_slowtimo = curtime;
435 f0cbd3ec bellard
                }
436 5fafdf24 ths
437 f0cbd3ec bellard
        /*
438 f0cbd3ec bellard
         * Check sockets
439 f0cbd3ec bellard
         */
440 d918f23e Jan Kiszka
        if (!select_error) {
441 f0cbd3ec bellard
                /*
442 f0cbd3ec bellard
                 * Check TCP sockets
443 f0cbd3ec bellard
                 */
444 460fec67 Jan Kiszka
                for (so = slirp->tcb.so_next; so != &slirp->tcb;
445 460fec67 Jan Kiszka
                     so = so_next) {
446 f0cbd3ec bellard
                        so_next = so->so_next;
447 3b46e624 ths
448 f0cbd3ec bellard
                        /*
449 f0cbd3ec bellard
                         * FD_ISSET is meaningless on these sockets
450 f0cbd3ec bellard
                         * (and they can crash the program)
451 f0cbd3ec bellard
                         */
452 f0cbd3ec bellard
                        if (so->so_state & SS_NOFDREF || so->s == -1)
453 f0cbd3ec bellard
                           continue;
454 3b46e624 ths
455 f0cbd3ec bellard
                        /*
456 f0cbd3ec bellard
                         * Check for URG data
457 f0cbd3ec bellard
                         * This will soread as well, so no need to
458 f0cbd3ec bellard
                         * test for readfds below if this succeeds
459 f0cbd3ec bellard
                         */
460 f0cbd3ec bellard
                        if (FD_ISSET(so->s, xfds))
461 f0cbd3ec bellard
                           sorecvoob(so);
462 f0cbd3ec bellard
                        /*
463 f0cbd3ec bellard
                         * Check sockets for reading
464 f0cbd3ec bellard
                         */
465 f0cbd3ec bellard
                        else if (FD_ISSET(so->s, readfds)) {
466 f0cbd3ec bellard
                                /*
467 f0cbd3ec bellard
                                 * Check for incoming connections
468 f0cbd3ec bellard
                                 */
469 f0cbd3ec bellard
                                if (so->so_state & SS_FACCEPTCONN) {
470 f0cbd3ec bellard
                                        tcp_connect(so);
471 f0cbd3ec bellard
                                        continue;
472 f0cbd3ec bellard
                                } /* else */
473 f0cbd3ec bellard
                                ret = soread(so);
474 3b46e624 ths
475 f0cbd3ec bellard
                                /* Output it if we read something */
476 f0cbd3ec bellard
                                if (ret > 0)
477 f0cbd3ec bellard
                                   tcp_output(sototcpcb(so));
478 f0cbd3ec bellard
                        }
479 3b46e624 ths
480 f0cbd3ec bellard
                        /*
481 f0cbd3ec bellard
                         * Check sockets for writing
482 f0cbd3ec bellard
                         */
483 f0cbd3ec bellard
                        if (FD_ISSET(so->s, writefds)) {
484 f0cbd3ec bellard
                          /*
485 f0cbd3ec bellard
                           * Check for non-blocking, still-connecting sockets
486 f0cbd3ec bellard
                           */
487 f0cbd3ec bellard
                          if (so->so_state & SS_ISFCONNECTING) {
488 f0cbd3ec bellard
                            /* Connected */
489 f0cbd3ec bellard
                            so->so_state &= ~SS_ISFCONNECTING;
490 3b46e624 ths
491 0a656f5f malc
                            ret = send(so->s, (const void *) &ret, 0, 0);
492 f0cbd3ec bellard
                            if (ret < 0) {
493 f0cbd3ec bellard
                              /* XXXXX Must fix, zero bytes is a NOP */
494 f0cbd3ec bellard
                              if (errno == EAGAIN || errno == EWOULDBLOCK ||
495 f0cbd3ec bellard
                                  errno == EINPROGRESS || errno == ENOTCONN)
496 f0cbd3ec bellard
                                continue;
497 3b46e624 ths
498 f0cbd3ec bellard
                              /* else failed */
499 f932b6ce Jan Kiszka
                              so->so_state &= SS_PERSISTENT_MASK;
500 f932b6ce Jan Kiszka
                              so->so_state |= SS_NOFDREF;
501 f0cbd3ec bellard
                            }
502 f0cbd3ec bellard
                            /* else so->so_state &= ~SS_ISFCONNECTING; */
503 3b46e624 ths
504 f0cbd3ec bellard
                            /*
505 f0cbd3ec bellard
                             * Continue tcp_input
506 f0cbd3ec bellard
                             */
507 f0cbd3ec bellard
                            tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
508 f0cbd3ec bellard
                            /* continue; */
509 f0cbd3ec bellard
                          } else
510 f0cbd3ec bellard
                            ret = sowrite(so);
511 f0cbd3ec bellard
                          /*
512 5fafdf24 ths
                           * XXXXX If we wrote something (a lot), there
513 f0cbd3ec bellard
                           * could be a need for a window update.
514 f0cbd3ec bellard
                           * In the worst case, the remote will send
515 f0cbd3ec bellard
                           * a window probe to get things going again
516 f0cbd3ec bellard
                           */
517 f0cbd3ec bellard
                        }
518 3b46e624 ths
519 f0cbd3ec bellard
                        /*
520 f0cbd3ec bellard
                         * Probe a still-connecting, non-blocking socket
521 f0cbd3ec bellard
                         * to check if it's still alive
522 f0cbd3ec bellard
                           */
523 f0cbd3ec bellard
#ifdef PROBE_CONN
524 f0cbd3ec bellard
                        if (so->so_state & SS_ISFCONNECTING) {
525 00aa0040 Blue Swirl
                          ret = qemu_recv(so->s, &ret, 0,0);
526 3b46e624 ths
527 f0cbd3ec bellard
                          if (ret < 0) {
528 f0cbd3ec bellard
                            /* XXX */
529 f0cbd3ec bellard
                            if (errno == EAGAIN || errno == EWOULDBLOCK ||
530 f0cbd3ec bellard
                                errno == EINPROGRESS || errno == ENOTCONN)
531 f0cbd3ec bellard
                              continue; /* Still connecting, continue */
532 3b46e624 ths
533 f0cbd3ec bellard
                            /* else failed */
534 f932b6ce Jan Kiszka
                            so->so_state &= SS_PERSISTENT_MASK;
535 f932b6ce Jan Kiszka
                            so->so_state |= SS_NOFDREF;
536 3b46e624 ths
537 f0cbd3ec bellard
                            /* tcp_input will take care of it */
538 f0cbd3ec bellard
                          } else {
539 02d2c54c bellard
                            ret = send(so->s, &ret, 0,0);
540 f0cbd3ec bellard
                            if (ret < 0) {
541 f0cbd3ec bellard
                              /* XXX */
542 f0cbd3ec bellard
                              if (errno == EAGAIN || errno == EWOULDBLOCK ||
543 f0cbd3ec bellard
                                  errno == EINPROGRESS || errno == ENOTCONN)
544 f0cbd3ec bellard
                                continue;
545 f0cbd3ec bellard
                              /* else failed */
546 f932b6ce Jan Kiszka
                              so->so_state &= SS_PERSISTENT_MASK;
547 f932b6ce Jan Kiszka
                              so->so_state |= SS_NOFDREF;
548 f0cbd3ec bellard
                            } else
549 f0cbd3ec bellard
                              so->so_state &= ~SS_ISFCONNECTING;
550 3b46e624 ths
551 f0cbd3ec bellard
                          }
552 f0cbd3ec bellard
                          tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
553 f0cbd3ec bellard
                        } /* SS_ISFCONNECTING */
554 f0cbd3ec bellard
#endif
555 f0cbd3ec bellard
                }
556 3b46e624 ths
557 f0cbd3ec bellard
                /*
558 f0cbd3ec bellard
                 * Now UDP sockets.
559 f0cbd3ec bellard
                 * Incoming packets are sent straight away, they're not buffered.
560 f0cbd3ec bellard
                 * Incoming UDP data isn't buffered either.
561 f0cbd3ec bellard
                 */
562 460fec67 Jan Kiszka
                for (so = slirp->udb.so_next; so != &slirp->udb;
563 460fec67 Jan Kiszka
                     so = so_next) {
564 f0cbd3ec bellard
                        so_next = so->so_next;
565 3b46e624 ths
566 f0cbd3ec bellard
                        if (so->s != -1 && FD_ISSET(so->s, readfds)) {
567 f0cbd3ec bellard
                            sorecvfrom(so);
568 f0cbd3ec bellard
                        }
569 f0cbd3ec bellard
                }
570 e6d43cfb Jan Kiszka
571 e6d43cfb Jan Kiszka
                /*
572 e6d43cfb Jan Kiszka
                 * Check incoming ICMP relies.
573 e6d43cfb Jan Kiszka
                 */
574 e6d43cfb Jan Kiszka
                for (so = slirp->icmp.so_next; so != &slirp->icmp;
575 e6d43cfb Jan Kiszka
                     so = so_next) {
576 e6d43cfb Jan Kiszka
                     so_next = so->so_next;
577 e6d43cfb Jan Kiszka
578 e6d43cfb Jan Kiszka
                    if (so->s != -1 && FD_ISSET(so->s, readfds)) {
579 e6d43cfb Jan Kiszka
                        icmp_receive(so);
580 e6d43cfb Jan Kiszka
                    }
581 e6d43cfb Jan Kiszka
                }
582 f0cbd3ec bellard
        }
583 5fafdf24 ths
584 f0cbd3ec bellard
        /*
585 f0cbd3ec bellard
         * See if we can start outputting
586 f0cbd3ec bellard
         */
587 460fec67 Jan Kiszka
        if (slirp->if_queued) {
588 460fec67 Jan Kiszka
            if_start(slirp);
589 460fec67 Jan Kiszka
        }
590 b1c99fcd Jan Kiszka
    }
591 02d2c54c bellard
592 02d2c54c bellard
        /* clear global file descriptor sets.
593 02d2c54c bellard
         * these reside on the stack in vl.c
594 02d2c54c bellard
         * so they're unusable if we're not in
595 02d2c54c bellard
         * slirp_select_fill or slirp_select_poll.
596 02d2c54c bellard
         */
597 02d2c54c bellard
         global_readfds = NULL;
598 02d2c54c bellard
         global_writefds = NULL;
599 02d2c54c bellard
         global_xfds = NULL;
600 f0cbd3ec bellard
}
601 f0cbd3ec bellard
602 460fec67 Jan Kiszka
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
603 f0cbd3ec bellard
{
604 f0cbd3ec bellard
    struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
605 dbf3c4b4 Hervรฉ Poussineau
    uint8_t arp_reply[max(ETH_HLEN + sizeof(struct arphdr), 64)];
606 f0cbd3ec bellard
    struct ethhdr *reh = (struct ethhdr *)arp_reply;
607 f0cbd3ec bellard
    struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
608 f0cbd3ec bellard
    int ar_op;
609 a3d4af03 bellard
    struct ex_list *ex_ptr;
610 f0cbd3ec bellard
611 f0cbd3ec bellard
    ar_op = ntohs(ah->ar_op);
612 f0cbd3ec bellard
    switch(ar_op) {
613 f0cbd3ec bellard
    case ARPOP_REQUEST:
614 1a0ca1e1 Fabien Chouteau
        if (ah->ar_tip == ah->ar_sip) {
615 1a0ca1e1 Fabien Chouteau
            /* Gratuitous ARP */
616 1a0ca1e1 Fabien Chouteau
            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
617 1a0ca1e1 Fabien Chouteau
            return;
618 1a0ca1e1 Fabien Chouteau
        }
619 1a0ca1e1 Fabien Chouteau
620 460fec67 Jan Kiszka
        if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) ==
621 460fec67 Jan Kiszka
            slirp->vnetwork_addr.s_addr) {
622 460fec67 Jan Kiszka
            if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
623 460fec67 Jan Kiszka
                ah->ar_tip == slirp->vhost_addr.s_addr)
624 a3d4af03 bellard
                goto arp_ok;
625 460fec67 Jan Kiszka
            for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
626 a13a4126 Jan Kiszka
                if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
627 a3d4af03 bellard
                    goto arp_ok;
628 a3d4af03 bellard
            }
629 a3d4af03 bellard
            return;
630 a3d4af03 bellard
        arp_ok:
631 dbf3c4b4 Hervรฉ Poussineau
            memset(arp_reply, 0, sizeof(arp_reply));
632 1a0ca1e1 Fabien Chouteau
633 1a0ca1e1 Fabien Chouteau
            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
634 f0cbd3ec bellard
635 f0cbd3ec bellard
            /* ARP request for alias/dns mac address */
636 f0cbd3ec bellard
            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
637 a13a4126 Jan Kiszka
            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
638 a13a4126 Jan Kiszka
            memcpy(&reh->h_source[2], &ah->ar_tip, 4);
639 f0cbd3ec bellard
            reh->h_proto = htons(ETH_P_ARP);
640 f0cbd3ec bellard
641 f0cbd3ec bellard
            rah->ar_hrd = htons(1);
642 f0cbd3ec bellard
            rah->ar_pro = htons(ETH_P_IP);
643 f0cbd3ec bellard
            rah->ar_hln = ETH_ALEN;
644 f0cbd3ec bellard
            rah->ar_pln = 4;
645 f0cbd3ec bellard
            rah->ar_op = htons(ARPOP_REPLY);
646 f0cbd3ec bellard
            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
647 a13a4126 Jan Kiszka
            rah->ar_sip = ah->ar_tip;
648 f0cbd3ec bellard
            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
649 a13a4126 Jan Kiszka
            rah->ar_tip = ah->ar_sip;
650 9f8bd042 Jan Kiszka
            slirp_output(slirp->opaque, arp_reply, sizeof(arp_reply));
651 f0cbd3ec bellard
        }
652 f0cbd3ec bellard
        break;
653 de806f07 bellard
    case ARPOP_REPLY:
654 1a0ca1e1 Fabien Chouteau
        arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
655 de806f07 bellard
        break;
656 f0cbd3ec bellard
    default:
657 f0cbd3ec bellard
        break;
658 f0cbd3ec bellard
    }
659 f0cbd3ec bellard
}
660 f0cbd3ec bellard
661 9f8bd042 Jan Kiszka
void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
662 f0cbd3ec bellard
{
663 f0cbd3ec bellard
    struct mbuf *m;
664 f0cbd3ec bellard
    int proto;
665 f0cbd3ec bellard
666 f0cbd3ec bellard
    if (pkt_len < ETH_HLEN)
667 f0cbd3ec bellard
        return;
668 3b46e624 ths
669 f0cbd3ec bellard
    proto = ntohs(*(uint16_t *)(pkt + 12));
670 f0cbd3ec bellard
    switch(proto) {
671 f0cbd3ec bellard
    case ETH_P_ARP:
672 460fec67 Jan Kiszka
        arp_input(slirp, pkt, pkt_len);
673 f0cbd3ec bellard
        break;
674 f0cbd3ec bellard
    case ETH_P_IP:
675 460fec67 Jan Kiszka
        m = m_get(slirp);
676 f0cbd3ec bellard
        if (!m)
677 f0cbd3ec bellard
            return;
678 38f3e7c2 bellard
        /* Note: we add to align the IP header */
679 e8e880a7 aurel32
        if (M_FREEROOM(m) < pkt_len + 2) {
680 e8e880a7 aurel32
            m_inc(m, pkt_len + 2);
681 e8e880a7 aurel32
        }
682 38f3e7c2 bellard
        m->m_len = pkt_len + 2;
683 38f3e7c2 bellard
        memcpy(m->m_data + 2, pkt, pkt_len);
684 f0cbd3ec bellard
685 38f3e7c2 bellard
        m->m_data += 2 + ETH_HLEN;
686 38f3e7c2 bellard
        m->m_len -= 2 + ETH_HLEN;
687 f0cbd3ec bellard
688 f0cbd3ec bellard
        ip_input(m);
689 f0cbd3ec bellard
        break;
690 f0cbd3ec bellard
    default:
691 f0cbd3ec bellard
        break;
692 f0cbd3ec bellard
    }
693 f0cbd3ec bellard
}
694 f0cbd3ec bellard
695 1ab74cea Fabien Chouteau
/* Output the IP packet to the ethernet device. Returns 0 if the packet must be
696 1ab74cea Fabien Chouteau
 * re-queued.
697 1ab74cea Fabien Chouteau
 */
698 1ab74cea Fabien Chouteau
int if_encap(Slirp *slirp, struct mbuf *ifm)
699 f0cbd3ec bellard
{
700 f0cbd3ec bellard
    uint8_t buf[1600];
701 f0cbd3ec bellard
    struct ethhdr *eh = (struct ethhdr *)buf;
702 1a0ca1e1 Fabien Chouteau
    uint8_t ethaddr[ETH_ALEN];
703 1ab74cea Fabien Chouteau
    const struct ip *iph = (const struct ip *)ifm->m_data;
704 f0cbd3ec bellard
705 1ab74cea Fabien Chouteau
    if (ifm->m_len + ETH_HLEN > sizeof(buf)) {
706 1ab74cea Fabien Chouteau
        return 1;
707 1ab74cea Fabien Chouteau
    }
708 1a0ca1e1 Fabien Chouteau
709 1a0ca1e1 Fabien Chouteau
    if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
710 de806f07 bellard
        uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
711 de806f07 bellard
        struct ethhdr *reh = (struct ethhdr *)arp_req;
712 de806f07 bellard
        struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
713 de806f07 bellard
714 1ab74cea Fabien Chouteau
        if (!ifm->arp_requested) {
715 1ab74cea Fabien Chouteau
            /* If the client addr is not known, send an ARP request */
716 1ab74cea Fabien Chouteau
            memset(reh->h_dest, 0xff, ETH_ALEN);
717 1ab74cea Fabien Chouteau
            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
718 1ab74cea Fabien Chouteau
            memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
719 1ab74cea Fabien Chouteau
            reh->h_proto = htons(ETH_P_ARP);
720 1ab74cea Fabien Chouteau
            rah->ar_hrd = htons(1);
721 1ab74cea Fabien Chouteau
            rah->ar_pro = htons(ETH_P_IP);
722 1ab74cea Fabien Chouteau
            rah->ar_hln = ETH_ALEN;
723 1ab74cea Fabien Chouteau
            rah->ar_pln = 4;
724 1ab74cea Fabien Chouteau
            rah->ar_op = htons(ARPOP_REQUEST);
725 1ab74cea Fabien Chouteau
726 1ab74cea Fabien Chouteau
            /* source hw addr */
727 1ab74cea Fabien Chouteau
            memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
728 1ab74cea Fabien Chouteau
            memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
729 1ab74cea Fabien Chouteau
730 1ab74cea Fabien Chouteau
            /* source IP */
731 1ab74cea Fabien Chouteau
            rah->ar_sip = slirp->vhost_addr.s_addr;
732 1ab74cea Fabien Chouteau
733 1ab74cea Fabien Chouteau
            /* target hw addr (none) */
734 1ab74cea Fabien Chouteau
            memset(rah->ar_tha, 0, ETH_ALEN);
735 1ab74cea Fabien Chouteau
736 1ab74cea Fabien Chouteau
            /* target IP */
737 1ab74cea Fabien Chouteau
            rah->ar_tip = iph->ip_dst.s_addr;
738 1ab74cea Fabien Chouteau
            slirp->client_ipaddr = iph->ip_dst;
739 1ab74cea Fabien Chouteau
            slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
740 1ab74cea Fabien Chouteau
            ifm->arp_requested = true;
741 e3a110b5 Jan Kiszka
742 e3a110b5 Jan Kiszka
            /* Expire request and drop outgoing packet after 1 second */
743 e3a110b5 Jan Kiszka
            ifm->expiration_date = qemu_get_clock_ns(rt_clock) + 1000000000ULL;
744 1ab74cea Fabien Chouteau
        }
745 1ab74cea Fabien Chouteau
        return 0;
746 de806f07 bellard
    } else {
747 1a0ca1e1 Fabien Chouteau
        memcpy(eh->h_dest, ethaddr, ETH_ALEN);
748 a13a4126 Jan Kiszka
        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
749 de806f07 bellard
        /* XXX: not correct */
750 460fec67 Jan Kiszka
        memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
751 de806f07 bellard
        eh->h_proto = htons(ETH_P_IP);
752 1ab74cea Fabien Chouteau
        memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
753 1ab74cea Fabien Chouteau
        slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
754 1ab74cea Fabien Chouteau
        return 1;
755 de806f07 bellard
    }
756 f0cbd3ec bellard
}
757 9bf05444 bellard
758 9c12a6f2 Jan Kiszka
/* Drop host forwarding rule, return 0 if found. */
759 9f8bd042 Jan Kiszka
int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
760 9f8bd042 Jan Kiszka
                         int host_port)
761 c1261d8d Alexander Graf
{
762 c1261d8d Alexander Graf
    struct socket *so;
763 460fec67 Jan Kiszka
    struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb);
764 2ad82cf9 Jan Kiszka
    struct sockaddr_in addr;
765 2ad82cf9 Jan Kiszka
    int port = htons(host_port);
766 2ad82cf9 Jan Kiszka
    socklen_t addr_len;
767 c1261d8d Alexander Graf
768 c1261d8d Alexander Graf
    for (so = head->so_next; so != head; so = so->so_next) {
769 2ad82cf9 Jan Kiszka
        addr_len = sizeof(addr);
770 9c12a6f2 Jan Kiszka
        if ((so->so_state & SS_HOSTFWD) &&
771 9c12a6f2 Jan Kiszka
            getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
772 3c6a0580 Jan Kiszka
            addr.sin_addr.s_addr == host_addr.s_addr &&
773 2ad82cf9 Jan Kiszka
            addr.sin_port == port) {
774 c1261d8d Alexander Graf
            close(so->s);
775 c1261d8d Alexander Graf
            sofree(so);
776 9c12a6f2 Jan Kiszka
            return 0;
777 c1261d8d Alexander Graf
        }
778 c1261d8d Alexander Graf
    }
779 c1261d8d Alexander Graf
780 9c12a6f2 Jan Kiszka
    return -1;
781 c1261d8d Alexander Graf
}
782 c1261d8d Alexander Graf
783 9f8bd042 Jan Kiszka
int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
784 9f8bd042 Jan Kiszka
                      int host_port, struct in_addr guest_addr, int guest_port)
785 9bf05444 bellard
{
786 a13a4126 Jan Kiszka
    if (!guest_addr.s_addr) {
787 460fec67 Jan Kiszka
        guest_addr = slirp->vdhcp_startaddr;
788 a13a4126 Jan Kiszka
    }
789 9bf05444 bellard
    if (is_udp) {
790 460fec67 Jan Kiszka
        if (!udp_listen(slirp, host_addr.s_addr, htons(host_port),
791 460fec67 Jan Kiszka
                        guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
792 9bf05444 bellard
            return -1;
793 9bf05444 bellard
    } else {
794 460fec67 Jan Kiszka
        if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port),
795 460fec67 Jan Kiszka
                        guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
796 9bf05444 bellard
            return -1;
797 9bf05444 bellard
    }
798 9bf05444 bellard
    return 0;
799 9bf05444 bellard
}
800 a3d4af03 bellard
801 9f8bd042 Jan Kiszka
int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
802 bb53fc53 Jan Kiszka
                   struct in_addr *guest_addr, int guest_port)
803 a3d4af03 bellard
{
804 bb53fc53 Jan Kiszka
    if (!guest_addr->s_addr) {
805 bb53fc53 Jan Kiszka
        guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
806 460fec67 Jan Kiszka
            (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
807 c92ef6a2 Jan Kiszka
    }
808 bb53fc53 Jan Kiszka
    if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
809 460fec67 Jan Kiszka
        slirp->vnetwork_addr.s_addr ||
810 bb53fc53 Jan Kiszka
        guest_addr->s_addr == slirp->vhost_addr.s_addr ||
811 bb53fc53 Jan Kiszka
        guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
812 a13a4126 Jan Kiszka
        return -1;
813 a13a4126 Jan Kiszka
    }
814 bb53fc53 Jan Kiszka
    return add_exec(&slirp->exec_list, do_pty, (char *)args, *guest_addr,
815 a13a4126 Jan Kiszka
                    htons(guest_port));
816 a3d4af03 bellard
}
817 e1c5a2b3 aliguori
818 e1c5a2b3 aliguori
ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
819 e1c5a2b3 aliguori
{
820 e1c5a2b3 aliguori
        if (so->s == -1 && so->extra) {
821 e1c5a2b3 aliguori
                qemu_chr_write(so->extra, buf, len);
822 e1c5a2b3 aliguori
                return len;
823 e1c5a2b3 aliguori
        }
824 e1c5a2b3 aliguori
825 e1c5a2b3 aliguori
        return send(so->s, buf, len, flags);
826 e1c5a2b3 aliguori
}
827 e1c5a2b3 aliguori
828 a13a4126 Jan Kiszka
static struct socket *
829 460fec67 Jan Kiszka
slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port)
830 e1c5a2b3 aliguori
{
831 a13a4126 Jan Kiszka
    struct socket *so;
832 e1c5a2b3 aliguori
833 460fec67 Jan Kiszka
    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
834 a13a4126 Jan Kiszka
        if (so->so_faddr.s_addr == guest_addr.s_addr &&
835 a13a4126 Jan Kiszka
            htons(so->so_fport) == guest_port) {
836 a13a4126 Jan Kiszka
            return so;
837 a13a4126 Jan Kiszka
        }
838 a13a4126 Jan Kiszka
    }
839 a13a4126 Jan Kiszka
    return NULL;
840 e1c5a2b3 aliguori
}
841 e1c5a2b3 aliguori
842 9f8bd042 Jan Kiszka
size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
843 9f8bd042 Jan Kiszka
                             int guest_port)
844 e1c5a2b3 aliguori
{
845 e1c5a2b3 aliguori
        struct iovec iov[2];
846 e1c5a2b3 aliguori
        struct socket *so;
847 e1c5a2b3 aliguori
848 460fec67 Jan Kiszka
        so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
849 e1c5a2b3 aliguori
850 e1c5a2b3 aliguori
        if (!so || so->so_state & SS_NOFDREF)
851 e1c5a2b3 aliguori
                return 0;
852 e1c5a2b3 aliguori
853 e1c5a2b3 aliguori
        if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2))
854 e1c5a2b3 aliguori
                return 0;
855 e1c5a2b3 aliguori
856 e1c5a2b3 aliguori
        return sopreprbuf(so, iov, NULL);
857 e1c5a2b3 aliguori
}
858 e1c5a2b3 aliguori
859 9f8bd042 Jan Kiszka
void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
860 c92ef6a2 Jan Kiszka
                       const uint8_t *buf, int size)
861 e1c5a2b3 aliguori
{
862 e1c5a2b3 aliguori
    int ret;
863 460fec67 Jan Kiszka
    struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
864 a13a4126 Jan Kiszka
865 e1c5a2b3 aliguori
    if (!so)
866 e1c5a2b3 aliguori
        return;
867 e1c5a2b3 aliguori
868 0580ac91 blueswir1
    ret = soreadbuf(so, (const char *)buf, size);
869 e1c5a2b3 aliguori
870 e1c5a2b3 aliguori
    if (ret > 0)
871 e1c5a2b3 aliguori
        tcp_output(sototcpcb(so));
872 e1c5a2b3 aliguori
}
873 062e5527 aliguori
874 062e5527 aliguori
static void slirp_tcp_save(QEMUFile *f, struct tcpcb *tp)
875 062e5527 aliguori
{
876 062e5527 aliguori
    int i;
877 062e5527 aliguori
878 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_state);
879 062e5527 aliguori
    for (i = 0; i < TCPT_NTIMERS; i++)
880 062e5527 aliguori
        qemu_put_sbe16(f, tp->t_timer[i]);
881 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_rxtshift);
882 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_rxtcur);
883 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_dupacks);
884 062e5527 aliguori
    qemu_put_be16(f, tp->t_maxseg);
885 062e5527 aliguori
    qemu_put_sbyte(f, tp->t_force);
886 062e5527 aliguori
    qemu_put_be16(f, tp->t_flags);
887 062e5527 aliguori
    qemu_put_be32(f, tp->snd_una);
888 062e5527 aliguori
    qemu_put_be32(f, tp->snd_nxt);
889 062e5527 aliguori
    qemu_put_be32(f, tp->snd_up);
890 062e5527 aliguori
    qemu_put_be32(f, tp->snd_wl1);
891 062e5527 aliguori
    qemu_put_be32(f, tp->snd_wl2);
892 062e5527 aliguori
    qemu_put_be32(f, tp->iss);
893 062e5527 aliguori
    qemu_put_be32(f, tp->snd_wnd);
894 062e5527 aliguori
    qemu_put_be32(f, tp->rcv_wnd);
895 062e5527 aliguori
    qemu_put_be32(f, tp->rcv_nxt);
896 062e5527 aliguori
    qemu_put_be32(f, tp->rcv_up);
897 062e5527 aliguori
    qemu_put_be32(f, tp->irs);
898 062e5527 aliguori
    qemu_put_be32(f, tp->rcv_adv);
899 062e5527 aliguori
    qemu_put_be32(f, tp->snd_max);
900 062e5527 aliguori
    qemu_put_be32(f, tp->snd_cwnd);
901 062e5527 aliguori
    qemu_put_be32(f, tp->snd_ssthresh);
902 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_idle);
903 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_rtt);
904 062e5527 aliguori
    qemu_put_be32(f, tp->t_rtseq);
905 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_srtt);
906 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_rttvar);
907 062e5527 aliguori
    qemu_put_be16(f, tp->t_rttmin);
908 062e5527 aliguori
    qemu_put_be32(f, tp->max_sndwnd);
909 062e5527 aliguori
    qemu_put_byte(f, tp->t_oobflags);
910 062e5527 aliguori
    qemu_put_byte(f, tp->t_iobc);
911 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_softerror);
912 062e5527 aliguori
    qemu_put_byte(f, tp->snd_scale);
913 062e5527 aliguori
    qemu_put_byte(f, tp->rcv_scale);
914 062e5527 aliguori
    qemu_put_byte(f, tp->request_r_scale);
915 062e5527 aliguori
    qemu_put_byte(f, tp->requested_s_scale);
916 062e5527 aliguori
    qemu_put_be32(f, tp->ts_recent);
917 062e5527 aliguori
    qemu_put_be32(f, tp->ts_recent_age);
918 062e5527 aliguori
    qemu_put_be32(f, tp->last_ack_sent);
919 062e5527 aliguori
}
920 062e5527 aliguori
921 062e5527 aliguori
static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf)
922 062e5527 aliguori
{
923 062e5527 aliguori
    uint32_t off;
924 062e5527 aliguori
925 062e5527 aliguori
    qemu_put_be32(f, sbuf->sb_cc);
926 062e5527 aliguori
    qemu_put_be32(f, sbuf->sb_datalen);
927 062e5527 aliguori
    off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data);
928 062e5527 aliguori
    qemu_put_sbe32(f, off);
929 062e5527 aliguori
    off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data);
930 062e5527 aliguori
    qemu_put_sbe32(f, off);
931 062e5527 aliguori
    qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
932 062e5527 aliguori
}
933 062e5527 aliguori
934 062e5527 aliguori
static void slirp_socket_save(QEMUFile *f, struct socket *so)
935 062e5527 aliguori
{
936 062e5527 aliguori
    qemu_put_be32(f, so->so_urgc);
937 062e5527 aliguori
    qemu_put_be32(f, so->so_faddr.s_addr);
938 062e5527 aliguori
    qemu_put_be32(f, so->so_laddr.s_addr);
939 062e5527 aliguori
    qemu_put_be16(f, so->so_fport);
940 062e5527 aliguori
    qemu_put_be16(f, so->so_lport);
941 062e5527 aliguori
    qemu_put_byte(f, so->so_iptos);
942 062e5527 aliguori
    qemu_put_byte(f, so->so_emu);
943 062e5527 aliguori
    qemu_put_byte(f, so->so_type);
944 062e5527 aliguori
    qemu_put_be32(f, so->so_state);
945 062e5527 aliguori
    slirp_sbuf_save(f, &so->so_rcv);
946 062e5527 aliguori
    slirp_sbuf_save(f, &so->so_snd);
947 062e5527 aliguori
    slirp_tcp_save(f, so->so_tcpcb);
948 062e5527 aliguori
}
949 062e5527 aliguori
950 0a1f851e Jan Kiszka
static void slirp_bootp_save(QEMUFile *f, Slirp *slirp)
951 0a1f851e Jan Kiszka
{
952 0a1f851e Jan Kiszka
    int i;
953 0a1f851e Jan Kiszka
954 0a1f851e Jan Kiszka
    for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
955 0a1f851e Jan Kiszka
        qemu_put_be16(f, slirp->bootp_clients[i].allocated);
956 0a1f851e Jan Kiszka
        qemu_put_buffer(f, slirp->bootp_clients[i].macaddr, 6);
957 0a1f851e Jan Kiszka
    }
958 0a1f851e Jan Kiszka
}
959 0a1f851e Jan Kiszka
960 062e5527 aliguori
static void slirp_state_save(QEMUFile *f, void *opaque)
961 062e5527 aliguori
{
962 460fec67 Jan Kiszka
    Slirp *slirp = opaque;
963 062e5527 aliguori
    struct ex_list *ex_ptr;
964 062e5527 aliguori
965 460fec67 Jan Kiszka
    for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
966 062e5527 aliguori
        if (ex_ptr->ex_pty == 3) {
967 062e5527 aliguori
            struct socket *so;
968 460fec67 Jan Kiszka
            so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
969 460fec67 Jan Kiszka
                                       ntohs(ex_ptr->ex_fport));
970 062e5527 aliguori
            if (!so)
971 062e5527 aliguori
                continue;
972 062e5527 aliguori
973 062e5527 aliguori
            qemu_put_byte(f, 42);
974 062e5527 aliguori
            slirp_socket_save(f, so);
975 062e5527 aliguori
        }
976 062e5527 aliguori
    qemu_put_byte(f, 0);
977 285f7a62 Jan Kiszka
978 460fec67 Jan Kiszka
    qemu_put_be16(f, slirp->ip_id);
979 0a1f851e Jan Kiszka
980 0a1f851e Jan Kiszka
    slirp_bootp_save(f, slirp);
981 062e5527 aliguori
}
982 062e5527 aliguori
983 062e5527 aliguori
static void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp)
984 062e5527 aliguori
{
985 062e5527 aliguori
    int i;
986 062e5527 aliguori
987 062e5527 aliguori
    tp->t_state = qemu_get_sbe16(f);
988 062e5527 aliguori
    for (i = 0; i < TCPT_NTIMERS; i++)
989 062e5527 aliguori
        tp->t_timer[i] = qemu_get_sbe16(f);
990 062e5527 aliguori
    tp->t_rxtshift = qemu_get_sbe16(f);
991 062e5527 aliguori
    tp->t_rxtcur = qemu_get_sbe16(f);
992 062e5527 aliguori
    tp->t_dupacks = qemu_get_sbe16(f);
993 062e5527 aliguori
    tp->t_maxseg = qemu_get_be16(f);
994 062e5527 aliguori
    tp->t_force = qemu_get_sbyte(f);
995 062e5527 aliguori
    tp->t_flags = qemu_get_be16(f);
996 062e5527 aliguori
    tp->snd_una = qemu_get_be32(f);
997 062e5527 aliguori
    tp->snd_nxt = qemu_get_be32(f);
998 062e5527 aliguori
    tp->snd_up = qemu_get_be32(f);
999 062e5527 aliguori
    tp->snd_wl1 = qemu_get_be32(f);
1000 062e5527 aliguori
    tp->snd_wl2 = qemu_get_be32(f);
1001 062e5527 aliguori
    tp->iss = qemu_get_be32(f);
1002 062e5527 aliguori
    tp->snd_wnd = qemu_get_be32(f);
1003 062e5527 aliguori
    tp->rcv_wnd = qemu_get_be32(f);
1004 062e5527 aliguori
    tp->rcv_nxt = qemu_get_be32(f);
1005 062e5527 aliguori
    tp->rcv_up = qemu_get_be32(f);
1006 062e5527 aliguori
    tp->irs = qemu_get_be32(f);
1007 062e5527 aliguori
    tp->rcv_adv = qemu_get_be32(f);
1008 062e5527 aliguori
    tp->snd_max = qemu_get_be32(f);
1009 062e5527 aliguori
    tp->snd_cwnd = qemu_get_be32(f);
1010 062e5527 aliguori
    tp->snd_ssthresh = qemu_get_be32(f);
1011 062e5527 aliguori
    tp->t_idle = qemu_get_sbe16(f);
1012 062e5527 aliguori
    tp->t_rtt = qemu_get_sbe16(f);
1013 062e5527 aliguori
    tp->t_rtseq = qemu_get_be32(f);
1014 062e5527 aliguori
    tp->t_srtt = qemu_get_sbe16(f);
1015 062e5527 aliguori
    tp->t_rttvar = qemu_get_sbe16(f);
1016 062e5527 aliguori
    tp->t_rttmin = qemu_get_be16(f);
1017 062e5527 aliguori
    tp->max_sndwnd = qemu_get_be32(f);
1018 062e5527 aliguori
    tp->t_oobflags = qemu_get_byte(f);
1019 062e5527 aliguori
    tp->t_iobc = qemu_get_byte(f);
1020 062e5527 aliguori
    tp->t_softerror = qemu_get_sbe16(f);
1021 062e5527 aliguori
    tp->snd_scale = qemu_get_byte(f);
1022 062e5527 aliguori
    tp->rcv_scale = qemu_get_byte(f);
1023 062e5527 aliguori
    tp->request_r_scale = qemu_get_byte(f);
1024 062e5527 aliguori
    tp->requested_s_scale = qemu_get_byte(f);
1025 062e5527 aliguori
    tp->ts_recent = qemu_get_be32(f);
1026 062e5527 aliguori
    tp->ts_recent_age = qemu_get_be32(f);
1027 062e5527 aliguori
    tp->last_ack_sent = qemu_get_be32(f);
1028 062e5527 aliguori
    tcp_template(tp);
1029 062e5527 aliguori
}
1030 062e5527 aliguori
1031 062e5527 aliguori
static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf)
1032 062e5527 aliguori
{
1033 062e5527 aliguori
    uint32_t off, sb_cc, sb_datalen;
1034 062e5527 aliguori
1035 062e5527 aliguori
    sb_cc = qemu_get_be32(f);
1036 062e5527 aliguori
    sb_datalen = qemu_get_be32(f);
1037 062e5527 aliguori
1038 062e5527 aliguori
    sbreserve(sbuf, sb_datalen);
1039 062e5527 aliguori
1040 062e5527 aliguori
    if (sbuf->sb_datalen != sb_datalen)
1041 062e5527 aliguori
        return -ENOMEM;
1042 062e5527 aliguori
1043 062e5527 aliguori
    sbuf->sb_cc = sb_cc;
1044 062e5527 aliguori
1045 062e5527 aliguori
    off = qemu_get_sbe32(f);
1046 062e5527 aliguori
    sbuf->sb_wptr = sbuf->sb_data + off;
1047 062e5527 aliguori
    off = qemu_get_sbe32(f);
1048 062e5527 aliguori
    sbuf->sb_rptr = sbuf->sb_data + off;
1049 062e5527 aliguori
    qemu_get_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
1050 062e5527 aliguori
1051 062e5527 aliguori
    return 0;
1052 062e5527 aliguori
}
1053 062e5527 aliguori
1054 062e5527 aliguori
static int slirp_socket_load(QEMUFile *f, struct socket *so)
1055 062e5527 aliguori
{
1056 062e5527 aliguori
    if (tcp_attach(so) < 0)
1057 062e5527 aliguori
        return -ENOMEM;
1058 062e5527 aliguori
1059 062e5527 aliguori
    so->so_urgc = qemu_get_be32(f);
1060 062e5527 aliguori
    so->so_faddr.s_addr = qemu_get_be32(f);
1061 062e5527 aliguori
    so->so_laddr.s_addr = qemu_get_be32(f);
1062 062e5527 aliguori
    so->so_fport = qemu_get_be16(f);
1063 062e5527 aliguori
    so->so_lport = qemu_get_be16(f);
1064 062e5527 aliguori
    so->so_iptos = qemu_get_byte(f);
1065 062e5527 aliguori
    so->so_emu = qemu_get_byte(f);
1066 062e5527 aliguori
    so->so_type = qemu_get_byte(f);
1067 062e5527 aliguori
    so->so_state = qemu_get_be32(f);
1068 062e5527 aliguori
    if (slirp_sbuf_load(f, &so->so_rcv) < 0)
1069 062e5527 aliguori
        return -ENOMEM;
1070 062e5527 aliguori
    if (slirp_sbuf_load(f, &so->so_snd) < 0)
1071 062e5527 aliguori
        return -ENOMEM;
1072 062e5527 aliguori
    slirp_tcp_load(f, so->so_tcpcb);
1073 062e5527 aliguori
1074 062e5527 aliguori
    return 0;
1075 062e5527 aliguori
}
1076 062e5527 aliguori
1077 0a1f851e Jan Kiszka
static void slirp_bootp_load(QEMUFile *f, Slirp *slirp)
1078 0a1f851e Jan Kiszka
{
1079 0a1f851e Jan Kiszka
    int i;
1080 0a1f851e Jan Kiszka
1081 0a1f851e Jan Kiszka
    for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
1082 0a1f851e Jan Kiszka
        slirp->bootp_clients[i].allocated = qemu_get_be16(f);
1083 0a1f851e Jan Kiszka
        qemu_get_buffer(f, slirp->bootp_clients[i].macaddr, 6);
1084 0a1f851e Jan Kiszka
    }
1085 0a1f851e Jan Kiszka
}
1086 0a1f851e Jan Kiszka
1087 062e5527 aliguori
static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
1088 062e5527 aliguori
{
1089 460fec67 Jan Kiszka
    Slirp *slirp = opaque;
1090 062e5527 aliguori
    struct ex_list *ex_ptr;
1091 062e5527 aliguori
1092 b0e04867 Blue Swirl
    while (qemu_get_byte(f)) {
1093 062e5527 aliguori
        int ret;
1094 460fec67 Jan Kiszka
        struct socket *so = socreate(slirp);
1095 062e5527 aliguori
1096 062e5527 aliguori
        if (!so)
1097 062e5527 aliguori
            return -ENOMEM;
1098 062e5527 aliguori
1099 062e5527 aliguori
        ret = slirp_socket_load(f, so);
1100 062e5527 aliguori
1101 062e5527 aliguori
        if (ret < 0)
1102 062e5527 aliguori
            return ret;
1103 062e5527 aliguori
1104 460fec67 Jan Kiszka
        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) !=
1105 460fec67 Jan Kiszka
            slirp->vnetwork_addr.s_addr) {
1106 062e5527 aliguori
            return -EINVAL;
1107 a13a4126 Jan Kiszka
        }
1108 460fec67 Jan Kiszka
        for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
1109 062e5527 aliguori
            if (ex_ptr->ex_pty == 3 &&
1110 a13a4126 Jan Kiszka
                so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
1111 a13a4126 Jan Kiszka
                so->so_fport == ex_ptr->ex_fport) {
1112 062e5527 aliguori
                break;
1113 a13a4126 Jan Kiszka
            }
1114 a13a4126 Jan Kiszka
        }
1115 062e5527 aliguori
        if (!ex_ptr)
1116 062e5527 aliguori
            return -EINVAL;
1117 062e5527 aliguori
1118 0580ac91 blueswir1
        so->extra = (void *)ex_ptr->ex_exec;
1119 062e5527 aliguori
    }
1120 062e5527 aliguori
1121 285f7a62 Jan Kiszka
    if (version_id >= 2) {
1122 460fec67 Jan Kiszka
        slirp->ip_id = qemu_get_be16(f);
1123 285f7a62 Jan Kiszka
    }
1124 285f7a62 Jan Kiszka
1125 0a1f851e Jan Kiszka
    if (version_id >= 3) {
1126 0a1f851e Jan Kiszka
        slirp_bootp_load(f, slirp);
1127 0a1f851e Jan Kiszka
    }
1128 0a1f851e Jan Kiszka
1129 062e5527 aliguori
    return 0;
1130 062e5527 aliguori
}