Statistics
| Branch: | Revision:

root / slirp / slirp.c @ 5b50e790

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