Statistics
| Branch: | Revision:

root / slirp / slirp.c @ ac72472b

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