qemu/net/slirp.c
<<
>>
Prefs
   1/*
   2 * QEMU System Emulator
   3 *
   4 * Copyright (c) 2003-2008 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24#include "net/slirp.h"
  25
  26#include "config-host.h"
  27
  28#ifndef _WIN32
  29#include <sys/wait.h>
  30#endif
  31#include "net.h"
  32#include "monitor.h"
  33#include "sysemu.h"
  34#include "qemu_socket.h"
  35#include "slirp/libslirp.h"
  36
  37static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
  38{
  39    const char *p, *p1;
  40    int len;
  41    p = *pp;
  42    p1 = strchr(p, sep);
  43    if (!p1)
  44        return -1;
  45    len = p1 - p;
  46    p1++;
  47    if (buf_size > 0) {
  48        if (len > buf_size - 1)
  49            len = buf_size - 1;
  50        memcpy(buf, p, len);
  51        buf[len] = '\0';
  52    }
  53    *pp = p1;
  54    return 0;
  55}
  56
  57/* slirp network adapter */
  58
  59#define SLIRP_CFG_HOSTFWD 1
  60#define SLIRP_CFG_LEGACY  2
  61
  62struct slirp_config_str {
  63    struct slirp_config_str *next;
  64    int flags;
  65    char str[1024];
  66    int legacy_format;
  67};
  68
  69typedef struct SlirpState {
  70    VLANClientState nc;
  71    QTAILQ_ENTRY(SlirpState) entry;
  72    Slirp *slirp;
  73#ifndef _WIN32
  74    char smb_dir[128];
  75#endif
  76} SlirpState;
  77
  78static struct slirp_config_str *slirp_configs;
  79const char *legacy_tftp_prefix;
  80const char *legacy_bootp_filename;
  81static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks =
  82    QTAILQ_HEAD_INITIALIZER(slirp_stacks);
  83
  84static int slirp_hostfwd(SlirpState *s, const char *redir_str,
  85                         int legacy_format);
  86static int slirp_guestfwd(SlirpState *s, const char *config_str,
  87                          int legacy_format);
  88
  89#ifndef _WIN32
  90static const char *legacy_smb_export;
  91
  92static int slirp_smb(SlirpState *s, const char *exported_dir,
  93                     struct in_addr vserver_addr);
  94static void slirp_smb_cleanup(SlirpState *s);
  95#else
  96static inline void slirp_smb_cleanup(SlirpState *s) { }
  97#endif
  98
  99int slirp_can_output(void *opaque)
 100{
 101    SlirpState *s = opaque;
 102
 103    return qemu_can_send_packet(&s->nc);
 104}
 105
 106void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len)
 107{
 108    SlirpState *s = opaque;
 109
 110    qemu_send_packet(&s->nc, pkt, pkt_len);
 111}
 112
 113static ssize_t net_slirp_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
 114{
 115    SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
 116
 117    slirp_input(s->slirp, buf, size);
 118
 119    return size;
 120}
 121
 122static void net_slirp_cleanup(VLANClientState *nc)
 123{
 124    SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
 125
 126    slirp_cleanup(s->slirp);
 127    slirp_smb_cleanup(s);
 128    QTAILQ_REMOVE(&slirp_stacks, s, entry);
 129}
 130
 131static NetClientInfo net_slirp_info = {
 132    .type = NET_CLIENT_TYPE_SLIRP,
 133    .size = sizeof(SlirpState),
 134    .receive = net_slirp_receive,
 135    .cleanup = net_slirp_cleanup,
 136};
 137
 138static int net_slirp_init(VLANState *vlan, const char *model,
 139                          const char *name, int restricted,
 140                          const char *vnetwork, const char *vhost,
 141                          const char *vhostname, const char *tftp_export,
 142                          const char *bootfile, const char *vdhcp_start,
 143                          const char *vnameserver, const char *smb_export,
 144                          const char *vsmbserver)
 145{
 146    /* default settings according to historic slirp */
 147    struct in_addr net  = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
 148    struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
 149    struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
 150    struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
 151    struct in_addr dns  = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
 152#ifndef _WIN32
 153    struct in_addr smbsrv = { .s_addr = 0 };
 154#endif
 155    VLANClientState *nc;
 156    SlirpState *s;
 157    char buf[20];
 158    uint32_t addr;
 159    int shift;
 160    char *end;
 161    struct slirp_config_str *config;
 162
 163    if (!tftp_export) {
 164        tftp_export = legacy_tftp_prefix;
 165    }
 166    if (!bootfile) {
 167        bootfile = legacy_bootp_filename;
 168    }
 169
 170    if (vnetwork) {
 171        if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) {
 172            if (!inet_aton(vnetwork, &net)) {
 173                return -1;
 174            }
 175            addr = ntohl(net.s_addr);
 176            if (!(addr & 0x80000000)) {
 177                mask.s_addr = htonl(0xff000000); /* class A */
 178            } else if ((addr & 0xfff00000) == 0xac100000) {
 179                mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */
 180            } else if ((addr & 0xc0000000) == 0x80000000) {
 181                mask.s_addr = htonl(0xffff0000); /* class B */
 182            } else if ((addr & 0xffff0000) == 0xc0a80000) {
 183                mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */
 184            } else if ((addr & 0xffff0000) == 0xc6120000) {
 185                mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */
 186            } else if ((addr & 0xe0000000) == 0xe0000000) {
 187                mask.s_addr = htonl(0xffffff00); /* class C */
 188            } else {
 189                mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */
 190            }
 191        } else {
 192            if (!inet_aton(buf, &net)) {
 193                return -1;
 194            }
 195            shift = strtol(vnetwork, &end, 10);
 196            if (*end != '\0') {
 197                if (!inet_aton(vnetwork, &mask)) {
 198                    return -1;
 199                }
 200            } else if (shift < 4 || shift > 32) {
 201                return -1;
 202            } else {
 203                mask.s_addr = htonl(0xffffffff << (32 - shift));
 204            }
 205        }
 206        net.s_addr &= mask.s_addr;
 207        host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr);
 208        dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr);
 209        dns.s_addr  = net.s_addr | (htonl(0x0203) & ~mask.s_addr);
 210    }
 211
 212    if (vhost && !inet_aton(vhost, &host)) {
 213        return -1;
 214    }
 215    if ((host.s_addr & mask.s_addr) != net.s_addr) {
 216        return -1;
 217    }
 218
 219    if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) {
 220        return -1;
 221    }
 222    if ((dhcp.s_addr & mask.s_addr) != net.s_addr ||
 223        dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) {
 224        return -1;
 225    }
 226
 227    if (vnameserver && !inet_aton(vnameserver, &dns)) {
 228        return -1;
 229    }
 230    if ((dns.s_addr & mask.s_addr) != net.s_addr ||
 231        dns.s_addr == host.s_addr) {
 232        return -1;
 233    }
 234
 235#ifndef _WIN32
 236    if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
 237        return -1;
 238    }
 239#endif
 240
 241    nc = qemu_new_net_client(&net_slirp_info, vlan, NULL, model, name);
 242
 243    snprintf(nc->info_str, sizeof(nc->info_str),
 244             "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n');
 245
 246    s = DO_UPCAST(SlirpState, nc, nc);
 247
 248    s->slirp = slirp_init(restricted, net, mask, host, vhostname,
 249                          tftp_export, bootfile, dhcp, dns, s);
 250    QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
 251
 252    for (config = slirp_configs; config; config = config->next) {
 253        if (config->flags & SLIRP_CFG_HOSTFWD) {
 254            if (slirp_hostfwd(s, config->str,
 255                              config->flags & SLIRP_CFG_LEGACY) < 0)
 256                goto error;
 257        } else {
 258            if (slirp_guestfwd(s, config->str,
 259                               config->flags & SLIRP_CFG_LEGACY) < 0)
 260                goto error;
 261        }
 262    }
 263#ifndef _WIN32
 264    if (!smb_export) {
 265        smb_export = legacy_smb_export;
 266    }
 267    if (smb_export) {
 268        if (slirp_smb(s, smb_export, smbsrv) < 0)
 269            goto error;
 270    }
 271#endif
 272
 273    return 0;
 274
 275error:
 276    qemu_del_vlan_client(nc);
 277    return -1;
 278}
 279
 280static SlirpState *slirp_lookup(Monitor *mon, const char *vlan,
 281                                const char *stack)
 282{
 283
 284    if (vlan) {
 285        VLANClientState *nc;
 286        nc = qemu_find_vlan_client_by_name(mon, strtol(vlan, NULL, 0), stack);
 287        if (!nc) {
 288            return NULL;
 289        }
 290        if (strcmp(nc->model, "user")) {
 291            monitor_printf(mon, "invalid device specified\n");
 292            return NULL;
 293        }
 294        return DO_UPCAST(SlirpState, nc, nc);
 295    } else {
 296        if (QTAILQ_EMPTY(&slirp_stacks)) {
 297            monitor_printf(mon, "user mode network stack not in use\n");
 298            return NULL;
 299        }
 300        return QTAILQ_FIRST(&slirp_stacks);
 301    }
 302}
 303
 304void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict)
 305{
 306    struct in_addr host_addr = { .s_addr = INADDR_ANY };
 307    int host_port;
 308    char buf[256] = "";
 309    const char *src_str, *p;
 310    SlirpState *s;
 311    int is_udp = 0;
 312    int err;
 313    const char *arg1 = qdict_get_str(qdict, "arg1");
 314    const char *arg2 = qdict_get_try_str(qdict, "arg2");
 315    const char *arg3 = qdict_get_try_str(qdict, "arg3");
 316
 317    if (arg2) {
 318        s = slirp_lookup(mon, arg1, arg2);
 319        src_str = arg3;
 320    } else {
 321        s = slirp_lookup(mon, NULL, NULL);
 322        src_str = arg1;
 323    }
 324    if (!s) {
 325        return;
 326    }
 327
 328    if (!src_str || !src_str[0])
 329        goto fail_syntax;
 330
 331    p = src_str;
 332    get_str_sep(buf, sizeof(buf), &p, ':');
 333
 334    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
 335        is_udp = 0;
 336    } else if (!strcmp(buf, "udp")) {
 337        is_udp = 1;
 338    } else {
 339        goto fail_syntax;
 340    }
 341
 342    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 343        goto fail_syntax;
 344    }
 345    if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
 346        goto fail_syntax;
 347    }
 348
 349    host_port = atoi(p);
 350
 351    err = slirp_remove_hostfwd(QTAILQ_FIRST(&slirp_stacks)->slirp, is_udp,
 352                               host_addr, host_port);
 353
 354    monitor_printf(mon, "host forwarding rule for %s %s\n", src_str,
 355                   err ? "removed" : "not found");
 356    return;
 357
 358 fail_syntax:
 359    monitor_printf(mon, "invalid format\n");
 360}
 361
 362static int slirp_hostfwd(SlirpState *s, const char *redir_str,
 363                         int legacy_format)
 364{
 365    struct in_addr host_addr = { .s_addr = INADDR_ANY };
 366    struct in_addr guest_addr = { .s_addr = 0 };
 367    int host_port, guest_port;
 368    const char *p;
 369    char buf[256];
 370    int is_udp;
 371    char *end;
 372
 373    p = redir_str;
 374    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 375        goto fail_syntax;
 376    }
 377    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
 378        is_udp = 0;
 379    } else if (!strcmp(buf, "udp")) {
 380        is_udp = 1;
 381    } else {
 382        goto fail_syntax;
 383    }
 384
 385    if (!legacy_format) {
 386        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 387            goto fail_syntax;
 388        }
 389        if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
 390            goto fail_syntax;
 391        }
 392    }
 393
 394    if (get_str_sep(buf, sizeof(buf), &p, legacy_format ? ':' : '-') < 0) {
 395        goto fail_syntax;
 396    }
 397    host_port = strtol(buf, &end, 0);
 398    if (*end != '\0' || host_port < 1 || host_port > 65535) {
 399        goto fail_syntax;
 400    }
 401
 402    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 403        goto fail_syntax;
 404    }
 405    if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) {
 406        goto fail_syntax;
 407    }
 408
 409    guest_port = strtol(p, &end, 0);
 410    if (*end != '\0' || guest_port < 1 || guest_port > 65535) {
 411        goto fail_syntax;
 412    }
 413
 414    if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr,
 415                          guest_port) < 0) {
 416        error_report("could not set up host forwarding rule '%s'",
 417                     redir_str);
 418        return -1;
 419    }
 420    return 0;
 421
 422 fail_syntax:
 423    error_report("invalid host forwarding rule '%s'", redir_str);
 424    return -1;
 425}
 426
 427void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict)
 428{
 429    const char *redir_str;
 430    SlirpState *s;
 431    const char *arg1 = qdict_get_str(qdict, "arg1");
 432    const char *arg2 = qdict_get_try_str(qdict, "arg2");
 433    const char *arg3 = qdict_get_try_str(qdict, "arg3");
 434
 435    if (arg2) {
 436        s = slirp_lookup(mon, arg1, arg2);
 437        redir_str = arg3;
 438    } else {
 439        s = slirp_lookup(mon, NULL, NULL);
 440        redir_str = arg1;
 441    }
 442    if (s) {
 443        slirp_hostfwd(s, redir_str, 0);
 444    }
 445
 446}
 447
 448int net_slirp_redir(const char *redir_str)
 449{
 450    struct slirp_config_str *config;
 451
 452    if (QTAILQ_EMPTY(&slirp_stacks)) {
 453        config = qemu_malloc(sizeof(*config));
 454        pstrcpy(config->str, sizeof(config->str), redir_str);
 455        config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY;
 456        config->next = slirp_configs;
 457        slirp_configs = config;
 458        return 0;
 459    }
 460
 461    return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1);
 462}
 463
 464#ifndef _WIN32
 465
 466/* automatic user mode samba server configuration */
 467static void slirp_smb_cleanup(SlirpState *s)
 468{
 469    char cmd[128];
 470    int ret;
 471
 472    if (s->smb_dir[0] != '\0') {
 473        snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir);
 474        ret = system(cmd);
 475        if (ret == -1 || !WIFEXITED(ret)) {
 476            error_report("'%s' failed.", cmd);
 477        } else if (WEXITSTATUS(ret)) {
 478            error_report("'%s' failed. Error code: %d",
 479                         cmd, WEXITSTATUS(ret));
 480        }
 481        s->smb_dir[0] = '\0';
 482    }
 483}
 484
 485static int slirp_smb(SlirpState* s, const char *exported_dir,
 486                     struct in_addr vserver_addr)
 487{
 488    static int instance;
 489    char smb_conf[128];
 490    char smb_cmdline[128];
 491    FILE *f;
 492
 493    snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d",
 494             (long)getpid(), instance++);
 495    if (mkdir(s->smb_dir, 0700) < 0) {
 496        error_report("could not create samba server dir '%s'", s->smb_dir);
 497        return -1;
 498    }
 499    snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf");
 500
 501    f = fopen(smb_conf, "w");
 502    if (!f) {
 503        slirp_smb_cleanup(s);
 504        error_report("could not create samba server configuration file '%s'",
 505                     smb_conf);
 506        return -1;
 507    }
 508    fprintf(f,
 509            "[global]\n"
 510            "private dir=%s\n"
 511            "smb ports=0\n"
 512            "socket address=127.0.0.1\n"
 513            "pid directory=%s\n"
 514            "lock directory=%s\n"
 515            "log file=%s/log.smbd\n"
 516            "smb passwd file=%s/smbpasswd\n"
 517            "security = share\n"
 518            "[qemu]\n"
 519            "path=%s\n"
 520            "read only=no\n"
 521            "guest ok=yes\n",
 522            s->smb_dir,
 523            s->smb_dir,
 524            s->smb_dir,
 525            s->smb_dir,
 526            s->smb_dir,
 527            exported_dir
 528            );
 529    fclose(f);
 530
 531    snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
 532             SMBD_COMMAND, smb_conf);
 533
 534    if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) {
 535        slirp_smb_cleanup(s);
 536        error_report("conflicting/invalid smbserver address");
 537        return -1;
 538    }
 539    return 0;
 540}
 541
 542/* automatic user mode samba server configuration (legacy interface) */
 543int net_slirp_smb(const char *exported_dir)
 544{
 545    struct in_addr vserver_addr = { .s_addr = 0 };
 546
 547    if (legacy_smb_export) {
 548        fprintf(stderr, "-smb given twice\n");
 549        return -1;
 550    }
 551    legacy_smb_export = exported_dir;
 552    if (!QTAILQ_EMPTY(&slirp_stacks)) {
 553        return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir,
 554                         vserver_addr);
 555    }
 556    return 0;
 557}
 558
 559#endif /* !defined(_WIN32) */
 560
 561struct GuestFwd {
 562    CharDriverState *hd;
 563    struct in_addr server;
 564    int port;
 565    Slirp *slirp;
 566};
 567
 568static int guestfwd_can_read(void *opaque)
 569{
 570    struct GuestFwd *fwd = opaque;
 571    return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port);
 572}
 573
 574static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
 575{
 576    struct GuestFwd *fwd = opaque;
 577    slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size);
 578}
 579
 580static int slirp_guestfwd(SlirpState *s, const char *config_str,
 581                          int legacy_format)
 582{
 583    struct in_addr server = { .s_addr = 0 };
 584    struct GuestFwd *fwd;
 585    const char *p;
 586    char buf[128];
 587    char *end;
 588    int port;
 589
 590    p = config_str;
 591    if (legacy_format) {
 592        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 593            goto fail_syntax;
 594        }
 595    } else {
 596        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 597            goto fail_syntax;
 598        }
 599        if (strcmp(buf, "tcp") && buf[0] != '\0') {
 600            goto fail_syntax;
 601        }
 602        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
 603            goto fail_syntax;
 604        }
 605        if (buf[0] != '\0' && !inet_aton(buf, &server)) {
 606            goto fail_syntax;
 607        }
 608        if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
 609            goto fail_syntax;
 610        }
 611    }
 612    port = strtol(buf, &end, 10);
 613    if (*end != '\0' || port < 1 || port > 65535) {
 614        goto fail_syntax;
 615    }
 616
 617    fwd = qemu_malloc(sizeof(struct GuestFwd));
 618    snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port);
 619    fwd->hd = qemu_chr_open(buf, p, NULL);
 620    if (!fwd->hd) {
 621        error_report("could not open guest forwarding device '%s'", buf);
 622        qemu_free(fwd);
 623        return -1;
 624    }
 625
 626    if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) {
 627        error_report("conflicting/invalid host:port in guest forwarding "
 628                     "rule '%s'", config_str);
 629        qemu_free(fwd);
 630        return -1;
 631    }
 632    fwd->server = server;
 633    fwd->port = port;
 634    fwd->slirp = s->slirp;
 635
 636    qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
 637                          NULL, fwd);
 638    return 0;
 639
 640 fail_syntax:
 641    error_report("invalid guest forwarding rule '%s'", config_str);
 642    return -1;
 643}
 644
 645void do_info_usernet(Monitor *mon)
 646{
 647    SlirpState *s;
 648
 649    QTAILQ_FOREACH(s, &slirp_stacks, entry) {
 650        monitor_printf(mon, "VLAN %d (%s):\n",
 651                       s->nc.vlan ? s->nc.vlan->id : -1,
 652                       s->nc.name);
 653        slirp_connection_info(s->slirp, mon);
 654    }
 655}
 656
 657static int net_init_slirp_configs(const char *name, const char *value, void *opaque)
 658{
 659    struct slirp_config_str *config;
 660
 661    if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) {
 662        return 0;
 663    }
 664
 665    config = qemu_mallocz(sizeof(*config));
 666
 667    pstrcpy(config->str, sizeof(config->str), value);
 668
 669    if (!strcmp(name, "hostfwd")) {
 670        config->flags = SLIRP_CFG_HOSTFWD;
 671    }
 672
 673    config->next = slirp_configs;
 674    slirp_configs = config;
 675
 676    return 0;
 677}
 678
 679int net_init_slirp(QemuOpts *opts,
 680                   Monitor *mon,
 681                   const char *name,
 682                   VLANState *vlan)
 683{
 684    struct slirp_config_str *config;
 685    const char *vhost;
 686    const char *vhostname;
 687    const char *vdhcp_start;
 688    const char *vnamesrv;
 689    const char *tftp_export;
 690    const char *bootfile;
 691    const char *smb_export;
 692    const char *vsmbsrv;
 693    char *vnet = NULL;
 694    int restricted = 0;
 695    int ret;
 696
 697    vhost       = qemu_opt_get(opts, "host");
 698    vhostname   = qemu_opt_get(opts, "hostname");
 699    vdhcp_start = qemu_opt_get(opts, "dhcpstart");
 700    vnamesrv    = qemu_opt_get(opts, "dns");
 701    tftp_export = qemu_opt_get(opts, "tftp");
 702    bootfile    = qemu_opt_get(opts, "bootfile");
 703    smb_export  = qemu_opt_get(opts, "smb");
 704    vsmbsrv     = qemu_opt_get(opts, "smbserver");
 705
 706    if (qemu_opt_get(opts, "ip")) {
 707        const char *ip = qemu_opt_get(opts, "ip");
 708        int l = strlen(ip) + strlen("/24") + 1;
 709
 710        vnet = qemu_malloc(l);
 711
 712        /* emulate legacy ip= parameter */
 713        pstrcpy(vnet, l, ip);
 714        pstrcat(vnet, l, "/24");
 715    }
 716
 717    if (qemu_opt_get(opts, "net")) {
 718        if (vnet) {
 719            qemu_free(vnet);
 720        }
 721        vnet = qemu_strdup(qemu_opt_get(opts, "net"));
 722    }
 723
 724    if (qemu_opt_get(opts, "restrict") &&
 725        qemu_opt_get(opts, "restrict")[0] == 'y') {
 726        restricted = 1;
 727    }
 728
 729    qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0);
 730
 731    ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost,
 732                         vhostname, tftp_export, bootfile, vdhcp_start,
 733                         vnamesrv, smb_export, vsmbsrv);
 734
 735    while (slirp_configs) {
 736        config = slirp_configs;
 737        slirp_configs = config->next;
 738        qemu_free(config);
 739    }
 740
 741    qemu_free(vnet);
 742
 743    return ret;
 744}
 745
 746int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret)
 747{
 748    if (strcmp(opts_list->name, "net") != 0 ||
 749        strncmp(optarg, "channel,", strlen("channel,")) != 0) {
 750        return 0;
 751    }
 752
 753    /* handle legacy -net channel,port:chr */
 754    optarg += strlen("channel,");
 755
 756    if (QTAILQ_EMPTY(&slirp_stacks)) {
 757        struct slirp_config_str *config;
 758
 759        config = qemu_malloc(sizeof(*config));
 760        pstrcpy(config->str, sizeof(config->str), optarg);
 761        config->flags = SLIRP_CFG_LEGACY;
 762        config->next = slirp_configs;
 763        slirp_configs = config;
 764        *ret = 0;
 765    } else {
 766        *ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1);
 767    }
 768
 769    return 1;
 770}
 771
 772