slirp.c 37.5 KB
Newer Older
B
bellard 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * libslirp glue
 *
 * Copyright (c) 2004-2008 Fabrice Bellard
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
P
Peter Maydell 已提交
24
#include "qemu/osdep.h"
25
#include "qemu-common.h"
26
#include "qemu/timer.h"
27
#include "qemu/error-report.h"
28
#include "sysemu/char.h"
B
bellard 已提交
29
#include "slirp.h"
30
#include "hw/hw.h"
B
bellard 已提交
31 32 33

/* host loopback address */
struct in_addr loopback_addr;
34
/* host loopback network mask */
A
Anthony Liguori 已提交
35
unsigned long loopback_mask;
B
bellard 已提交
36

37
/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
F
Fabien Chouteau 已提交
38
static const uint8_t special_ethaddr[ETH_ALEN] = {
39
    0x52, 0x55, 0x00, 0x00, 0x00, 0x00
B
bellard 已提交
40 41
};

42 43
u_int curtime;

B
Blue Swirl 已提交
44 45
static QTAILQ_HEAD(slirp_instances, Slirp) slirp_instances =
    QTAILQ_HEAD_INITIALIZER(slirp_instances);
P
pbrook 已提交
46

S
Stefan Weil 已提交
47 48
static struct in_addr dns_addr;
static u_int dns_addr_time;
49

L
Liu Ping Fan 已提交
50 51 52 53 54
#define TIMEOUT_FAST 2  /* milliseconds */
#define TIMEOUT_SLOW 499  /* milliseconds */
/* for the aging of certain requests like DNS */
#define TIMEOUT_DEFAULT 1000  /* milliseconds */

B
bellard 已提交
55 56
#ifdef _WIN32

57
int get_dns_addr(struct in_addr *pdns_addr)
B
bellard 已提交
58
{
B
bellard 已提交
59 60 61 62 63
    FIXED_INFO *FixedInfo=NULL;
    ULONG    BufLen;
    DWORD    ret;
    IP_ADDR_STRING *pIPAddr;
    struct in_addr tmp_addr;
64

L
Liu Ping Fan 已提交
65
    if (dns_addr.s_addr != 0 && (curtime - dns_addr_time) < TIMEOUT_DEFAULT) {
66 67 68 69
        *pdns_addr = dns_addr;
        return 0;
    }

B
bellard 已提交
70 71
    FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
    BufLen = sizeof(FIXED_INFO);
72

B
bellard 已提交
73 74 75 76 77 78 79
    if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
        if (FixedInfo) {
            GlobalFree(FixedInfo);
            FixedInfo = NULL;
        }
        FixedInfo = GlobalAlloc(GPTR, BufLen);
    }
80

B
bellard 已提交
81 82 83 84 85 86 87 88
    if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
        printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
        if (FixedInfo) {
            GlobalFree(FixedInfo);
            FixedInfo = NULL;
        }
        return -1;
    }
89

B
bellard 已提交
90 91 92
    pIPAddr = &(FixedInfo->DnsServerList);
    inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
    *pdns_addr = tmp_addr;
93 94
    dns_addr = tmp_addr;
    dns_addr_time = curtime;
B
bellard 已提交
95 96 97 98 99
    if (FixedInfo) {
        GlobalFree(FixedInfo);
        FixedInfo = NULL;
    }
    return 0;
B
bellard 已提交
100 101
}

102 103 104 105 106
static void winsock_cleanup(void)
{
    WSACleanup();
}

B
bellard 已提交
107 108
#else

B
Blue Swirl 已提交
109
static struct stat dns_addr_stat;
110 111

int get_dns_addr(struct in_addr *pdns_addr)
B
bellard 已提交
112 113
{
    char buff[512];
B
blueswir1 已提交
114
    char buff2[257];
B
bellard 已提交
115 116 117
    FILE *f;
    int found = 0;
    struct in_addr tmp_addr;
118

119 120
    if (dns_addr.s_addr != 0) {
        struct stat old_stat;
L
Liu Ping Fan 已提交
121
        if ((curtime - dns_addr_time) < TIMEOUT_DEFAULT) {
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
            *pdns_addr = dns_addr;
            return 0;
        }
        old_stat = dns_addr_stat;
        if (stat("/etc/resolv.conf", &dns_addr_stat) != 0)
            return -1;
        if ((dns_addr_stat.st_dev == old_stat.st_dev)
            && (dns_addr_stat.st_ino == old_stat.st_ino)
            && (dns_addr_stat.st_size == old_stat.st_size)
            && (dns_addr_stat.st_mtime == old_stat.st_mtime)) {
            *pdns_addr = dns_addr;
            return 0;
        }
    }

B
bellard 已提交
137 138 139 140
    f = fopen("/etc/resolv.conf", "r");
    if (!f)
        return -1;

141
#ifdef DEBUG
C
Cole Robinson 已提交
142
    fprintf(stderr, "IP address of your DNS(s): ");
143
#endif
B
bellard 已提交
144 145 146 147 148
    while (fgets(buff, 512, f) != NULL) {
        if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
            if (!inet_aton(buff2, &tmp_addr))
                continue;
            /* If it's the first one, set it to dns_addr */
149
            if (!found) {
B
bellard 已提交
150
                *pdns_addr = tmp_addr;
151 152 153
                dns_addr = tmp_addr;
                dns_addr_time = curtime;
            }
154
#ifdef DEBUG
B
bellard 已提交
155
            else
C
Cole Robinson 已提交
156
                fprintf(stderr, ", ");
157
#endif
B
bellard 已提交
158
            if (++found > 3) {
159
#ifdef DEBUG
C
Cole Robinson 已提交
160
                fprintf(stderr, "(more)");
161
#endif
B
bellard 已提交
162
                break;
163 164 165
            }
#ifdef DEBUG
            else
C
Cole Robinson 已提交
166
                fprintf(stderr, "%s", inet_ntoa(tmp_addr));
167
#endif
B
bellard 已提交
168 169
        }
    }
B
bellard 已提交
170
    fclose(f);
B
bellard 已提交
171 172 173 174 175 176 177
    if (!found)
        return -1;
    return 0;
}

#endif

178
static void slirp_init_once(void)
B
bellard 已提交
179
{
180 181 182
    static int initialized;
#ifdef _WIN32
    WSADATA Data;
B
bellard 已提交
183 184
#endif

185 186 187 188 189 190 191 192 193 194 195
    if (initialized) {
        return;
    }
    initialized = 1;

#ifdef _WIN32
    WSAStartup(MAKEWORD(2,0), &Data);
    atexit(winsock_cleanup);
#endif

    loopback_addr.s_addr = htonl(INADDR_LOOPBACK);
196
    loopback_mask = htonl(IN_CLASSA_NET);
197 198
}

199 200 201
static void slirp_state_save(QEMUFile *f, void *opaque);
static int slirp_state_load(QEMUFile *f, void *opaque, int version_id);

202 203 204 205
Slirp *slirp_init(int restricted, struct in_addr vnetwork,
                  struct in_addr vnetmask, struct in_addr vhost,
                  const char *vhostname, const char *tftp_path,
                  const char *bootfile, struct in_addr vdhcp_start,
206 207
                  struct in_addr vnameserver, const char **vdnssearch,
                  void *opaque)
B
bellard 已提交
208
{
209
    Slirp *slirp = g_malloc0(sizeof(Slirp));
210

211
    slirp_init_once();
B
bellard 已提交
212

213
    slirp->restricted = restricted;
B
bellard 已提交
214

215 216
    if_init(slirp);
    ip_init(slirp);
B
bellard 已提交
217 218

    /* Initialise mbufs *after* setting the MTU */
219
    m_init(slirp);
B
bellard 已提交
220

221 222 223
    slirp->vnetwork_addr = vnetwork;
    slirp->vnetwork_mask = vnetmask;
    slirp->vhost_addr = vhost;
224
    if (vhostname) {
225 226
        pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
                vhostname);
227
    }
228 229
    slirp->tftp_prefix = g_strdup(tftp_path);
    slirp->bootp_filename = g_strdup(bootfile);
230 231
    slirp->vdhcp_startaddr = vdhcp_start;
    slirp->vnameserver_addr = vnameserver;
232

233 234 235 236
    if (vdnssearch) {
        translate_dnssearch(slirp, vdnssearch);
    }

237 238
    slirp->opaque = opaque;

239
    register_savevm(NULL, "slirp", 0, 4,
A
Alex Williamson 已提交
240
                    slirp_state_save, slirp_state_load, slirp);
241

B
Blue Swirl 已提交
242
    QTAILQ_INSERT_TAIL(&slirp_instances, slirp, entry);
243

244
    return slirp;
B
bellard 已提交
245 246
}

247 248
void slirp_cleanup(Slirp *slirp)
{
B
Blue Swirl 已提交
249
    QTAILQ_REMOVE(&slirp_instances, slirp, entry);
J
Jan Kiszka 已提交
250

A
Alex Williamson 已提交
251
    unregister_savevm(NULL, "slirp", slirp);
252

253 254 255
    ip_cleanup(slirp);
    m_cleanup(slirp);

256
    g_free(slirp->vdnssearch);
257 258 259
    g_free(slirp->tftp_prefix);
    g_free(slirp->bootp_filename);
    g_free(slirp);
260 261
}

B
bellard 已提交
262 263 264
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)

265
static void slirp_update_timeout(uint32_t *timeout)
266
{
267 268 269 270 271 272
    Slirp *slirp;
    uint32_t t;

    if (*timeout <= TIMEOUT_FAST) {
        return;
    }
273 274

    t = MIN(1000, *timeout);
275 276 277 278 279 280 281 282 283 284 285 286

    /* If we have tcp timeout with slirp, then we will fill @timeout with
     * more precise value.
     */
    QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
        if (slirp->time_fasttimo) {
            *timeout = TIMEOUT_FAST;
            return;
        }
        if (slirp->do_slowtimo) {
            t = MIN(TIMEOUT_SLOW, t);
        }
287
    }
288
    *timeout = t;
289 290
}

291
void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
B
bellard 已提交
292
{
J
Jan Kiszka 已提交
293
    Slirp *slirp;
B
bellard 已提交
294 295
    struct socket *so, *so_next;

B
Blue Swirl 已提交
296
    if (QTAILQ_EMPTY(&slirp_instances)) {
J
Jan Kiszka 已提交
297 298 299
        return;
    }

300 301 302
    /*
     * First, TCP sockets
     */
303

304 305 306 307 308
    QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
        /*
         * *_slowtimo needs calling if there are IP fragments
         * in the fragment queue, or there are TCP connections active
         */
L
Liu Ping Fan 已提交
309
        slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
310 311 312 313
                (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));

        for (so = slirp->tcb.so_next; so != &slirp->tcb;
                so = so_next) {
S
Stefan Hajnoczi 已提交
314 315
            int events = 0;

316 317
            so_next = so->so_next;

S
Stefan Hajnoczi 已提交
318 319
            so->pollfds_idx = -1;

320 321 322
            /*
             * See if we need a tcp_fasttimo
             */
L
Liu Ping Fan 已提交
323 324 325
            if (slirp->time_fasttimo == 0 &&
                so->so_tcpcb->t_flags & TF_DELACK) {
                slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */
326
            }
327

328 329 330 331 332 333 334
            /*
             * NOFDREF can include still connecting to local-host,
             * newly socreated() sockets etc. Don't want to select these.
             */
            if (so->so_state & SS_NOFDREF || so->s == -1) {
                continue;
            }
335

336 337 338 339
            /*
             * Set for reading sockets which are accepting
             */
            if (so->so_state & SS_FACCEPTCONN) {
S
Stefan Hajnoczi 已提交
340 341 342 343 344 345
                GPollFD pfd = {
                    .fd = so->s,
                    .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
                };
                so->pollfds_idx = pollfds->len;
                g_array_append_val(pollfds, pfd);
346 347 348 349 350 351 352
                continue;
            }

            /*
             * Set for writing sockets which are connecting
             */
            if (so->so_state & SS_ISFCONNECTING) {
S
Stefan Hajnoczi 已提交
353 354 355 356 357 358
                GPollFD pfd = {
                    .fd = so->s,
                    .events = G_IO_OUT | G_IO_ERR,
                };
                so->pollfds_idx = pollfds->len;
                g_array_append_val(pollfds, pfd);
359 360 361 362 363 364 365 366
                continue;
            }

            /*
             * Set for writing if we are connected, can send more, and
             * we have something to send
             */
            if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
S
Stefan Hajnoczi 已提交
367
                events |= G_IO_OUT | G_IO_ERR;
368 369 370 371 372 373 374 375
            }

            /*
             * Set for reading (and urgent data) if we are connected, can
             * receive more, and we have room for it XXX /2 ?
             */
            if (CONN_CANFRCV(so) &&
                (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
S
Stefan Hajnoczi 已提交
376 377 378 379 380 381 382 383 384 385
                events |= G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
            }

            if (events) {
                GPollFD pfd = {
                    .fd = so->s,
                    .events = events,
                };
                so->pollfds_idx = pollfds->len;
                g_array_append_val(pollfds, pfd);
386 387 388 389 390 391 392 393 394 395
            }
        }

        /*
         * UDP sockets
         */
        for (so = slirp->udb.so_next; so != &slirp->udb;
                so = so_next) {
            so_next = so->so_next;

S
Stefan Hajnoczi 已提交
396 397
            so->pollfds_idx = -1;

398 399 400 401 402 403 404 405
            /*
             * See if it's timed out
             */
            if (so->so_expire) {
                if (so->so_expire <= curtime) {
                    udp_detach(so);
                    continue;
                } else {
L
Liu Ping Fan 已提交
406
                    slirp->do_slowtimo = true; /* Let socket expire */
407
                }
408 409 410 411 412 413 414 415 416 417 418 419 420
            }

            /*
             * When UDP packets are received from over the
             * link, they're sendto()'d straight away, so
             * no need for setting for writing
             * Limit the number of packets queued by this session
             * to 4.  Note that even though we try and limit this
             * to 4 packets, the session could have more queued
             * if the packets needed to be fragmented
             * (XXX <= 4 ?)
             */
            if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
S
Stefan Hajnoczi 已提交
421 422 423 424 425 426
                GPollFD pfd = {
                    .fd = so->s,
                    .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
                };
                so->pollfds_idx = pollfds->len;
                g_array_append_val(pollfds, pfd);
427 428
            }
        }
429

430 431 432 433 434 435 436
        /*
         * ICMP sockets
         */
        for (so = slirp->icmp.so_next; so != &slirp->icmp;
                so = so_next) {
            so_next = so->so_next;

S
Stefan Hajnoczi 已提交
437 438
            so->pollfds_idx = -1;

439 440 441 442 443 444 445 446
            /*
             * See if it's timed out
             */
            if (so->so_expire) {
                if (so->so_expire <= curtime) {
                    icmp_detach(so);
                    continue;
                } else {
L
Liu Ping Fan 已提交
447
                    slirp->do_slowtimo = true; /* Let socket expire */
448 449 450 451
                }
            }

            if (so->so_state & SS_ISFCONNECTED) {
S
Stefan Hajnoczi 已提交
452 453 454 455 456 457
                GPollFD pfd = {
                    .fd = so->s,
                    .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
                };
                so->pollfds_idx = pollfds->len;
                g_array_append_val(pollfds, pfd);
458 459 460
            }
        }
    }
461
    slirp_update_timeout(timeout);
462
}
B
bellard 已提交
463

S
Stefan Hajnoczi 已提交
464
void slirp_pollfds_poll(GArray *pollfds, int select_error)
B
bellard 已提交
465
{
J
Jan Kiszka 已提交
466
    Slirp *slirp;
B
bellard 已提交
467 468 469
    struct socket *so, *so_next;
    int ret;

B
Blue Swirl 已提交
470
    if (QTAILQ_EMPTY(&slirp_instances)) {
J
Jan Kiszka 已提交
471 472 473
        return;
    }

474
    curtime = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
475

B
Blue Swirl 已提交
476
    QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
477 478 479
        /*
         * See if anything has timed out
         */
L
Liu Ping Fan 已提交
480 481
        if (slirp->time_fasttimo &&
            ((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) {
482
            tcp_fasttimo(slirp);
L
Liu Ping Fan 已提交
483
            slirp->time_fasttimo = 0;
484
        }
L
Liu Ping Fan 已提交
485 486
        if (slirp->do_slowtimo &&
            ((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) {
487 488
            ip_slowtimo(slirp);
            tcp_slowtimo(slirp);
L
Liu Ping Fan 已提交
489
            slirp->last_slowtimo = curtime;
490 491 492 493 494 495 496 497 498 499 500
        }

        /*
         * Check sockets
         */
        if (!select_error) {
            /*
             * Check TCP sockets
             */
            for (so = slirp->tcb.so_next; so != &slirp->tcb;
                    so = so_next) {
S
Stefan Hajnoczi 已提交
501 502
                int revents;

503 504
                so_next = so->so_next;

S
Stefan Hajnoczi 已提交
505 506 507 508 509 510
                revents = 0;
                if (so->pollfds_idx != -1) {
                    revents = g_array_index(pollfds, GPollFD,
                                            so->pollfds_idx).revents;
                }

511 512 513 514 515 516 517
                if (so->so_state & SS_NOFDREF || so->s == -1) {
                    continue;
                }

                /*
                 * Check for URG data
                 * This will soread as well, so no need to
S
Stefan Hajnoczi 已提交
518
                 * test for G_IO_IN below if this succeeds
519
                 */
S
Stefan Hajnoczi 已提交
520
                if (revents & G_IO_PRI) {
521 522 523 524 525
                    sorecvoob(so);
                }
                /*
                 * Check sockets for reading
                 */
S
Stefan Hajnoczi 已提交
526
                else if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
                    /*
                     * Check for incoming connections
                     */
                    if (so->so_state & SS_FACCEPTCONN) {
                        tcp_connect(so);
                        continue;
                    } /* else */
                    ret = soread(so);

                    /* Output it if we read something */
                    if (ret > 0) {
                        tcp_output(sototcpcb(so));
                    }
                }

                /*
                 * Check sockets for writing
                 */
S
Stefan Hajnoczi 已提交
545 546
                if (!(so->so_state & SS_NOFDREF) &&
                        (revents & (G_IO_OUT | G_IO_ERR))) {
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
                    /*
                     * Check for non-blocking, still-connecting sockets
                     */
                    if (so->so_state & SS_ISFCONNECTING) {
                        /* Connected */
                        so->so_state &= ~SS_ISFCONNECTING;

                        ret = send(so->s, (const void *) &ret, 0, 0);
                        if (ret < 0) {
                            /* XXXXX Must fix, zero bytes is a NOP */
                            if (errno == EAGAIN || errno == EWOULDBLOCK ||
                                errno == EINPROGRESS || errno == ENOTCONN) {
                                continue;
                            }

                            /* else failed */
                            so->so_state &= SS_PERSISTENT_MASK;
                            so->so_state |= SS_NOFDREF;
B
bellard 已提交
565
                        }
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
                        /* else so->so_state &= ~SS_ISFCONNECTING; */

                        /*
                         * Continue tcp_input
                         */
                        tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
                        /* continue; */
                    } else {
                        ret = sowrite(so);
                    }
                    /*
                     * XXXXX If we wrote something (a lot), there
                     * could be a need for a window update.
                     * In the worst case, the remote will send
                     * a window probe to get things going again
                     */
                }
583 584

                /*
585 586
                 * Probe a still-connecting, non-blocking socket
                 * to check if it's still alive
587
                 */
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
#ifdef PROBE_CONN
                if (so->so_state & SS_ISFCONNECTING) {
                    ret = qemu_recv(so->s, &ret, 0, 0);

                    if (ret < 0) {
                        /* XXX */
                        if (errno == EAGAIN || errno == EWOULDBLOCK ||
                            errno == EINPROGRESS || errno == ENOTCONN) {
                            continue; /* Still connecting, continue */
                        }

                        /* else failed */
                        so->so_state &= SS_PERSISTENT_MASK;
                        so->so_state |= SS_NOFDREF;

                        /* tcp_input will take care of it */
                    } else {
                        ret = send(so->s, &ret, 0, 0);
                        if (ret < 0) {
                            /* XXX */
                            if (errno == EAGAIN || errno == EWOULDBLOCK ||
                                errno == EINPROGRESS || errno == ENOTCONN) {
                                continue;
                            }
                            /* else failed */
                            so->so_state &= SS_PERSISTENT_MASK;
                            so->so_state |= SS_NOFDREF;
                        } else {
                            so->so_state &= ~SS_ISFCONNECTING;
                        }
618 619

                    }
620 621 622 623 624 625 626 627 628 629 630 631
                    tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
                } /* SS_ISFCONNECTING */
#endif
            }

            /*
             * Now UDP sockets.
             * Incoming packets are sent straight away, they're not buffered.
             * Incoming UDP data isn't buffered either.
             */
            for (so = slirp->udb.so_next; so != &slirp->udb;
                    so = so_next) {
S
Stefan Hajnoczi 已提交
632 633
                int revents;

634 635
                so_next = so->so_next;

S
Stefan Hajnoczi 已提交
636 637 638 639 640 641 642 643
                revents = 0;
                if (so->pollfds_idx != -1) {
                    revents = g_array_index(pollfds, GPollFD,
                            so->pollfds_idx).revents;
                }

                if (so->s != -1 &&
                    (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
644
                    sorecvfrom(so);
645
                }
646 647 648 649 650 651 652
            }

            /*
             * Check incoming ICMP relies.
             */
            for (so = slirp->icmp.so_next; so != &slirp->icmp;
                    so = so_next) {
S
Stefan Hajnoczi 已提交
653 654 655 656 657 658 659 660 661
                    int revents;

                    so_next = so->so_next;

                    revents = 0;
                    if (so->pollfds_idx != -1) {
                        revents = g_array_index(pollfds, GPollFD,
                                                so->pollfds_idx).revents;
                    }
662

S
Stefan Hajnoczi 已提交
663 664
                    if (so->s != -1 &&
                        (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
665 666 667 668
                    icmp_receive(so);
                }
            }
        }
669

J
Jan Kiszka 已提交
670
        if_start(slirp);
J
Jan Kiszka 已提交
671
    }
B
bellard 已提交
672 673
}

674
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
B
bellard 已提交
675 676
{
    struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
677
    uint8_t arp_reply[max(ETH_HLEN + sizeof(struct arphdr), 64)];
B
bellard 已提交
678 679 680
    struct ethhdr *reh = (struct ethhdr *)arp_reply;
    struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
    int ar_op;
B
bellard 已提交
681
    struct ex_list *ex_ptr;
B
bellard 已提交
682 683 684 685

    ar_op = ntohs(ah->ar_op);
    switch(ar_op) {
    case ARPOP_REQUEST:
F
Fabien Chouteau 已提交
686 687 688 689 690 691
        if (ah->ar_tip == ah->ar_sip) {
            /* Gratuitous ARP */
            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
            return;
        }

692 693 694 695
        if ((ah->ar_tip & slirp->vnetwork_mask.s_addr) ==
            slirp->vnetwork_addr.s_addr) {
            if (ah->ar_tip == slirp->vnameserver_addr.s_addr ||
                ah->ar_tip == slirp->vhost_addr.s_addr)
B
bellard 已提交
696
                goto arp_ok;
697
            for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
698
                if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
B
bellard 已提交
699 700 701 702
                    goto arp_ok;
            }
            return;
        arp_ok:
703
            memset(arp_reply, 0, sizeof(arp_reply));
F
Fabien Chouteau 已提交
704 705

            arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
B
bellard 已提交
706 707 708

            /* ARP request for alias/dns mac address */
            memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
709 710
            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
            memcpy(&reh->h_source[2], &ah->ar_tip, 4);
B
bellard 已提交
711 712 713 714 715 716 717 718
            reh->h_proto = htons(ETH_P_ARP);

            rah->ar_hrd = htons(1);
            rah->ar_pro = htons(ETH_P_IP);
            rah->ar_hln = ETH_ALEN;
            rah->ar_pln = 4;
            rah->ar_op = htons(ARPOP_REPLY);
            memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
719
            rah->ar_sip = ah->ar_tip;
B
bellard 已提交
720
            memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
721
            rah->ar_tip = ah->ar_sip;
722
            slirp_output(slirp->opaque, arp_reply, sizeof(arp_reply));
B
bellard 已提交
723 724
        }
        break;
725
    case ARPOP_REPLY:
F
Fabien Chouteau 已提交
726
        arp_table_add(slirp, ah->ar_sip, ah->ar_sha);
727
        break;
B
bellard 已提交
728 729 730 731 732
    default:
        break;
    }
}

733
void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
B
bellard 已提交
734 735 736 737 738 739
{
    struct mbuf *m;
    int proto;

    if (pkt_len < ETH_HLEN)
        return;
740

B
bellard 已提交
741 742 743
    proto = ntohs(*(uint16_t *)(pkt + 12));
    switch(proto) {
    case ETH_P_ARP:
744
        arp_input(slirp, pkt, pkt_len);
B
bellard 已提交
745 746
        break;
    case ETH_P_IP:
747
        m = m_get(slirp);
B
bellard 已提交
748 749
        if (!m)
            return;
B
bellard 已提交
750
        /* Note: we add to align the IP header */
A
aurel32 已提交
751 752 753
        if (M_FREEROOM(m) < pkt_len + 2) {
            m_inc(m, pkt_len + 2);
        }
B
bellard 已提交
754 755
        m->m_len = pkt_len + 2;
        memcpy(m->m_data + 2, pkt, pkt_len);
B
bellard 已提交
756

B
bellard 已提交
757 758
        m->m_data += 2 + ETH_HLEN;
        m->m_len -= 2 + ETH_HLEN;
B
bellard 已提交
759 760 761 762 763 764 765 766

        ip_input(m);
        break;
    default:
        break;
    }
}

767 768 769
/* Prepare the IPv4 packet to be sent to the ethernet device. Returns 1 if no
 * packet should be sent, 0 if the packet must be re-queued, 2 if the packet
 * is ready to go.
F
Fabien Chouteau 已提交
770
 */
771 772
static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
        uint8_t ethaddr[ETH_ALEN])
B
bellard 已提交
773
{
F
Fabien Chouteau 已提交
774
    const struct ip *iph = (const struct ip *)ifm->m_data;
B
bellard 已提交
775

776 777 778 779 780
    if (iph->ip_dst.s_addr == 0) {
        /* 0.0.0.0 can not be a destination address, something went wrong,
         * avoid making it worse */
        return 1;
    }
F
Fabien Chouteau 已提交
781
    if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
782 783 784 785
        uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
        struct ethhdr *reh = (struct ethhdr *)arp_req;
        struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);

786
        if (!ifm->resolution_requested) {
F
Fabien Chouteau 已提交
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
            /* If the client addr is not known, send an ARP request */
            memset(reh->h_dest, 0xff, ETH_ALEN);
            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
            memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
            reh->h_proto = htons(ETH_P_ARP);
            rah->ar_hrd = htons(1);
            rah->ar_pro = htons(ETH_P_IP);
            rah->ar_hln = ETH_ALEN;
            rah->ar_pln = 4;
            rah->ar_op = htons(ARPOP_REQUEST);

            /* source hw addr */
            memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
            memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);

            /* source IP */
            rah->ar_sip = slirp->vhost_addr.s_addr;

            /* target hw addr (none) */
            memset(rah->ar_tha, 0, ETH_ALEN);

            /* target IP */
            rah->ar_tip = iph->ip_dst.s_addr;
            slirp->client_ipaddr = iph->ip_dst;
            slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
812
            ifm->resolution_requested = true;
813 814

            /* Expire request and drop outgoing packet after 1 second */
815
            ifm->expiration_date = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL;
F
Fabien Chouteau 已提交
816 817
        }
        return 0;
818
    } else {
819
        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
820
        /* XXX: not correct */
821
        memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
822
        eh->h_proto = htons(ETH_P_IP);
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840

        /* Send this */
        return 2;
    }
}

/* Output the IP packet to the ethernet device. Returns 0 if the packet must be
 * re-queued.
 */
int if_encap(Slirp *slirp, struct mbuf *ifm)
{
    uint8_t buf[1600];
    struct ethhdr *eh = (struct ethhdr *)buf;
    uint8_t ethaddr[ETH_ALEN];
    const struct ip *iph = (const struct ip *)ifm->m_data;
    int ret;

    if (ifm->m_len + ETH_HLEN > sizeof(buf)) {
F
Fabien Chouteau 已提交
841
        return 1;
842
    }
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867

    switch (iph->ip_v) {
    case IPVERSION:
        ret = if_encap4(slirp, ifm, eh, ethaddr);
        if (ret < 2) {
            return ret;
        }
        break;

    default:
        /* Do not assert while we don't manage IP6VERSION */
        /* assert(0); */
        break;
    }

    memcpy(eh->h_dest, ethaddr, ETH_ALEN);
    DEBUG_ARGS((dfd, " src = %02x:%02x:%02x:%02x:%02x:%02x\n",
                eh->h_source[0], eh->h_source[1], eh->h_source[2],
                eh->h_source[3], eh->h_source[4], eh->h_source[5]));
    DEBUG_ARGS((dfd, " dst = %02x:%02x:%02x:%02x:%02x:%02x\n",
                eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
                eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]));
    memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
    slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
    return 1;
B
bellard 已提交
868
}
B
bellard 已提交
869

870
/* Drop host forwarding rule, return 0 if found. */
871 872
int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
                         int host_port)
873 874
{
    struct socket *so;
875
    struct socket *head = (is_udp ? &slirp->udb : &slirp->tcb);
876 877 878
    struct sockaddr_in addr;
    int port = htons(host_port);
    socklen_t addr_len;
879 880

    for (so = head->so_next; so != head; so = so->so_next) {
881
        addr_len = sizeof(addr);
882 883
        if ((so->so_state & SS_HOSTFWD) &&
            getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
884
            addr.sin_addr.s_addr == host_addr.s_addr &&
885
            addr.sin_port == port) {
886 887
            close(so->s);
            sofree(so);
888
            return 0;
889 890 891
        }
    }

892
    return -1;
893 894
}

895 896
int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
                      int host_port, struct in_addr guest_addr, int guest_port)
B
bellard 已提交
897
{
898
    if (!guest_addr.s_addr) {
899
        guest_addr = slirp->vdhcp_startaddr;
900
    }
B
bellard 已提交
901
    if (is_udp) {
902 903
        if (!udp_listen(slirp, host_addr.s_addr, htons(host_port),
                        guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
B
bellard 已提交
904 905
            return -1;
    } else {
906 907
        if (!tcp_listen(slirp, host_addr.s_addr, htons(host_port),
                        guest_addr.s_addr, htons(guest_port), SS_HOSTFWD))
B
bellard 已提交
908 909 910 911
            return -1;
    }
    return 0;
}
B
bellard 已提交
912

913
int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
914
                   struct in_addr *guest_addr, int guest_port)
B
bellard 已提交
915
{
916 917
    if (!guest_addr->s_addr) {
        guest_addr->s_addr = slirp->vnetwork_addr.s_addr |
918
            (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr);
919
    }
920
    if ((guest_addr->s_addr & slirp->vnetwork_mask.s_addr) !=
921
        slirp->vnetwork_addr.s_addr ||
922 923
        guest_addr->s_addr == slirp->vhost_addr.s_addr ||
        guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
924 925
        return -1;
    }
926
    return add_exec(&slirp->exec_list, do_pty, (char *)args, *guest_addr,
927
                    htons(guest_port));
B
bellard 已提交
928
}
929 930 931

ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
{
932 933 934 935
    if (so->s == -1 && so->extra) {
        qemu_chr_fe_write(so->extra, buf, len);
        return len;
    }
936

937
    return send(so->s, buf, len, flags);
938 939
}

940
static struct socket *
941
slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port)
942
{
943
    struct socket *so;
944

945
    for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so->so_next) {
946 947 948 949 950 951
        if (so->so_faddr.s_addr == guest_addr.s_addr &&
            htons(so->so_fport) == guest_port) {
            return so;
        }
    }
    return NULL;
952 953
}

954 955
size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
                             int guest_port)
956
{
957 958
    struct iovec iov[2];
    struct socket *so;
959

960
    so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
961

962 963 964
    if (!so || so->so_state & SS_NOFDREF) {
        return 0;
    }
965

966 967 968
    if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2)) {
        return 0;
    }
969

970
    return sopreprbuf(so, iov, NULL);
971 972
}

973
void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
974
                       const uint8_t *buf, int size)
975 976
{
    int ret;
977
    struct socket *so = slirp_find_ctl_socket(slirp, guest_addr, guest_port);
978

979 980 981
    if (!so)
        return;

B
blueswir1 已提交
982
    ret = soreadbuf(so, (const char *)buf, size);
983 984 985 986

    if (ret > 0)
        tcp_output(sototcpcb(so));
}
987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050

static void slirp_tcp_save(QEMUFile *f, struct tcpcb *tp)
{
    int i;

    qemu_put_sbe16(f, tp->t_state);
    for (i = 0; i < TCPT_NTIMERS; i++)
        qemu_put_sbe16(f, tp->t_timer[i]);
    qemu_put_sbe16(f, tp->t_rxtshift);
    qemu_put_sbe16(f, tp->t_rxtcur);
    qemu_put_sbe16(f, tp->t_dupacks);
    qemu_put_be16(f, tp->t_maxseg);
    qemu_put_sbyte(f, tp->t_force);
    qemu_put_be16(f, tp->t_flags);
    qemu_put_be32(f, tp->snd_una);
    qemu_put_be32(f, tp->snd_nxt);
    qemu_put_be32(f, tp->snd_up);
    qemu_put_be32(f, tp->snd_wl1);
    qemu_put_be32(f, tp->snd_wl2);
    qemu_put_be32(f, tp->iss);
    qemu_put_be32(f, tp->snd_wnd);
    qemu_put_be32(f, tp->rcv_wnd);
    qemu_put_be32(f, tp->rcv_nxt);
    qemu_put_be32(f, tp->rcv_up);
    qemu_put_be32(f, tp->irs);
    qemu_put_be32(f, tp->rcv_adv);
    qemu_put_be32(f, tp->snd_max);
    qemu_put_be32(f, tp->snd_cwnd);
    qemu_put_be32(f, tp->snd_ssthresh);
    qemu_put_sbe16(f, tp->t_idle);
    qemu_put_sbe16(f, tp->t_rtt);
    qemu_put_be32(f, tp->t_rtseq);
    qemu_put_sbe16(f, tp->t_srtt);
    qemu_put_sbe16(f, tp->t_rttvar);
    qemu_put_be16(f, tp->t_rttmin);
    qemu_put_be32(f, tp->max_sndwnd);
    qemu_put_byte(f, tp->t_oobflags);
    qemu_put_byte(f, tp->t_iobc);
    qemu_put_sbe16(f, tp->t_softerror);
    qemu_put_byte(f, tp->snd_scale);
    qemu_put_byte(f, tp->rcv_scale);
    qemu_put_byte(f, tp->request_r_scale);
    qemu_put_byte(f, tp->requested_s_scale);
    qemu_put_be32(f, tp->ts_recent);
    qemu_put_be32(f, tp->ts_recent_age);
    qemu_put_be32(f, tp->last_ack_sent);
}

static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf)
{
    uint32_t off;

    qemu_put_be32(f, sbuf->sb_cc);
    qemu_put_be32(f, sbuf->sb_datalen);
    off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data);
    qemu_put_sbe32(f, off);
    off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data);
    qemu_put_sbe32(f, off);
    qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
}

static void slirp_socket_save(QEMUFile *f, struct socket *so)
{
    qemu_put_be32(f, so->so_urgc);
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
    qemu_put_be16(f, so->so_ffamily);
    switch (so->so_ffamily) {
    case AF_INET:
        qemu_put_be32(f, so->so_faddr.s_addr);
        qemu_put_be16(f, so->so_fport);
        break;
    default:
        error_report(
                "so_ffamily unknown, unable to save so_faddr and so_fport\n");
    }
    qemu_put_be16(f, so->so_lfamily);
    switch (so->so_lfamily) {
    case AF_INET:
        qemu_put_be32(f, so->so_laddr.s_addr);
        qemu_put_be16(f, so->so_lport);
        break;
    default:
        error_report(
                "so_ffamily unknown, unable to save so_laddr and so_lport\n");
    }
1071 1072 1073 1074 1075 1076 1077 1078 1079
    qemu_put_byte(f, so->so_iptos);
    qemu_put_byte(f, so->so_emu);
    qemu_put_byte(f, so->so_type);
    qemu_put_be32(f, so->so_state);
    slirp_sbuf_save(f, &so->so_rcv);
    slirp_sbuf_save(f, &so->so_snd);
    slirp_tcp_save(f, so->so_tcpcb);
}

1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
static void slirp_bootp_save(QEMUFile *f, Slirp *slirp)
{
    int i;

    for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
        qemu_put_be16(f, slirp->bootp_clients[i].allocated);
        qemu_put_buffer(f, slirp->bootp_clients[i].macaddr, 6);
    }
}

1090 1091
static void slirp_state_save(QEMUFile *f, void *opaque)
{
1092
    Slirp *slirp = opaque;
1093 1094
    struct ex_list *ex_ptr;

1095
    for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
1096 1097
        if (ex_ptr->ex_pty == 3) {
            struct socket *so;
1098 1099
            so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
                                       ntohs(ex_ptr->ex_fport));
1100 1101 1102 1103 1104 1105 1106
            if (!so)
                continue;

            qemu_put_byte(f, 42);
            slirp_socket_save(f, so);
        }
    qemu_put_byte(f, 0);
J
Jan Kiszka 已提交
1107

1108
    qemu_put_be16(f, slirp->ip_id);
1109 1110

    slirp_bootp_save(f, slirp);
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189
}

static void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp)
{
    int i;

    tp->t_state = qemu_get_sbe16(f);
    for (i = 0; i < TCPT_NTIMERS; i++)
        tp->t_timer[i] = qemu_get_sbe16(f);
    tp->t_rxtshift = qemu_get_sbe16(f);
    tp->t_rxtcur = qemu_get_sbe16(f);
    tp->t_dupacks = qemu_get_sbe16(f);
    tp->t_maxseg = qemu_get_be16(f);
    tp->t_force = qemu_get_sbyte(f);
    tp->t_flags = qemu_get_be16(f);
    tp->snd_una = qemu_get_be32(f);
    tp->snd_nxt = qemu_get_be32(f);
    tp->snd_up = qemu_get_be32(f);
    tp->snd_wl1 = qemu_get_be32(f);
    tp->snd_wl2 = qemu_get_be32(f);
    tp->iss = qemu_get_be32(f);
    tp->snd_wnd = qemu_get_be32(f);
    tp->rcv_wnd = qemu_get_be32(f);
    tp->rcv_nxt = qemu_get_be32(f);
    tp->rcv_up = qemu_get_be32(f);
    tp->irs = qemu_get_be32(f);
    tp->rcv_adv = qemu_get_be32(f);
    tp->snd_max = qemu_get_be32(f);
    tp->snd_cwnd = qemu_get_be32(f);
    tp->snd_ssthresh = qemu_get_be32(f);
    tp->t_idle = qemu_get_sbe16(f);
    tp->t_rtt = qemu_get_sbe16(f);
    tp->t_rtseq = qemu_get_be32(f);
    tp->t_srtt = qemu_get_sbe16(f);
    tp->t_rttvar = qemu_get_sbe16(f);
    tp->t_rttmin = qemu_get_be16(f);
    tp->max_sndwnd = qemu_get_be32(f);
    tp->t_oobflags = qemu_get_byte(f);
    tp->t_iobc = qemu_get_byte(f);
    tp->t_softerror = qemu_get_sbe16(f);
    tp->snd_scale = qemu_get_byte(f);
    tp->rcv_scale = qemu_get_byte(f);
    tp->request_r_scale = qemu_get_byte(f);
    tp->requested_s_scale = qemu_get_byte(f);
    tp->ts_recent = qemu_get_be32(f);
    tp->ts_recent_age = qemu_get_be32(f);
    tp->last_ack_sent = qemu_get_be32(f);
    tcp_template(tp);
}

static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf)
{
    uint32_t off, sb_cc, sb_datalen;

    sb_cc = qemu_get_be32(f);
    sb_datalen = qemu_get_be32(f);

    sbreserve(sbuf, sb_datalen);

    if (sbuf->sb_datalen != sb_datalen)
        return -ENOMEM;

    sbuf->sb_cc = sb_cc;

    off = qemu_get_sbe32(f);
    sbuf->sb_wptr = sbuf->sb_data + off;
    off = qemu_get_sbe32(f);
    sbuf->sb_rptr = sbuf->sb_data + off;
    qemu_get_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);

    return 0;
}

static int slirp_socket_load(QEMUFile *f, struct socket *so)
{
    if (tcp_attach(so) < 0)
        return -ENOMEM;

    so->so_urgc = qemu_get_be32(f);
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
    so->so_ffamily = qemu_get_be16(f);
    switch (so->so_ffamily) {
    case AF_INET:
        so->so_faddr.s_addr = qemu_get_be32(f);
        so->so_fport = qemu_get_be16(f);
        break;
    default:
        error_report(
                "so_ffamily unknown, unable to restore so_faddr and so_lport\n");
    }
    so->so_lfamily = qemu_get_be16(f);
    switch (so->so_lfamily) {
    case AF_INET:
        so->so_laddr.s_addr = qemu_get_be32(f);
        so->so_lport = qemu_get_be16(f);
        break;
    default:
        error_report(
                "so_ffamily unknown, unable to restore so_laddr and so_lport\n");
    }
1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
    so->so_iptos = qemu_get_byte(f);
    so->so_emu = qemu_get_byte(f);
    so->so_type = qemu_get_byte(f);
    so->so_state = qemu_get_be32(f);
    if (slirp_sbuf_load(f, &so->so_rcv) < 0)
        return -ENOMEM;
    if (slirp_sbuf_load(f, &so->so_snd) < 0)
        return -ENOMEM;
    slirp_tcp_load(f, so->so_tcpcb);

    return 0;
}

1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
static void slirp_bootp_load(QEMUFile *f, Slirp *slirp)
{
    int i;

    for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
        slirp->bootp_clients[i].allocated = qemu_get_be16(f);
        qemu_get_buffer(f, slirp->bootp_clients[i].macaddr, 6);
    }
}

1233 1234
static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
{
1235
    Slirp *slirp = opaque;
1236 1237
    struct ex_list *ex_ptr;

1238
    while (qemu_get_byte(f)) {
1239
        int ret;
1240
        struct socket *so = socreate(slirp);
1241 1242 1243 1244 1245 1246 1247 1248 1249

        if (!so)
            return -ENOMEM;

        ret = slirp_socket_load(f, so);

        if (ret < 0)
            return ret;

1250 1251
        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) !=
            slirp->vnetwork_addr.s_addr) {
1252
            return -EINVAL;
1253
        }
1254
        for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
1255
            if (ex_ptr->ex_pty == 3 &&
1256 1257
                so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
                so->so_fport == ex_ptr->ex_fport) {
1258
                break;
1259 1260
            }
        }
1261 1262 1263
        if (!ex_ptr)
            return -EINVAL;

B
blueswir1 已提交
1264
        so->extra = (void *)ex_ptr->ex_exec;
1265 1266
    }

J
Jan Kiszka 已提交
1267
    if (version_id >= 2) {
1268
        slirp->ip_id = qemu_get_be16(f);
J
Jan Kiszka 已提交
1269 1270
    }

1271 1272 1273 1274
    if (version_id >= 3) {
        slirp_bootp_load(f, slirp);
    }

1275 1276
    return 0;
}