Statistics
| Branch: | Revision:

root / slirp / slirp.c @ e6d43cfb

History | View | Annotate | Download (31.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 9634d903 blueswir1
static const uint8_t special_ethaddr[6] = {
35 a13a4126 Jan Kiszka
    0x52, 0x55, 0x00, 0x00, 0x00, 0x00
36 f0cbd3ec bellard
};
37 f0cbd3ec bellard
38 de806f07 bellard
static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
39 f0cbd3ec bellard
40 f0cbd3ec bellard
/* XXX: suppress those select globals */
41 f0cbd3ec bellard
fd_set *global_readfds, *global_writefds, *global_xfds;
42 f0cbd3ec bellard
43 f1d99bbd Jan Kiszka
u_int curtime;
44 f1d99bbd Jan Kiszka
static u_int time_fasttimo, last_slowtimo;
45 f1d99bbd Jan Kiszka
static int do_slowtimo;
46 f1d99bbd Jan Kiszka
47 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 ad0d8c4c Jan Kiszka
    Slirp *slirp = qemu_mallocz(sizeof(Slirp));
206 460fec67 Jan Kiszka
207 df461894 Jan Kiszka
    slirp_init_once();
208 379ff53d bellard
209 460fec67 Jan Kiszka
    slirp->restricted = restricted;
210 f0cbd3ec bellard
211 460fec67 Jan Kiszka
    if_init(slirp);
212 460fec67 Jan Kiszka
    ip_init(slirp);
213 f0cbd3ec bellard
214 f0cbd3ec bellard
    /* Initialise mbufs *after* setting the MTU */
215 460fec67 Jan Kiszka
    m_init(slirp);
216 f0cbd3ec bellard
217 460fec67 Jan Kiszka
    slirp->vnetwork_addr = vnetwork;
218 460fec67 Jan Kiszka
    slirp->vnetwork_mask = vnetmask;
219 460fec67 Jan Kiszka
    slirp->vhost_addr = vhost;
220 c92ef6a2 Jan Kiszka
    if (vhostname) {
221 460fec67 Jan Kiszka
        pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
222 460fec67 Jan Kiszka
                vhostname);
223 a13a4126 Jan Kiszka
    }
224 ad196a9d Jan Kiszka
    if (tftp_path) {
225 460fec67 Jan Kiszka
        slirp->tftp_prefix = qemu_strdup(tftp_path);
226 ad196a9d Jan Kiszka
    }
227 ad196a9d Jan Kiszka
    if (bootfile) {
228 460fec67 Jan Kiszka
        slirp->bootp_filename = qemu_strdup(bootfile);
229 ad196a9d Jan Kiszka
    }
230 460fec67 Jan Kiszka
    slirp->vdhcp_startaddr = vdhcp_start;
231 460fec67 Jan Kiszka
    slirp->vnameserver_addr = vnameserver;
232 ad196a9d Jan Kiszka
233 9f8bd042 Jan Kiszka
    slirp->opaque = opaque;
234 9f8bd042 Jan Kiszka
235 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 ad0d8c4c Jan Kiszka
    qemu_free(slirp->tftp_prefix);
250 ad0d8c4c Jan Kiszka
    qemu_free(slirp->bootp_filename);
251 ad0d8c4c Jan Kiszka
    qemu_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 02d2c54c bellard
                          ret = recv(so->s, (char *)&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 f0cbd3ec bellard
#define ETH_ALEN 6
603 f0cbd3ec bellard
#define ETH_HLEN 14
604 f0cbd3ec bellard
605 f0cbd3ec bellard
#define ETH_P_IP        0x0800                /* Internet Protocol packet        */
606 f0cbd3ec bellard
#define ETH_P_ARP        0x0806                /* Address Resolution packet        */
607 f0cbd3ec bellard
608 f0cbd3ec bellard
#define        ARPOP_REQUEST        1                /* ARP request                        */
609 f0cbd3ec bellard
#define        ARPOP_REPLY        2                /* ARP reply                        */
610 f0cbd3ec bellard
611 5fafdf24 ths
struct ethhdr
612 f0cbd3ec bellard
{
613 f0cbd3ec bellard
        unsigned char        h_dest[ETH_ALEN];        /* destination eth addr        */
614 f0cbd3ec bellard
        unsigned char        h_source[ETH_ALEN];        /* source ether addr        */
615 f0cbd3ec bellard
        unsigned short        h_proto;                /* packet type ID field        */
616 f0cbd3ec bellard
};
617 f0cbd3ec bellard
618 f0cbd3ec bellard
struct arphdr
619 f0cbd3ec bellard
{
620 f0cbd3ec bellard
        unsigned short        ar_hrd;                /* format of hardware address        */
621 f0cbd3ec bellard
        unsigned short        ar_pro;                /* format of protocol address        */
622 f0cbd3ec bellard
        unsigned char        ar_hln;                /* length of hardware address        */
623 f0cbd3ec bellard
        unsigned char        ar_pln;                /* length of protocol address        */
624 f0cbd3ec bellard
        unsigned short        ar_op;                /* ARP opcode (command)                */
625 f0cbd3ec bellard
626 f0cbd3ec bellard
         /*
627 f0cbd3ec bellard
          *         Ethernet looks like this : This bit is variable sized however...
628 f0cbd3ec bellard
          */
629 f0cbd3ec bellard
        unsigned char                ar_sha[ETH_ALEN];        /* sender hardware address        */
630 a13a4126 Jan Kiszka
        uint32_t                ar_sip;                        /* sender IP address                */
631 f0cbd3ec bellard
        unsigned char                ar_tha[ETH_ALEN];        /* target hardware address        */
632 a13a4126 Jan Kiszka
        uint32_t                ar_tip        ;                /* target IP address                */
633 a13a4126 Jan Kiszka
} __attribute__((packed));
634 f0cbd3ec bellard
635 460fec67 Jan Kiszka
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
636 f0cbd3ec bellard
{
637 f0cbd3ec bellard
    struct ethhdr *eh = (struct ethhdr *)pkt;
638 f0cbd3ec bellard
    struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
639 dbf3c4b4 Hervรฉ Poussineau
    uint8_t arp_reply[max(ETH_HLEN + sizeof(struct arphdr), 64)];
640 f0cbd3ec bellard
    struct ethhdr *reh = (struct ethhdr *)arp_reply;
641 f0cbd3ec bellard
    struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
642 f0cbd3ec bellard
    int ar_op;
643 a3d4af03 bellard
    struct ex_list *ex_ptr;
644 f0cbd3ec bellard
645 f0cbd3ec bellard
    ar_op = ntohs(ah->ar_op);
646 f0cbd3ec bellard
    switch(ar_op) {
647 f0cbd3ec bellard
    case ARPOP_REQUEST:
648 460fec67 Jan Kiszka
        if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) ==
649 460fec67 Jan Kiszka
            slirp->vnetwork_addr.s_addr) {
650 460fec67 Jan Kiszka
            if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
651 460fec67 Jan Kiszka
                ah->ar_tip == slirp->vhost_addr.s_addr)
652 a3d4af03 bellard
                goto arp_ok;
653 460fec67 Jan Kiszka
            for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
654 a13a4126 Jan Kiszka
                if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
655 a3d4af03 bellard
                    goto arp_ok;
656 a3d4af03 bellard
            }
657 a3d4af03 bellard
            return;
658 a3d4af03 bellard
        arp_ok:
659 dbf3c4b4 Hervรฉ Poussineau
            memset(arp_reply, 0, sizeof(arp_reply));
660 f0cbd3ec bellard
            /* XXX: make an ARP request to have the client address */
661 460fec67 Jan Kiszka
            memcpy(slirp->client_ethaddr, eh->h_source, ETH_ALEN);
662 f0cbd3ec bellard
663 f0cbd3ec bellard
            /* ARP request for alias/dns mac address */
664 f0cbd3ec bellard
            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
665 a13a4126 Jan Kiszka
            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
666 a13a4126 Jan Kiszka
            memcpy(&reh->h_source[2], &ah->ar_tip, 4);
667 f0cbd3ec bellard
            reh->h_proto = htons(ETH_P_ARP);
668 f0cbd3ec bellard
669 f0cbd3ec bellard
            rah->ar_hrd = htons(1);
670 f0cbd3ec bellard
            rah->ar_pro = htons(ETH_P_IP);
671 f0cbd3ec bellard
            rah->ar_hln = ETH_ALEN;
672 f0cbd3ec bellard
            rah->ar_pln = 4;
673 f0cbd3ec bellard
            rah->ar_op = htons(ARPOP_REPLY);
674 f0cbd3ec bellard
            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
675 a13a4126 Jan Kiszka
            rah->ar_sip = ah->ar_tip;
676 f0cbd3ec bellard
            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
677 a13a4126 Jan Kiszka
            rah->ar_tip = ah->ar_sip;
678 9f8bd042 Jan Kiszka
            slirp_output(slirp->opaque, arp_reply, sizeof(arp_reply));
679 f0cbd3ec bellard
        }
680 f0cbd3ec bellard
        break;
681 de806f07 bellard
    case ARPOP_REPLY:
682 de806f07 bellard
        /* reply to request of client mac address ? */
683 460fec67 Jan Kiszka
        if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN) &&
684 460fec67 Jan Kiszka
            ah->ar_sip == slirp->client_ipaddr.s_addr) {
685 460fec67 Jan Kiszka
            memcpy(slirp->client_ethaddr, ah->ar_sha, ETH_ALEN);
686 de806f07 bellard
        }
687 de806f07 bellard
        break;
688 f0cbd3ec bellard
    default:
689 f0cbd3ec bellard
        break;
690 f0cbd3ec bellard
    }
691 f0cbd3ec bellard
}
692 f0cbd3ec bellard
693 9f8bd042 Jan Kiszka
void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
694 f0cbd3ec bellard
{
695 f0cbd3ec bellard
    struct mbuf *m;
696 f0cbd3ec bellard
    int proto;
697 f0cbd3ec bellard
698 f0cbd3ec bellard
    if (pkt_len < ETH_HLEN)
699 f0cbd3ec bellard
        return;
700 3b46e624 ths
701 f0cbd3ec bellard
    proto = ntohs(*(uint16_t *)(pkt + 12));
702 f0cbd3ec bellard
    switch(proto) {
703 f0cbd3ec bellard
    case ETH_P_ARP:
704 460fec67 Jan Kiszka
        arp_input(slirp, pkt, pkt_len);
705 f0cbd3ec bellard
        break;
706 f0cbd3ec bellard
    case ETH_P_IP:
707 460fec67 Jan Kiszka
        m = m_get(slirp);
708 f0cbd3ec bellard
        if (!m)
709 f0cbd3ec bellard
            return;
710 38f3e7c2 bellard
        /* Note: we add to align the IP header */
711 e8e880a7 aurel32
        if (M_FREEROOM(m) < pkt_len + 2) {
712 e8e880a7 aurel32
            m_inc(m, pkt_len + 2);
713 e8e880a7 aurel32
        }
714 38f3e7c2 bellard
        m->m_len = pkt_len + 2;
715 38f3e7c2 bellard
        memcpy(m->m_data + 2, pkt, pkt_len);
716 f0cbd3ec bellard
717 38f3e7c2 bellard
        m->m_data += 2 + ETH_HLEN;
718 38f3e7c2 bellard
        m->m_len -= 2 + ETH_HLEN;
719 f0cbd3ec bellard
720 f0cbd3ec bellard
        ip_input(m);
721 f0cbd3ec bellard
        break;
722 f0cbd3ec bellard
    default:
723 f0cbd3ec bellard
        break;
724 f0cbd3ec bellard
    }
725 f0cbd3ec bellard
}
726 f0cbd3ec bellard
727 f0cbd3ec bellard
/* output the IP packet to the ethernet device */
728 460fec67 Jan Kiszka
void if_encap(Slirp *slirp, const uint8_t *ip_data, int ip_data_len)
729 f0cbd3ec bellard
{
730 f0cbd3ec bellard
    uint8_t buf[1600];
731 f0cbd3ec bellard
    struct ethhdr *eh = (struct ethhdr *)buf;
732 f0cbd3ec bellard
733 f0cbd3ec bellard
    if (ip_data_len + ETH_HLEN > sizeof(buf))
734 f0cbd3ec bellard
        return;
735 de806f07 bellard
    
736 460fec67 Jan Kiszka
    if (!memcmp(slirp->client_ethaddr, zero_ethaddr, ETH_ALEN)) {
737 de806f07 bellard
        uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
738 de806f07 bellard
        struct ethhdr *reh = (struct ethhdr *)arp_req;
739 de806f07 bellard
        struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
740 de806f07 bellard
        const struct ip *iph = (const struct ip *)ip_data;
741 de806f07 bellard
742 de806f07 bellard
        /* If the client addr is not known, there is no point in
743 de806f07 bellard
           sending the packet to it. Normally the sender should have
744 de806f07 bellard
           done an ARP request to get its MAC address. Here we do it
745 de806f07 bellard
           in place of sending the packet and we hope that the sender
746 de806f07 bellard
           will retry sending its packet. */
747 de806f07 bellard
        memset(reh->h_dest, 0xff, ETH_ALEN);
748 a13a4126 Jan Kiszka
        memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
749 460fec67 Jan Kiszka
        memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
750 de806f07 bellard
        reh->h_proto = htons(ETH_P_ARP);
751 de806f07 bellard
        rah->ar_hrd = htons(1);
752 de806f07 bellard
        rah->ar_pro = htons(ETH_P_IP);
753 de806f07 bellard
        rah->ar_hln = ETH_ALEN;
754 de806f07 bellard
        rah->ar_pln = 4;
755 de806f07 bellard
        rah->ar_op = htons(ARPOP_REQUEST);
756 de806f07 bellard
        /* source hw addr */
757 a13a4126 Jan Kiszka
        memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
758 460fec67 Jan Kiszka
        memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
759 de806f07 bellard
        /* source IP */
760 460fec67 Jan Kiszka
        rah->ar_sip = slirp->vhost_addr.s_addr;
761 de806f07 bellard
        /* target hw addr (none) */
762 de806f07 bellard
        memset(rah->ar_tha, 0, ETH_ALEN);
763 de806f07 bellard
        /* target IP */
764 a13a4126 Jan Kiszka
        rah->ar_tip = iph->ip_dst.s_addr;
765 460fec67 Jan Kiszka
        slirp->client_ipaddr = iph->ip_dst;
766 9f8bd042 Jan Kiszka
        slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
767 de806f07 bellard
    } else {
768 460fec67 Jan Kiszka
        memcpy(eh->h_dest, slirp->client_ethaddr, ETH_ALEN);
769 a13a4126 Jan Kiszka
        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
770 de806f07 bellard
        /* XXX: not correct */
771 460fec67 Jan Kiszka
        memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
772 de806f07 bellard
        eh->h_proto = htons(ETH_P_IP);
773 de806f07 bellard
        memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
774 9f8bd042 Jan Kiszka
        slirp_output(slirp->opaque, buf, ip_data_len + ETH_HLEN);
775 de806f07 bellard
    }
776 f0cbd3ec bellard
}
777 9bf05444 bellard
778 9c12a6f2 Jan Kiszka
/* Drop host forwarding rule, return 0 if found. */
779 9f8bd042 Jan Kiszka
int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
780 9f8bd042 Jan Kiszka
                         int host_port)
781 c1261d8d Alexander Graf
{
782 c1261d8d Alexander Graf
    struct socket *so;
783 460fec67 Jan Kiszka
    struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb);
784 2ad82cf9 Jan Kiszka
    struct sockaddr_in addr;
785 2ad82cf9 Jan Kiszka
    int port = htons(host_port);
786 2ad82cf9 Jan Kiszka
    socklen_t addr_len;
787 c1261d8d Alexander Graf
788 c1261d8d Alexander Graf
    for (so = head->so_next; so != head; so = so->so_next) {
789 2ad82cf9 Jan Kiszka
        addr_len = sizeof(addr);
790 9c12a6f2 Jan Kiszka
        if ((so->so_state & SS_HOSTFWD) &&
791 9c12a6f2 Jan Kiszka
            getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
792 3c6a0580 Jan Kiszka
            addr.sin_addr.s_addr == host_addr.s_addr &&
793 2ad82cf9 Jan Kiszka
            addr.sin_port == port) {
794 c1261d8d Alexander Graf
            close(so->s);
795 c1261d8d Alexander Graf
            sofree(so);
796 9c12a6f2 Jan Kiszka
            return 0;
797 c1261d8d Alexander Graf
        }
798 c1261d8d Alexander Graf
    }
799 c1261d8d Alexander Graf
800 9c12a6f2 Jan Kiszka
    return -1;
801 c1261d8d Alexander Graf
}
802 c1261d8d Alexander Graf
803 9f8bd042 Jan Kiszka
int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
804 9f8bd042 Jan Kiszka
                      int host_port, struct in_addr guest_addr, int guest_port)
805 9bf05444 bellard
{
806 a13a4126 Jan Kiszka
    if (!guest_addr.s_addr) {
807 460fec67 Jan Kiszka
        guest_addr = slirp->vdhcp_startaddr;
808 a13a4126 Jan Kiszka
    }
809 9bf05444 bellard
    if (is_udp) {
810 460fec67 Jan Kiszka
        if (!udp_listen(slirp, host_addr.s_addr, htons(host_port),
811 460fec67 Jan Kiszka
                        guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
812 9bf05444 bellard
            return -1;
813 9bf05444 bellard
    } else {
814 460fec67 Jan Kiszka
        if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port),
815 460fec67 Jan Kiszka
                        guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
816 9bf05444 bellard
            return -1;
817 9bf05444 bellard
    }
818 9bf05444 bellard
    return 0;
819 9bf05444 bellard
}
820 a3d4af03 bellard
821 9f8bd042 Jan Kiszka
int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
822 bb53fc53 Jan Kiszka
                   struct in_addr *guest_addr, int guest_port)
823 a3d4af03 bellard
{
824 bb53fc53 Jan Kiszka
    if (!guest_addr->s_addr) {
825 bb53fc53 Jan Kiszka
        guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
826 460fec67 Jan Kiszka
            (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
827 c92ef6a2 Jan Kiszka
    }
828 bb53fc53 Jan Kiszka
    if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
829 460fec67 Jan Kiszka
        slirp->vnetwork_addr.s_addr ||
830 bb53fc53 Jan Kiszka
        guest_addr->s_addr == slirp->vhost_addr.s_addr ||
831 bb53fc53 Jan Kiszka
        guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
832 a13a4126 Jan Kiszka
        return -1;
833 a13a4126 Jan Kiszka
    }
834 bb53fc53 Jan Kiszka
    return add_exec(&slirp->exec_list, do_pty, (char *)args, *guest_addr,
835 a13a4126 Jan Kiszka
                    htons(guest_port));
836 a3d4af03 bellard
}
837 e1c5a2b3 aliguori
838 e1c5a2b3 aliguori
ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
839 e1c5a2b3 aliguori
{
840 e1c5a2b3 aliguori
        if (so->s == -1 && so->extra) {
841 e1c5a2b3 aliguori
                qemu_chr_write(so->extra, buf, len);
842 e1c5a2b3 aliguori
                return len;
843 e1c5a2b3 aliguori
        }
844 e1c5a2b3 aliguori
845 e1c5a2b3 aliguori
        return send(so->s, buf, len, flags);
846 e1c5a2b3 aliguori
}
847 e1c5a2b3 aliguori
848 a13a4126 Jan Kiszka
static struct socket *
849 460fec67 Jan Kiszka
slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port)
850 e1c5a2b3 aliguori
{
851 a13a4126 Jan Kiszka
    struct socket *so;
852 e1c5a2b3 aliguori
853 460fec67 Jan Kiszka
    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
854 a13a4126 Jan Kiszka
        if (so->so_faddr.s_addr == guest_addr.s_addr &&
855 a13a4126 Jan Kiszka
            htons(so->so_fport) == guest_port) {
856 a13a4126 Jan Kiszka
            return so;
857 a13a4126 Jan Kiszka
        }
858 a13a4126 Jan Kiszka
    }
859 a13a4126 Jan Kiszka
    return NULL;
860 e1c5a2b3 aliguori
}
861 e1c5a2b3 aliguori
862 9f8bd042 Jan Kiszka
size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
863 9f8bd042 Jan Kiszka
                             int guest_port)
864 e1c5a2b3 aliguori
{
865 e1c5a2b3 aliguori
        struct iovec iov[2];
866 e1c5a2b3 aliguori
        struct socket *so;
867 e1c5a2b3 aliguori
868 460fec67 Jan Kiszka
        so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
869 e1c5a2b3 aliguori
870 e1c5a2b3 aliguori
        if (!so || so->so_state & SS_NOFDREF)
871 e1c5a2b3 aliguori
                return 0;
872 e1c5a2b3 aliguori
873 e1c5a2b3 aliguori
        if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2))
874 e1c5a2b3 aliguori
                return 0;
875 e1c5a2b3 aliguori
876 e1c5a2b3 aliguori
        return sopreprbuf(so, iov, NULL);
877 e1c5a2b3 aliguori
}
878 e1c5a2b3 aliguori
879 9f8bd042 Jan Kiszka
void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
880 c92ef6a2 Jan Kiszka
                       const uint8_t *buf, int size)
881 e1c5a2b3 aliguori
{
882 e1c5a2b3 aliguori
    int ret;
883 460fec67 Jan Kiszka
    struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
884 a13a4126 Jan Kiszka
885 e1c5a2b3 aliguori
    if (!so)
886 e1c5a2b3 aliguori
        return;
887 e1c5a2b3 aliguori
888 0580ac91 blueswir1
    ret = soreadbuf(so, (const char *)buf, size);
889 e1c5a2b3 aliguori
890 e1c5a2b3 aliguori
    if (ret > 0)
891 e1c5a2b3 aliguori
        tcp_output(sototcpcb(so));
892 e1c5a2b3 aliguori
}
893 062e5527 aliguori
894 062e5527 aliguori
static void slirp_tcp_save(QEMUFile *f, struct tcpcb *tp)
895 062e5527 aliguori
{
896 062e5527 aliguori
    int i;
897 062e5527 aliguori
898 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_state);
899 062e5527 aliguori
    for (i = 0; i < TCPT_NTIMERS; i++)
900 062e5527 aliguori
        qemu_put_sbe16(f, tp->t_timer[i]);
901 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_rxtshift);
902 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_rxtcur);
903 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_dupacks);
904 062e5527 aliguori
    qemu_put_be16(f, tp->t_maxseg);
905 062e5527 aliguori
    qemu_put_sbyte(f, tp->t_force);
906 062e5527 aliguori
    qemu_put_be16(f, tp->t_flags);
907 062e5527 aliguori
    qemu_put_be32(f, tp->snd_una);
908 062e5527 aliguori
    qemu_put_be32(f, tp->snd_nxt);
909 062e5527 aliguori
    qemu_put_be32(f, tp->snd_up);
910 062e5527 aliguori
    qemu_put_be32(f, tp->snd_wl1);
911 062e5527 aliguori
    qemu_put_be32(f, tp->snd_wl2);
912 062e5527 aliguori
    qemu_put_be32(f, tp->iss);
913 062e5527 aliguori
    qemu_put_be32(f, tp->snd_wnd);
914 062e5527 aliguori
    qemu_put_be32(f, tp->rcv_wnd);
915 062e5527 aliguori
    qemu_put_be32(f, tp->rcv_nxt);
916 062e5527 aliguori
    qemu_put_be32(f, tp->rcv_up);
917 062e5527 aliguori
    qemu_put_be32(f, tp->irs);
918 062e5527 aliguori
    qemu_put_be32(f, tp->rcv_adv);
919 062e5527 aliguori
    qemu_put_be32(f, tp->snd_max);
920 062e5527 aliguori
    qemu_put_be32(f, tp->snd_cwnd);
921 062e5527 aliguori
    qemu_put_be32(f, tp->snd_ssthresh);
922 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_idle);
923 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_rtt);
924 062e5527 aliguori
    qemu_put_be32(f, tp->t_rtseq);
925 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_srtt);
926 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_rttvar);
927 062e5527 aliguori
    qemu_put_be16(f, tp->t_rttmin);
928 062e5527 aliguori
    qemu_put_be32(f, tp->max_sndwnd);
929 062e5527 aliguori
    qemu_put_byte(f, tp->t_oobflags);
930 062e5527 aliguori
    qemu_put_byte(f, tp->t_iobc);
931 062e5527 aliguori
    qemu_put_sbe16(f, tp->t_softerror);
932 062e5527 aliguori
    qemu_put_byte(f, tp->snd_scale);
933 062e5527 aliguori
    qemu_put_byte(f, tp->rcv_scale);
934 062e5527 aliguori
    qemu_put_byte(f, tp->request_r_scale);
935 062e5527 aliguori
    qemu_put_byte(f, tp->requested_s_scale);
936 062e5527 aliguori
    qemu_put_be32(f, tp->ts_recent);
937 062e5527 aliguori
    qemu_put_be32(f, tp->ts_recent_age);
938 062e5527 aliguori
    qemu_put_be32(f, tp->last_ack_sent);
939 062e5527 aliguori
}
940 062e5527 aliguori
941 062e5527 aliguori
static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf)
942 062e5527 aliguori
{
943 062e5527 aliguori
    uint32_t off;
944 062e5527 aliguori
945 062e5527 aliguori
    qemu_put_be32(f, sbuf->sb_cc);
946 062e5527 aliguori
    qemu_put_be32(f, sbuf->sb_datalen);
947 062e5527 aliguori
    off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data);
948 062e5527 aliguori
    qemu_put_sbe32(f, off);
949 062e5527 aliguori
    off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data);
950 062e5527 aliguori
    qemu_put_sbe32(f, off);
951 062e5527 aliguori
    qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
952 062e5527 aliguori
}
953 062e5527 aliguori
954 062e5527 aliguori
static void slirp_socket_save(QEMUFile *f, struct socket *so)
955 062e5527 aliguori
{
956 062e5527 aliguori
    qemu_put_be32(f, so->so_urgc);
957 062e5527 aliguori
    qemu_put_be32(f, so->so_faddr.s_addr);
958 062e5527 aliguori
    qemu_put_be32(f, so->so_laddr.s_addr);
959 062e5527 aliguori
    qemu_put_be16(f, so->so_fport);
960 062e5527 aliguori
    qemu_put_be16(f, so->so_lport);
961 062e5527 aliguori
    qemu_put_byte(f, so->so_iptos);
962 062e5527 aliguori
    qemu_put_byte(f, so->so_emu);
963 062e5527 aliguori
    qemu_put_byte(f, so->so_type);
964 062e5527 aliguori
    qemu_put_be32(f, so->so_state);
965 062e5527 aliguori
    slirp_sbuf_save(f, &so->so_rcv);
966 062e5527 aliguori
    slirp_sbuf_save(f, &so->so_snd);
967 062e5527 aliguori
    slirp_tcp_save(f, so->so_tcpcb);
968 062e5527 aliguori
}
969 062e5527 aliguori
970 0a1f851e Jan Kiszka
static void slirp_bootp_save(QEMUFile *f, Slirp *slirp)
971 0a1f851e Jan Kiszka
{
972 0a1f851e Jan Kiszka
    int i;
973 0a1f851e Jan Kiszka
974 0a1f851e Jan Kiszka
    for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
975 0a1f851e Jan Kiszka
        qemu_put_be16(f, slirp->bootp_clients[i].allocated);
976 0a1f851e Jan Kiszka
        qemu_put_buffer(f, slirp->bootp_clients[i].macaddr, 6);
977 0a1f851e Jan Kiszka
    }
978 0a1f851e Jan Kiszka
}
979 0a1f851e Jan Kiszka
980 062e5527 aliguori
static void slirp_state_save(QEMUFile *f, void *opaque)
981 062e5527 aliguori
{
982 460fec67 Jan Kiszka
    Slirp *slirp = opaque;
983 062e5527 aliguori
    struct ex_list *ex_ptr;
984 062e5527 aliguori
985 460fec67 Jan Kiszka
    for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
986 062e5527 aliguori
        if (ex_ptr->ex_pty == 3) {
987 062e5527 aliguori
            struct socket *so;
988 460fec67 Jan Kiszka
            so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
989 460fec67 Jan Kiszka
                                       ntohs(ex_ptr->ex_fport));
990 062e5527 aliguori
            if (!so)
991 062e5527 aliguori
                continue;
992 062e5527 aliguori
993 062e5527 aliguori
            qemu_put_byte(f, 42);
994 062e5527 aliguori
            slirp_socket_save(f, so);
995 062e5527 aliguori
        }
996 062e5527 aliguori
    qemu_put_byte(f, 0);
997 285f7a62 Jan Kiszka
998 460fec67 Jan Kiszka
    qemu_put_be16(f, slirp->ip_id);
999 0a1f851e Jan Kiszka
1000 0a1f851e Jan Kiszka
    slirp_bootp_save(f, slirp);
1001 062e5527 aliguori
}
1002 062e5527 aliguori
1003 062e5527 aliguori
static void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp)
1004 062e5527 aliguori
{
1005 062e5527 aliguori
    int i;
1006 062e5527 aliguori
1007 062e5527 aliguori
    tp->t_state = qemu_get_sbe16(f);
1008 062e5527 aliguori
    for (i = 0; i < TCPT_NTIMERS; i++)
1009 062e5527 aliguori
        tp->t_timer[i] = qemu_get_sbe16(f);
1010 062e5527 aliguori
    tp->t_rxtshift = qemu_get_sbe16(f);
1011 062e5527 aliguori
    tp->t_rxtcur = qemu_get_sbe16(f);
1012 062e5527 aliguori
    tp->t_dupacks = qemu_get_sbe16(f);
1013 062e5527 aliguori
    tp->t_maxseg = qemu_get_be16(f);
1014 062e5527 aliguori
    tp->t_force = qemu_get_sbyte(f);
1015 062e5527 aliguori
    tp->t_flags = qemu_get_be16(f);
1016 062e5527 aliguori
    tp->snd_una = qemu_get_be32(f);
1017 062e5527 aliguori
    tp->snd_nxt = qemu_get_be32(f);
1018 062e5527 aliguori
    tp->snd_up = qemu_get_be32(f);
1019 062e5527 aliguori
    tp->snd_wl1 = qemu_get_be32(f);
1020 062e5527 aliguori
    tp->snd_wl2 = qemu_get_be32(f);
1021 062e5527 aliguori
    tp->iss = qemu_get_be32(f);
1022 062e5527 aliguori
    tp->snd_wnd = qemu_get_be32(f);
1023 062e5527 aliguori
    tp->rcv_wnd = qemu_get_be32(f);
1024 062e5527 aliguori
    tp->rcv_nxt = qemu_get_be32(f);
1025 062e5527 aliguori
    tp->rcv_up = qemu_get_be32(f);
1026 062e5527 aliguori
    tp->irs = qemu_get_be32(f);
1027 062e5527 aliguori
    tp->rcv_adv = qemu_get_be32(f);
1028 062e5527 aliguori
    tp->snd_max = qemu_get_be32(f);
1029 062e5527 aliguori
    tp->snd_cwnd = qemu_get_be32(f);
1030 062e5527 aliguori
    tp->snd_ssthresh = qemu_get_be32(f);
1031 062e5527 aliguori
    tp->t_idle = qemu_get_sbe16(f);
1032 062e5527 aliguori
    tp->t_rtt = qemu_get_sbe16(f);
1033 062e5527 aliguori
    tp->t_rtseq = qemu_get_be32(f);
1034 062e5527 aliguori
    tp->t_srtt = qemu_get_sbe16(f);
1035 062e5527 aliguori
    tp->t_rttvar = qemu_get_sbe16(f);
1036 062e5527 aliguori
    tp->t_rttmin = qemu_get_be16(f);
1037 062e5527 aliguori
    tp->max_sndwnd = qemu_get_be32(f);
1038 062e5527 aliguori
    tp->t_oobflags = qemu_get_byte(f);
1039 062e5527 aliguori
    tp->t_iobc = qemu_get_byte(f);
1040 062e5527 aliguori
    tp->t_softerror = qemu_get_sbe16(f);
1041 062e5527 aliguori
    tp->snd_scale = qemu_get_byte(f);
1042 062e5527 aliguori
    tp->rcv_scale = qemu_get_byte(f);
1043 062e5527 aliguori
    tp->request_r_scale = qemu_get_byte(f);
1044 062e5527 aliguori
    tp->requested_s_scale = qemu_get_byte(f);
1045 062e5527 aliguori
    tp->ts_recent = qemu_get_be32(f);
1046 062e5527 aliguori
    tp->ts_recent_age = qemu_get_be32(f);
1047 062e5527 aliguori
    tp->last_ack_sent = qemu_get_be32(f);
1048 062e5527 aliguori
    tcp_template(tp);
1049 062e5527 aliguori
}
1050 062e5527 aliguori
1051 062e5527 aliguori
static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf)
1052 062e5527 aliguori
{
1053 062e5527 aliguori
    uint32_t off, sb_cc, sb_datalen;
1054 062e5527 aliguori
1055 062e5527 aliguori
    sb_cc = qemu_get_be32(f);
1056 062e5527 aliguori
    sb_datalen = qemu_get_be32(f);
1057 062e5527 aliguori
1058 062e5527 aliguori
    sbreserve(sbuf, sb_datalen);
1059 062e5527 aliguori
1060 062e5527 aliguori
    if (sbuf->sb_datalen != sb_datalen)
1061 062e5527 aliguori
        return -ENOMEM;
1062 062e5527 aliguori
1063 062e5527 aliguori
    sbuf->sb_cc = sb_cc;
1064 062e5527 aliguori
1065 062e5527 aliguori
    off = qemu_get_sbe32(f);
1066 062e5527 aliguori
    sbuf->sb_wptr = sbuf->sb_data + off;
1067 062e5527 aliguori
    off = qemu_get_sbe32(f);
1068 062e5527 aliguori
    sbuf->sb_rptr = sbuf->sb_data + off;
1069 062e5527 aliguori
    qemu_get_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
1070 062e5527 aliguori
1071 062e5527 aliguori
    return 0;
1072 062e5527 aliguori
}
1073 062e5527 aliguori
1074 062e5527 aliguori
static int slirp_socket_load(QEMUFile *f, struct socket *so)
1075 062e5527 aliguori
{
1076 062e5527 aliguori
    if (tcp_attach(so) < 0)
1077 062e5527 aliguori
        return -ENOMEM;
1078 062e5527 aliguori
1079 062e5527 aliguori
    so->so_urgc = qemu_get_be32(f);
1080 062e5527 aliguori
    so->so_faddr.s_addr = qemu_get_be32(f);
1081 062e5527 aliguori
    so->so_laddr.s_addr = qemu_get_be32(f);
1082 062e5527 aliguori
    so->so_fport = qemu_get_be16(f);
1083 062e5527 aliguori
    so->so_lport = qemu_get_be16(f);
1084 062e5527 aliguori
    so->so_iptos = qemu_get_byte(f);
1085 062e5527 aliguori
    so->so_emu = qemu_get_byte(f);
1086 062e5527 aliguori
    so->so_type = qemu_get_byte(f);
1087 062e5527 aliguori
    so->so_state = qemu_get_be32(f);
1088 062e5527 aliguori
    if (slirp_sbuf_load(f, &so->so_rcv) < 0)
1089 062e5527 aliguori
        return -ENOMEM;
1090 062e5527 aliguori
    if (slirp_sbuf_load(f, &so->so_snd) < 0)
1091 062e5527 aliguori
        return -ENOMEM;
1092 062e5527 aliguori
    slirp_tcp_load(f, so->so_tcpcb);
1093 062e5527 aliguori
1094 062e5527 aliguori
    return 0;
1095 062e5527 aliguori
}
1096 062e5527 aliguori
1097 0a1f851e Jan Kiszka
static void slirp_bootp_load(QEMUFile *f, Slirp *slirp)
1098 0a1f851e Jan Kiszka
{
1099 0a1f851e Jan Kiszka
    int i;
1100 0a1f851e Jan Kiszka
1101 0a1f851e Jan Kiszka
    for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
1102 0a1f851e Jan Kiszka
        slirp->bootp_clients[i].allocated = qemu_get_be16(f);
1103 0a1f851e Jan Kiszka
        qemu_get_buffer(f, slirp->bootp_clients[i].macaddr, 6);
1104 0a1f851e Jan Kiszka
    }
1105 0a1f851e Jan Kiszka
}
1106 0a1f851e Jan Kiszka
1107 062e5527 aliguori
static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
1108 062e5527 aliguori
{
1109 460fec67 Jan Kiszka
    Slirp *slirp = opaque;
1110 062e5527 aliguori
    struct ex_list *ex_ptr;
1111 062e5527 aliguori
1112 b0e04867 Blue Swirl
    while (qemu_get_byte(f)) {
1113 062e5527 aliguori
        int ret;
1114 460fec67 Jan Kiszka
        struct socket *so = socreate(slirp);
1115 062e5527 aliguori
1116 062e5527 aliguori
        if (!so)
1117 062e5527 aliguori
            return -ENOMEM;
1118 062e5527 aliguori
1119 062e5527 aliguori
        ret = slirp_socket_load(f, so);
1120 062e5527 aliguori
1121 062e5527 aliguori
        if (ret < 0)
1122 062e5527 aliguori
            return ret;
1123 062e5527 aliguori
1124 460fec67 Jan Kiszka
        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) !=
1125 460fec67 Jan Kiszka
            slirp->vnetwork_addr.s_addr) {
1126 062e5527 aliguori
            return -EINVAL;
1127 a13a4126 Jan Kiszka
        }
1128 460fec67 Jan Kiszka
        for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
1129 062e5527 aliguori
            if (ex_ptr->ex_pty == 3 &&
1130 a13a4126 Jan Kiszka
                so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
1131 a13a4126 Jan Kiszka
                so->so_fport == ex_ptr->ex_fport) {
1132 062e5527 aliguori
                break;
1133 a13a4126 Jan Kiszka
            }
1134 a13a4126 Jan Kiszka
        }
1135 062e5527 aliguori
        if (!ex_ptr)
1136 062e5527 aliguori
            return -EINVAL;
1137 062e5527 aliguori
1138 0580ac91 blueswir1
        so->extra = (void *)ex_ptr->ex_exec;
1139 062e5527 aliguori
    }
1140 062e5527 aliguori
1141 285f7a62 Jan Kiszka
    if (version_id >= 2) {
1142 460fec67 Jan Kiszka
        slirp->ip_id = qemu_get_be16(f);
1143 285f7a62 Jan Kiszka
    }
1144 285f7a62 Jan Kiszka
1145 0a1f851e Jan Kiszka
    if (version_id >= 3) {
1146 0a1f851e Jan Kiszka
        slirp_bootp_load(f, slirp);
1147 0a1f851e Jan Kiszka
    }
1148 0a1f851e Jan Kiszka
1149 062e5527 aliguori
    return 0;
1150 062e5527 aliguori
}