168ac40d2SMark McLoughlin /* 268ac40d2SMark McLoughlin * QEMU System Emulator 368ac40d2SMark McLoughlin * 468ac40d2SMark McLoughlin * Copyright (c) 2003-2008 Fabrice Bellard 568ac40d2SMark McLoughlin * 668ac40d2SMark McLoughlin * Permission is hereby granted, free of charge, to any person obtaining a copy 768ac40d2SMark McLoughlin * of this software and associated documentation files (the "Software"), to deal 868ac40d2SMark McLoughlin * in the Software without restriction, including without limitation the rights 968ac40d2SMark McLoughlin * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 1068ac40d2SMark McLoughlin * copies of the Software, and to permit persons to whom the Software is 1168ac40d2SMark McLoughlin * furnished to do so, subject to the following conditions: 1268ac40d2SMark McLoughlin * 1368ac40d2SMark McLoughlin * The above copyright notice and this permission notice shall be included in 1468ac40d2SMark McLoughlin * all copies or substantial portions of the Software. 1568ac40d2SMark McLoughlin * 1668ac40d2SMark McLoughlin * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1768ac40d2SMark McLoughlin * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1868ac40d2SMark McLoughlin * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1968ac40d2SMark McLoughlin * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2068ac40d2SMark McLoughlin * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2168ac40d2SMark McLoughlin * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 2268ac40d2SMark McLoughlin * THE SOFTWARE. 2368ac40d2SMark McLoughlin */ 2468ac40d2SMark McLoughlin #include "net/slirp.h" 2568ac40d2SMark McLoughlin 2668ac40d2SMark McLoughlin #include "config-host.h" 2768ac40d2SMark McLoughlin 2868ac40d2SMark McLoughlin #include "net.h" 2968ac40d2SMark McLoughlin #include "monitor.h" 3068ac40d2SMark McLoughlin #include "sysemu.h" 3168ac40d2SMark McLoughlin #include "qemu_socket.h" 3268ac40d2SMark McLoughlin #include "slirp/libslirp.h" 3368ac40d2SMark McLoughlin 3468ac40d2SMark McLoughlin static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) 3568ac40d2SMark McLoughlin { 3668ac40d2SMark McLoughlin const char *p, *p1; 3768ac40d2SMark McLoughlin int len; 3868ac40d2SMark McLoughlin p = *pp; 3968ac40d2SMark McLoughlin p1 = strchr(p, sep); 4068ac40d2SMark McLoughlin if (!p1) 4168ac40d2SMark McLoughlin return -1; 4268ac40d2SMark McLoughlin len = p1 - p; 4368ac40d2SMark McLoughlin p1++; 4468ac40d2SMark McLoughlin if (buf_size > 0) { 4568ac40d2SMark McLoughlin if (len > buf_size - 1) 4668ac40d2SMark McLoughlin len = buf_size - 1; 4768ac40d2SMark McLoughlin memcpy(buf, p, len); 4868ac40d2SMark McLoughlin buf[len] = '\0'; 4968ac40d2SMark McLoughlin } 5068ac40d2SMark McLoughlin *pp = p1; 5168ac40d2SMark McLoughlin return 0; 5268ac40d2SMark McLoughlin } 5368ac40d2SMark McLoughlin 5468ac40d2SMark McLoughlin /* slirp network adapter */ 5568ac40d2SMark McLoughlin 5668ac40d2SMark McLoughlin #define SLIRP_CFG_HOSTFWD 1 5768ac40d2SMark McLoughlin #define SLIRP_CFG_LEGACY 2 5868ac40d2SMark McLoughlin 5968ac40d2SMark McLoughlin struct slirp_config_str { 6068ac40d2SMark McLoughlin struct slirp_config_str *next; 6168ac40d2SMark McLoughlin int flags; 6268ac40d2SMark McLoughlin char str[1024]; 6368ac40d2SMark McLoughlin int legacy_format; 6468ac40d2SMark McLoughlin }; 6568ac40d2SMark McLoughlin 6668ac40d2SMark McLoughlin typedef struct SlirpState { 67ce20b5beSMark McLoughlin VLANClientState nc; 6868ac40d2SMark McLoughlin QTAILQ_ENTRY(SlirpState) entry; 6968ac40d2SMark McLoughlin Slirp *slirp; 7068ac40d2SMark McLoughlin #ifndef _WIN32 7168ac40d2SMark McLoughlin char smb_dir[128]; 7268ac40d2SMark McLoughlin #endif 7368ac40d2SMark McLoughlin } SlirpState; 7468ac40d2SMark McLoughlin 7568ac40d2SMark McLoughlin static struct slirp_config_str *slirp_configs; 7668ac40d2SMark McLoughlin const char *legacy_tftp_prefix; 7768ac40d2SMark McLoughlin const char *legacy_bootp_filename; 7868ac40d2SMark McLoughlin static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks = 7968ac40d2SMark McLoughlin QTAILQ_HEAD_INITIALIZER(slirp_stacks); 8068ac40d2SMark McLoughlin 8168ac40d2SMark McLoughlin static int slirp_hostfwd(SlirpState *s, const char *redir_str, 8268ac40d2SMark McLoughlin int legacy_format); 8368ac40d2SMark McLoughlin static int slirp_guestfwd(SlirpState *s, const char *config_str, 8468ac40d2SMark McLoughlin int legacy_format); 8568ac40d2SMark McLoughlin 8668ac40d2SMark McLoughlin #ifndef _WIN32 8768ac40d2SMark McLoughlin static const char *legacy_smb_export; 8868ac40d2SMark McLoughlin 8968ac40d2SMark McLoughlin static int slirp_smb(SlirpState *s, const char *exported_dir, 9068ac40d2SMark McLoughlin struct in_addr vserver_addr); 9168ac40d2SMark McLoughlin static void slirp_smb_cleanup(SlirpState *s); 9268ac40d2SMark McLoughlin #else 9368ac40d2SMark McLoughlin static inline void slirp_smb_cleanup(SlirpState *s) { } 9468ac40d2SMark McLoughlin #endif 9568ac40d2SMark McLoughlin 9668ac40d2SMark McLoughlin int slirp_can_output(void *opaque) 9768ac40d2SMark McLoughlin { 9868ac40d2SMark McLoughlin SlirpState *s = opaque; 9968ac40d2SMark McLoughlin 100ce20b5beSMark McLoughlin return qemu_can_send_packet(&s->nc); 10168ac40d2SMark McLoughlin } 10268ac40d2SMark McLoughlin 10368ac40d2SMark McLoughlin void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len) 10468ac40d2SMark McLoughlin { 10568ac40d2SMark McLoughlin SlirpState *s = opaque; 10668ac40d2SMark McLoughlin 107ce20b5beSMark McLoughlin qemu_send_packet(&s->nc, pkt, pkt_len); 10868ac40d2SMark McLoughlin } 10968ac40d2SMark McLoughlin 110ce20b5beSMark McLoughlin static ssize_t net_slirp_receive(VLANClientState *nc, const uint8_t *buf, size_t size) 11168ac40d2SMark McLoughlin { 112ce20b5beSMark McLoughlin SlirpState *s = DO_UPCAST(SlirpState, nc, nc); 11368ac40d2SMark McLoughlin 11468ac40d2SMark McLoughlin slirp_input(s->slirp, buf, size); 11568ac40d2SMark McLoughlin 11668ac40d2SMark McLoughlin return size; 11768ac40d2SMark McLoughlin } 11868ac40d2SMark McLoughlin 119ce20b5beSMark McLoughlin static void net_slirp_cleanup(VLANClientState *nc) 12068ac40d2SMark McLoughlin { 121ce20b5beSMark McLoughlin SlirpState *s = DO_UPCAST(SlirpState, nc, nc); 12268ac40d2SMark McLoughlin 12368ac40d2SMark McLoughlin slirp_cleanup(s->slirp); 12468ac40d2SMark McLoughlin slirp_smb_cleanup(s); 12568ac40d2SMark McLoughlin QTAILQ_REMOVE(&slirp_stacks, s, entry); 12668ac40d2SMark McLoughlin } 12768ac40d2SMark McLoughlin 128ce20b5beSMark McLoughlin static NetClientInfo net_slirp_info = { 129ce20b5beSMark McLoughlin .type = NET_CLIENT_TYPE_SLIRP, 130ce20b5beSMark McLoughlin .size = sizeof(SlirpState), 131ce20b5beSMark McLoughlin .receive = net_slirp_receive, 132ce20b5beSMark McLoughlin .cleanup = net_slirp_cleanup, 133ce20b5beSMark McLoughlin }; 134ce20b5beSMark McLoughlin 13568ac40d2SMark McLoughlin static int net_slirp_init(VLANState *vlan, const char *model, 13668ac40d2SMark McLoughlin const char *name, int restricted, 13768ac40d2SMark McLoughlin const char *vnetwork, const char *vhost, 13868ac40d2SMark McLoughlin const char *vhostname, const char *tftp_export, 13968ac40d2SMark McLoughlin const char *bootfile, const char *vdhcp_start, 14068ac40d2SMark McLoughlin const char *vnameserver, const char *smb_export, 14168ac40d2SMark McLoughlin const char *vsmbserver) 14268ac40d2SMark McLoughlin { 14368ac40d2SMark McLoughlin /* default settings according to historic slirp */ 14468ac40d2SMark McLoughlin struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */ 14568ac40d2SMark McLoughlin struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */ 14668ac40d2SMark McLoughlin struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */ 14768ac40d2SMark McLoughlin struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */ 14868ac40d2SMark McLoughlin struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */ 14968ac40d2SMark McLoughlin #ifndef _WIN32 15068ac40d2SMark McLoughlin struct in_addr smbsrv = { .s_addr = 0 }; 15168ac40d2SMark McLoughlin #endif 152ce20b5beSMark McLoughlin VLANClientState *nc; 15368ac40d2SMark McLoughlin SlirpState *s; 15468ac40d2SMark McLoughlin char buf[20]; 15568ac40d2SMark McLoughlin uint32_t addr; 15668ac40d2SMark McLoughlin int shift; 15768ac40d2SMark McLoughlin char *end; 15868ac40d2SMark McLoughlin struct slirp_config_str *config; 15968ac40d2SMark McLoughlin 16068ac40d2SMark McLoughlin if (!tftp_export) { 16168ac40d2SMark McLoughlin tftp_export = legacy_tftp_prefix; 16268ac40d2SMark McLoughlin } 16368ac40d2SMark McLoughlin if (!bootfile) { 16468ac40d2SMark McLoughlin bootfile = legacy_bootp_filename; 16568ac40d2SMark McLoughlin } 16668ac40d2SMark McLoughlin 16768ac40d2SMark McLoughlin if (vnetwork) { 16868ac40d2SMark McLoughlin if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) { 16968ac40d2SMark McLoughlin if (!inet_aton(vnetwork, &net)) { 17068ac40d2SMark McLoughlin return -1; 17168ac40d2SMark McLoughlin } 17268ac40d2SMark McLoughlin addr = ntohl(net.s_addr); 17368ac40d2SMark McLoughlin if (!(addr & 0x80000000)) { 17468ac40d2SMark McLoughlin mask.s_addr = htonl(0xff000000); /* class A */ 17568ac40d2SMark McLoughlin } else if ((addr & 0xfff00000) == 0xac100000) { 17668ac40d2SMark McLoughlin mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */ 17768ac40d2SMark McLoughlin } else if ((addr & 0xc0000000) == 0x80000000) { 17868ac40d2SMark McLoughlin mask.s_addr = htonl(0xffff0000); /* class B */ 17968ac40d2SMark McLoughlin } else if ((addr & 0xffff0000) == 0xc0a80000) { 18068ac40d2SMark McLoughlin mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */ 18168ac40d2SMark McLoughlin } else if ((addr & 0xffff0000) == 0xc6120000) { 18268ac40d2SMark McLoughlin mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */ 18368ac40d2SMark McLoughlin } else if ((addr & 0xe0000000) == 0xe0000000) { 18468ac40d2SMark McLoughlin mask.s_addr = htonl(0xffffff00); /* class C */ 18568ac40d2SMark McLoughlin } else { 18668ac40d2SMark McLoughlin mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */ 18768ac40d2SMark McLoughlin } 18868ac40d2SMark McLoughlin } else { 18968ac40d2SMark McLoughlin if (!inet_aton(buf, &net)) { 19068ac40d2SMark McLoughlin return -1; 19168ac40d2SMark McLoughlin } 19268ac40d2SMark McLoughlin shift = strtol(vnetwork, &end, 10); 19368ac40d2SMark McLoughlin if (*end != '\0') { 19468ac40d2SMark McLoughlin if (!inet_aton(vnetwork, &mask)) { 19568ac40d2SMark McLoughlin return -1; 19668ac40d2SMark McLoughlin } 19768ac40d2SMark McLoughlin } else if (shift < 4 || shift > 32) { 19868ac40d2SMark McLoughlin return -1; 19968ac40d2SMark McLoughlin } else { 20068ac40d2SMark McLoughlin mask.s_addr = htonl(0xffffffff << (32 - shift)); 20168ac40d2SMark McLoughlin } 20268ac40d2SMark McLoughlin } 20368ac40d2SMark McLoughlin net.s_addr &= mask.s_addr; 20468ac40d2SMark McLoughlin host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr); 20568ac40d2SMark McLoughlin dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr); 20668ac40d2SMark McLoughlin dns.s_addr = net.s_addr | (htonl(0x0203) & ~mask.s_addr); 20768ac40d2SMark McLoughlin } 20868ac40d2SMark McLoughlin 20968ac40d2SMark McLoughlin if (vhost && !inet_aton(vhost, &host)) { 21068ac40d2SMark McLoughlin return -1; 21168ac40d2SMark McLoughlin } 21268ac40d2SMark McLoughlin if ((host.s_addr & mask.s_addr) != net.s_addr) { 21368ac40d2SMark McLoughlin return -1; 21468ac40d2SMark McLoughlin } 21568ac40d2SMark McLoughlin 21668ac40d2SMark McLoughlin if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) { 21768ac40d2SMark McLoughlin return -1; 21868ac40d2SMark McLoughlin } 21968ac40d2SMark McLoughlin if ((dhcp.s_addr & mask.s_addr) != net.s_addr || 22068ac40d2SMark McLoughlin dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) { 22168ac40d2SMark McLoughlin return -1; 22268ac40d2SMark McLoughlin } 22368ac40d2SMark McLoughlin 22468ac40d2SMark McLoughlin if (vnameserver && !inet_aton(vnameserver, &dns)) { 22568ac40d2SMark McLoughlin return -1; 22668ac40d2SMark McLoughlin } 22768ac40d2SMark McLoughlin if ((dns.s_addr & mask.s_addr) != net.s_addr || 22868ac40d2SMark McLoughlin dns.s_addr == host.s_addr) { 22968ac40d2SMark McLoughlin return -1; 23068ac40d2SMark McLoughlin } 23168ac40d2SMark McLoughlin 23268ac40d2SMark McLoughlin #ifndef _WIN32 23368ac40d2SMark McLoughlin if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) { 23468ac40d2SMark McLoughlin return -1; 23568ac40d2SMark McLoughlin } 23668ac40d2SMark McLoughlin #endif 23768ac40d2SMark McLoughlin 238ce20b5beSMark McLoughlin nc = qemu_new_net_client(&net_slirp_info, vlan, NULL, model, name); 239ce20b5beSMark McLoughlin 240ce20b5beSMark McLoughlin snprintf(nc->info_str, sizeof(nc->info_str), 241ce20b5beSMark McLoughlin "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n'); 242ce20b5beSMark McLoughlin 243ce20b5beSMark McLoughlin s = DO_UPCAST(SlirpState, nc, nc); 244ce20b5beSMark McLoughlin 24568ac40d2SMark McLoughlin s->slirp = slirp_init(restricted, net, mask, host, vhostname, 24668ac40d2SMark McLoughlin tftp_export, bootfile, dhcp, dns, s); 24768ac40d2SMark McLoughlin QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry); 24868ac40d2SMark McLoughlin 24968ac40d2SMark McLoughlin for (config = slirp_configs; config; config = config->next) { 25068ac40d2SMark McLoughlin if (config->flags & SLIRP_CFG_HOSTFWD) { 25168ac40d2SMark McLoughlin if (slirp_hostfwd(s, config->str, 25268ac40d2SMark McLoughlin config->flags & SLIRP_CFG_LEGACY) < 0) 253ce20b5beSMark McLoughlin goto error; 25468ac40d2SMark McLoughlin } else { 25568ac40d2SMark McLoughlin if (slirp_guestfwd(s, config->str, 25668ac40d2SMark McLoughlin config->flags & SLIRP_CFG_LEGACY) < 0) 257ce20b5beSMark McLoughlin goto error; 25868ac40d2SMark McLoughlin } 25968ac40d2SMark McLoughlin } 26068ac40d2SMark McLoughlin #ifndef _WIN32 26168ac40d2SMark McLoughlin if (!smb_export) { 26268ac40d2SMark McLoughlin smb_export = legacy_smb_export; 26368ac40d2SMark McLoughlin } 26468ac40d2SMark McLoughlin if (smb_export) { 26568ac40d2SMark McLoughlin if (slirp_smb(s, smb_export, smbsrv) < 0) 266ce20b5beSMark McLoughlin goto error; 26768ac40d2SMark McLoughlin } 26868ac40d2SMark McLoughlin #endif 26968ac40d2SMark McLoughlin 27068ac40d2SMark McLoughlin return 0; 271ce20b5beSMark McLoughlin 272ce20b5beSMark McLoughlin error: 273ce20b5beSMark McLoughlin qemu_del_vlan_client(nc); 274ce20b5beSMark McLoughlin return -1; 27568ac40d2SMark McLoughlin } 27668ac40d2SMark McLoughlin 27768ac40d2SMark McLoughlin static SlirpState *slirp_lookup(Monitor *mon, const char *vlan, 27868ac40d2SMark McLoughlin const char *stack) 27968ac40d2SMark McLoughlin { 28068ac40d2SMark McLoughlin 28168ac40d2SMark McLoughlin if (vlan) { 282ce20b5beSMark McLoughlin VLANClientState *nc; 283ce20b5beSMark McLoughlin nc = qemu_find_vlan_client_by_name(mon, strtol(vlan, NULL, 0), stack); 284ce20b5beSMark McLoughlin if (!nc) { 28568ac40d2SMark McLoughlin return NULL; 28668ac40d2SMark McLoughlin } 287ce20b5beSMark McLoughlin if (strcmp(nc->model, "user")) { 28868ac40d2SMark McLoughlin monitor_printf(mon, "invalid device specified\n"); 28968ac40d2SMark McLoughlin return NULL; 29068ac40d2SMark McLoughlin } 291ce20b5beSMark McLoughlin return DO_UPCAST(SlirpState, nc, nc); 29268ac40d2SMark McLoughlin } else { 29368ac40d2SMark McLoughlin if (QTAILQ_EMPTY(&slirp_stacks)) { 29468ac40d2SMark McLoughlin monitor_printf(mon, "user mode network stack not in use\n"); 29568ac40d2SMark McLoughlin return NULL; 29668ac40d2SMark McLoughlin } 29768ac40d2SMark McLoughlin return QTAILQ_FIRST(&slirp_stacks); 29868ac40d2SMark McLoughlin } 29968ac40d2SMark McLoughlin } 30068ac40d2SMark McLoughlin 30168ac40d2SMark McLoughlin void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict) 30268ac40d2SMark McLoughlin { 30368ac40d2SMark McLoughlin struct in_addr host_addr = { .s_addr = INADDR_ANY }; 30468ac40d2SMark McLoughlin int host_port; 30568ac40d2SMark McLoughlin char buf[256] = ""; 30668ac40d2SMark McLoughlin const char *src_str, *p; 30768ac40d2SMark McLoughlin SlirpState *s; 30868ac40d2SMark McLoughlin int is_udp = 0; 30968ac40d2SMark McLoughlin int err; 31068ac40d2SMark McLoughlin const char *arg1 = qdict_get_str(qdict, "arg1"); 31168ac40d2SMark McLoughlin const char *arg2 = qdict_get_try_str(qdict, "arg2"); 31268ac40d2SMark McLoughlin const char *arg3 = qdict_get_try_str(qdict, "arg3"); 31368ac40d2SMark McLoughlin 31468ac40d2SMark McLoughlin if (arg2) { 31568ac40d2SMark McLoughlin s = slirp_lookup(mon, arg1, arg2); 31668ac40d2SMark McLoughlin src_str = arg3; 31768ac40d2SMark McLoughlin } else { 31868ac40d2SMark McLoughlin s = slirp_lookup(mon, NULL, NULL); 31968ac40d2SMark McLoughlin src_str = arg1; 32068ac40d2SMark McLoughlin } 32168ac40d2SMark McLoughlin if (!s) { 32268ac40d2SMark McLoughlin return; 32368ac40d2SMark McLoughlin } 32468ac40d2SMark McLoughlin 32568ac40d2SMark McLoughlin if (!src_str || !src_str[0]) 32668ac40d2SMark McLoughlin goto fail_syntax; 32768ac40d2SMark McLoughlin 32868ac40d2SMark McLoughlin p = src_str; 32968ac40d2SMark McLoughlin get_str_sep(buf, sizeof(buf), &p, ':'); 33068ac40d2SMark McLoughlin 33168ac40d2SMark McLoughlin if (!strcmp(buf, "tcp") || buf[0] == '\0') { 33268ac40d2SMark McLoughlin is_udp = 0; 33368ac40d2SMark McLoughlin } else if (!strcmp(buf, "udp")) { 33468ac40d2SMark McLoughlin is_udp = 1; 33568ac40d2SMark McLoughlin } else { 33668ac40d2SMark McLoughlin goto fail_syntax; 33768ac40d2SMark McLoughlin } 33868ac40d2SMark McLoughlin 33968ac40d2SMark McLoughlin if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { 34068ac40d2SMark McLoughlin goto fail_syntax; 34168ac40d2SMark McLoughlin } 34268ac40d2SMark McLoughlin if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { 34368ac40d2SMark McLoughlin goto fail_syntax; 34468ac40d2SMark McLoughlin } 34568ac40d2SMark McLoughlin 34668ac40d2SMark McLoughlin host_port = atoi(p); 34768ac40d2SMark McLoughlin 34868ac40d2SMark McLoughlin err = slirp_remove_hostfwd(QTAILQ_FIRST(&slirp_stacks)->slirp, is_udp, 34968ac40d2SMark McLoughlin host_addr, host_port); 35068ac40d2SMark McLoughlin 35168ac40d2SMark McLoughlin monitor_printf(mon, "host forwarding rule for %s %s\n", src_str, 35268ac40d2SMark McLoughlin err ? "removed" : "not found"); 35368ac40d2SMark McLoughlin return; 35468ac40d2SMark McLoughlin 35568ac40d2SMark McLoughlin fail_syntax: 35668ac40d2SMark McLoughlin monitor_printf(mon, "invalid format\n"); 35768ac40d2SMark McLoughlin } 35868ac40d2SMark McLoughlin 35968ac40d2SMark McLoughlin static int slirp_hostfwd(SlirpState *s, const char *redir_str, 36068ac40d2SMark McLoughlin int legacy_format) 36168ac40d2SMark McLoughlin { 36268ac40d2SMark McLoughlin struct in_addr host_addr = { .s_addr = INADDR_ANY }; 36368ac40d2SMark McLoughlin struct in_addr guest_addr = { .s_addr = 0 }; 36468ac40d2SMark McLoughlin int host_port, guest_port; 36568ac40d2SMark McLoughlin const char *p; 36668ac40d2SMark McLoughlin char buf[256]; 36768ac40d2SMark McLoughlin int is_udp; 36868ac40d2SMark McLoughlin char *end; 36968ac40d2SMark McLoughlin 37068ac40d2SMark McLoughlin p = redir_str; 37168ac40d2SMark McLoughlin if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) { 37268ac40d2SMark McLoughlin goto fail_syntax; 37368ac40d2SMark McLoughlin } 37468ac40d2SMark McLoughlin if (!strcmp(buf, "tcp") || buf[0] == '\0') { 37568ac40d2SMark McLoughlin is_udp = 0; 37668ac40d2SMark McLoughlin } else if (!strcmp(buf, "udp")) { 37768ac40d2SMark McLoughlin is_udp = 1; 37868ac40d2SMark McLoughlin } else { 37968ac40d2SMark McLoughlin goto fail_syntax; 38068ac40d2SMark McLoughlin } 38168ac40d2SMark McLoughlin 38268ac40d2SMark McLoughlin if (!legacy_format) { 38368ac40d2SMark McLoughlin if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { 38468ac40d2SMark McLoughlin goto fail_syntax; 38568ac40d2SMark McLoughlin } 38668ac40d2SMark McLoughlin if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) { 38768ac40d2SMark McLoughlin goto fail_syntax; 38868ac40d2SMark McLoughlin } 38968ac40d2SMark McLoughlin } 39068ac40d2SMark McLoughlin 39168ac40d2SMark McLoughlin if (get_str_sep(buf, sizeof(buf), &p, legacy_format ? ':' : '-') < 0) { 39268ac40d2SMark McLoughlin goto fail_syntax; 39368ac40d2SMark McLoughlin } 39468ac40d2SMark McLoughlin host_port = strtol(buf, &end, 0); 39568ac40d2SMark McLoughlin if (*end != '\0' || host_port < 1 || host_port > 65535) { 39668ac40d2SMark McLoughlin goto fail_syntax; 39768ac40d2SMark McLoughlin } 39868ac40d2SMark McLoughlin 39968ac40d2SMark McLoughlin if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { 40068ac40d2SMark McLoughlin goto fail_syntax; 40168ac40d2SMark McLoughlin } 40268ac40d2SMark McLoughlin if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) { 40368ac40d2SMark McLoughlin goto fail_syntax; 40468ac40d2SMark McLoughlin } 40568ac40d2SMark McLoughlin 40668ac40d2SMark McLoughlin guest_port = strtol(p, &end, 0); 40768ac40d2SMark McLoughlin if (*end != '\0' || guest_port < 1 || guest_port > 65535) { 40868ac40d2SMark McLoughlin goto fail_syntax; 40968ac40d2SMark McLoughlin } 41068ac40d2SMark McLoughlin 41168ac40d2SMark McLoughlin if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr, 41268ac40d2SMark McLoughlin guest_port) < 0) { 41368ac40d2SMark McLoughlin qemu_error("could not set up host forwarding rule '%s'\n", 41468ac40d2SMark McLoughlin redir_str); 41568ac40d2SMark McLoughlin return -1; 41668ac40d2SMark McLoughlin } 41768ac40d2SMark McLoughlin return 0; 41868ac40d2SMark McLoughlin 41968ac40d2SMark McLoughlin fail_syntax: 42068ac40d2SMark McLoughlin qemu_error("invalid host forwarding rule '%s'\n", redir_str); 42168ac40d2SMark McLoughlin return -1; 42268ac40d2SMark McLoughlin } 42368ac40d2SMark McLoughlin 42468ac40d2SMark McLoughlin void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict) 42568ac40d2SMark McLoughlin { 42668ac40d2SMark McLoughlin const char *redir_str; 42768ac40d2SMark McLoughlin SlirpState *s; 42868ac40d2SMark McLoughlin const char *arg1 = qdict_get_str(qdict, "arg1"); 42968ac40d2SMark McLoughlin const char *arg2 = qdict_get_try_str(qdict, "arg2"); 43068ac40d2SMark McLoughlin const char *arg3 = qdict_get_try_str(qdict, "arg3"); 43168ac40d2SMark McLoughlin 43268ac40d2SMark McLoughlin if (arg2) { 43368ac40d2SMark McLoughlin s = slirp_lookup(mon, arg1, arg2); 43468ac40d2SMark McLoughlin redir_str = arg3; 43568ac40d2SMark McLoughlin } else { 43668ac40d2SMark McLoughlin s = slirp_lookup(mon, NULL, NULL); 43768ac40d2SMark McLoughlin redir_str = arg1; 43868ac40d2SMark McLoughlin } 43968ac40d2SMark McLoughlin if (s) { 44068ac40d2SMark McLoughlin slirp_hostfwd(s, redir_str, 0); 44168ac40d2SMark McLoughlin } 44268ac40d2SMark McLoughlin 44368ac40d2SMark McLoughlin } 44468ac40d2SMark McLoughlin 44568ac40d2SMark McLoughlin int net_slirp_redir(const char *redir_str) 44668ac40d2SMark McLoughlin { 44768ac40d2SMark McLoughlin struct slirp_config_str *config; 44868ac40d2SMark McLoughlin 44968ac40d2SMark McLoughlin if (QTAILQ_EMPTY(&slirp_stacks)) { 45068ac40d2SMark McLoughlin config = qemu_malloc(sizeof(*config)); 45168ac40d2SMark McLoughlin pstrcpy(config->str, sizeof(config->str), redir_str); 45268ac40d2SMark McLoughlin config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY; 45368ac40d2SMark McLoughlin config->next = slirp_configs; 45468ac40d2SMark McLoughlin slirp_configs = config; 45568ac40d2SMark McLoughlin return 0; 45668ac40d2SMark McLoughlin } 45768ac40d2SMark McLoughlin 45868ac40d2SMark McLoughlin return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1); 45968ac40d2SMark McLoughlin } 46068ac40d2SMark McLoughlin 46168ac40d2SMark McLoughlin #ifndef _WIN32 46268ac40d2SMark McLoughlin 46368ac40d2SMark McLoughlin /* automatic user mode samba server configuration */ 46468ac40d2SMark McLoughlin static void slirp_smb_cleanup(SlirpState *s) 46568ac40d2SMark McLoughlin { 46668ac40d2SMark McLoughlin char cmd[128]; 467*5a01e99fSKirill A. Shutemov int ret; 46868ac40d2SMark McLoughlin 46968ac40d2SMark McLoughlin if (s->smb_dir[0] != '\0') { 47068ac40d2SMark McLoughlin snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir); 471*5a01e99fSKirill A. Shutemov ret = system(cmd); 472*5a01e99fSKirill A. Shutemov if (!WIFEXITED(ret)) { 473*5a01e99fSKirill A. Shutemov qemu_error("'%s' failed.\n", cmd); 474*5a01e99fSKirill A. Shutemov } else if (WEXITSTATUS(ret)) { 475*5a01e99fSKirill A. Shutemov qemu_error("'%s' failed. Error code: %d\n", 476*5a01e99fSKirill A. Shutemov cmd, WEXITSTATUS(ret)); 477*5a01e99fSKirill A. Shutemov } 47868ac40d2SMark McLoughlin s->smb_dir[0] = '\0'; 47968ac40d2SMark McLoughlin } 48068ac40d2SMark McLoughlin } 48168ac40d2SMark McLoughlin 48268ac40d2SMark McLoughlin static int slirp_smb(SlirpState* s, const char *exported_dir, 48368ac40d2SMark McLoughlin struct in_addr vserver_addr) 48468ac40d2SMark McLoughlin { 48568ac40d2SMark McLoughlin static int instance; 48668ac40d2SMark McLoughlin char smb_conf[128]; 48768ac40d2SMark McLoughlin char smb_cmdline[128]; 48868ac40d2SMark McLoughlin FILE *f; 48968ac40d2SMark McLoughlin 49068ac40d2SMark McLoughlin snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d", 49168ac40d2SMark McLoughlin (long)getpid(), instance++); 49268ac40d2SMark McLoughlin if (mkdir(s->smb_dir, 0700) < 0) { 49368ac40d2SMark McLoughlin qemu_error("could not create samba server dir '%s'\n", s->smb_dir); 49468ac40d2SMark McLoughlin return -1; 49568ac40d2SMark McLoughlin } 49668ac40d2SMark McLoughlin snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf"); 49768ac40d2SMark McLoughlin 49868ac40d2SMark McLoughlin f = fopen(smb_conf, "w"); 49968ac40d2SMark McLoughlin if (!f) { 50068ac40d2SMark McLoughlin slirp_smb_cleanup(s); 50168ac40d2SMark McLoughlin qemu_error("could not create samba server configuration file '%s'\n", 50268ac40d2SMark McLoughlin smb_conf); 50368ac40d2SMark McLoughlin return -1; 50468ac40d2SMark McLoughlin } 50568ac40d2SMark McLoughlin fprintf(f, 50668ac40d2SMark McLoughlin "[global]\n" 50768ac40d2SMark McLoughlin "private dir=%s\n" 50868ac40d2SMark McLoughlin "smb ports=0\n" 50968ac40d2SMark McLoughlin "socket address=127.0.0.1\n" 51068ac40d2SMark McLoughlin "pid directory=%s\n" 51168ac40d2SMark McLoughlin "lock directory=%s\n" 51268ac40d2SMark McLoughlin "log file=%s/log.smbd\n" 51368ac40d2SMark McLoughlin "smb passwd file=%s/smbpasswd\n" 51468ac40d2SMark McLoughlin "security = share\n" 51568ac40d2SMark McLoughlin "[qemu]\n" 51668ac40d2SMark McLoughlin "path=%s\n" 51768ac40d2SMark McLoughlin "read only=no\n" 51868ac40d2SMark McLoughlin "guest ok=yes\n", 51968ac40d2SMark McLoughlin s->smb_dir, 52068ac40d2SMark McLoughlin s->smb_dir, 52168ac40d2SMark McLoughlin s->smb_dir, 52268ac40d2SMark McLoughlin s->smb_dir, 52368ac40d2SMark McLoughlin s->smb_dir, 52468ac40d2SMark McLoughlin exported_dir 52568ac40d2SMark McLoughlin ); 52668ac40d2SMark McLoughlin fclose(f); 52768ac40d2SMark McLoughlin 52868ac40d2SMark McLoughlin snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", 52968ac40d2SMark McLoughlin SMBD_COMMAND, smb_conf); 53068ac40d2SMark McLoughlin 53168ac40d2SMark McLoughlin if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) { 53268ac40d2SMark McLoughlin slirp_smb_cleanup(s); 53368ac40d2SMark McLoughlin qemu_error("conflicting/invalid smbserver address\n"); 53468ac40d2SMark McLoughlin return -1; 53568ac40d2SMark McLoughlin } 53668ac40d2SMark McLoughlin return 0; 53768ac40d2SMark McLoughlin } 53868ac40d2SMark McLoughlin 53968ac40d2SMark McLoughlin /* automatic user mode samba server configuration (legacy interface) */ 54068ac40d2SMark McLoughlin int net_slirp_smb(const char *exported_dir) 54168ac40d2SMark McLoughlin { 54268ac40d2SMark McLoughlin struct in_addr vserver_addr = { .s_addr = 0 }; 54368ac40d2SMark McLoughlin 54468ac40d2SMark McLoughlin if (legacy_smb_export) { 54568ac40d2SMark McLoughlin fprintf(stderr, "-smb given twice\n"); 54668ac40d2SMark McLoughlin return -1; 54768ac40d2SMark McLoughlin } 54868ac40d2SMark McLoughlin legacy_smb_export = exported_dir; 54968ac40d2SMark McLoughlin if (!QTAILQ_EMPTY(&slirp_stacks)) { 55068ac40d2SMark McLoughlin return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir, 55168ac40d2SMark McLoughlin vserver_addr); 55268ac40d2SMark McLoughlin } 55368ac40d2SMark McLoughlin return 0; 55468ac40d2SMark McLoughlin } 55568ac40d2SMark McLoughlin 55668ac40d2SMark McLoughlin #endif /* !defined(_WIN32) */ 55768ac40d2SMark McLoughlin 55868ac40d2SMark McLoughlin struct GuestFwd { 55968ac40d2SMark McLoughlin CharDriverState *hd; 56068ac40d2SMark McLoughlin struct in_addr server; 56168ac40d2SMark McLoughlin int port; 56268ac40d2SMark McLoughlin Slirp *slirp; 56368ac40d2SMark McLoughlin }; 56468ac40d2SMark McLoughlin 56568ac40d2SMark McLoughlin static int guestfwd_can_read(void *opaque) 56668ac40d2SMark McLoughlin { 56768ac40d2SMark McLoughlin struct GuestFwd *fwd = opaque; 56868ac40d2SMark McLoughlin return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port); 56968ac40d2SMark McLoughlin } 57068ac40d2SMark McLoughlin 57168ac40d2SMark McLoughlin static void guestfwd_read(void *opaque, const uint8_t *buf, int size) 57268ac40d2SMark McLoughlin { 57368ac40d2SMark McLoughlin struct GuestFwd *fwd = opaque; 57468ac40d2SMark McLoughlin slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size); 57568ac40d2SMark McLoughlin } 57668ac40d2SMark McLoughlin 57768ac40d2SMark McLoughlin static int slirp_guestfwd(SlirpState *s, const char *config_str, 57868ac40d2SMark McLoughlin int legacy_format) 57968ac40d2SMark McLoughlin { 58068ac40d2SMark McLoughlin struct in_addr server = { .s_addr = 0 }; 58168ac40d2SMark McLoughlin struct GuestFwd *fwd; 58268ac40d2SMark McLoughlin const char *p; 58368ac40d2SMark McLoughlin char buf[128]; 58468ac40d2SMark McLoughlin char *end; 58568ac40d2SMark McLoughlin int port; 58668ac40d2SMark McLoughlin 58768ac40d2SMark McLoughlin p = config_str; 58868ac40d2SMark McLoughlin if (legacy_format) { 58968ac40d2SMark McLoughlin if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { 59068ac40d2SMark McLoughlin goto fail_syntax; 59168ac40d2SMark McLoughlin } 59268ac40d2SMark McLoughlin } else { 59368ac40d2SMark McLoughlin if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { 59468ac40d2SMark McLoughlin goto fail_syntax; 59568ac40d2SMark McLoughlin } 59668ac40d2SMark McLoughlin if (strcmp(buf, "tcp") && buf[0] != '\0') { 59768ac40d2SMark McLoughlin goto fail_syntax; 59868ac40d2SMark McLoughlin } 59968ac40d2SMark McLoughlin if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { 60068ac40d2SMark McLoughlin goto fail_syntax; 60168ac40d2SMark McLoughlin } 60268ac40d2SMark McLoughlin if (buf[0] != '\0' && !inet_aton(buf, &server)) { 60368ac40d2SMark McLoughlin goto fail_syntax; 60468ac40d2SMark McLoughlin } 60568ac40d2SMark McLoughlin if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) { 60668ac40d2SMark McLoughlin goto fail_syntax; 60768ac40d2SMark McLoughlin } 60868ac40d2SMark McLoughlin } 60968ac40d2SMark McLoughlin port = strtol(buf, &end, 10); 61068ac40d2SMark McLoughlin if (*end != '\0' || port < 1 || port > 65535) { 61168ac40d2SMark McLoughlin goto fail_syntax; 61268ac40d2SMark McLoughlin } 61368ac40d2SMark McLoughlin 61468ac40d2SMark McLoughlin fwd = qemu_malloc(sizeof(struct GuestFwd)); 61568ac40d2SMark McLoughlin snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port); 61668ac40d2SMark McLoughlin fwd->hd = qemu_chr_open(buf, p, NULL); 61768ac40d2SMark McLoughlin if (!fwd->hd) { 61868ac40d2SMark McLoughlin qemu_error("could not open guest forwarding device '%s'\n", buf); 61968ac40d2SMark McLoughlin qemu_free(fwd); 62068ac40d2SMark McLoughlin return -1; 62168ac40d2SMark McLoughlin } 62268ac40d2SMark McLoughlin 62368ac40d2SMark McLoughlin if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) { 62468ac40d2SMark McLoughlin qemu_error("conflicting/invalid host:port in guest forwarding " 62568ac40d2SMark McLoughlin "rule '%s'\n", config_str); 62668ac40d2SMark McLoughlin qemu_free(fwd); 62768ac40d2SMark McLoughlin return -1; 62868ac40d2SMark McLoughlin } 62968ac40d2SMark McLoughlin fwd->server = server; 63068ac40d2SMark McLoughlin fwd->port = port; 63168ac40d2SMark McLoughlin fwd->slirp = s->slirp; 63268ac40d2SMark McLoughlin 63368ac40d2SMark McLoughlin qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, 63468ac40d2SMark McLoughlin NULL, fwd); 63568ac40d2SMark McLoughlin return 0; 63668ac40d2SMark McLoughlin 63768ac40d2SMark McLoughlin fail_syntax: 63868ac40d2SMark McLoughlin qemu_error("invalid guest forwarding rule '%s'\n", config_str); 63968ac40d2SMark McLoughlin return -1; 64068ac40d2SMark McLoughlin } 64168ac40d2SMark McLoughlin 64268ac40d2SMark McLoughlin void do_info_usernet(Monitor *mon) 64368ac40d2SMark McLoughlin { 64468ac40d2SMark McLoughlin SlirpState *s; 64568ac40d2SMark McLoughlin 64668ac40d2SMark McLoughlin QTAILQ_FOREACH(s, &slirp_stacks, entry) { 647ce20b5beSMark McLoughlin monitor_printf(mon, "VLAN %d (%s):\n", 648ce20b5beSMark McLoughlin s->nc.vlan ? s->nc.vlan->id : -1, 649ce20b5beSMark McLoughlin s->nc.name); 65068ac40d2SMark McLoughlin slirp_connection_info(s->slirp, mon); 65168ac40d2SMark McLoughlin } 65268ac40d2SMark McLoughlin } 65368ac40d2SMark McLoughlin 65468ac40d2SMark McLoughlin static int net_init_slirp_configs(const char *name, const char *value, void *opaque) 65568ac40d2SMark McLoughlin { 65668ac40d2SMark McLoughlin struct slirp_config_str *config; 65768ac40d2SMark McLoughlin 65868ac40d2SMark McLoughlin if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) { 65968ac40d2SMark McLoughlin return 0; 66068ac40d2SMark McLoughlin } 66168ac40d2SMark McLoughlin 66268ac40d2SMark McLoughlin config = qemu_mallocz(sizeof(*config)); 66368ac40d2SMark McLoughlin 66468ac40d2SMark McLoughlin pstrcpy(config->str, sizeof(config->str), value); 66568ac40d2SMark McLoughlin 66668ac40d2SMark McLoughlin if (!strcmp(name, "hostfwd")) { 66768ac40d2SMark McLoughlin config->flags = SLIRP_CFG_HOSTFWD; 66868ac40d2SMark McLoughlin } 66968ac40d2SMark McLoughlin 67068ac40d2SMark McLoughlin config->next = slirp_configs; 67168ac40d2SMark McLoughlin slirp_configs = config; 67268ac40d2SMark McLoughlin 67368ac40d2SMark McLoughlin return 0; 67468ac40d2SMark McLoughlin } 67568ac40d2SMark McLoughlin 67668ac40d2SMark McLoughlin int net_init_slirp(QemuOpts *opts, 67768ac40d2SMark McLoughlin Monitor *mon, 67868ac40d2SMark McLoughlin const char *name, 67968ac40d2SMark McLoughlin VLANState *vlan) 68068ac40d2SMark McLoughlin { 68168ac40d2SMark McLoughlin struct slirp_config_str *config; 68268ac40d2SMark McLoughlin const char *vhost; 68368ac40d2SMark McLoughlin const char *vhostname; 68468ac40d2SMark McLoughlin const char *vdhcp_start; 68568ac40d2SMark McLoughlin const char *vnamesrv; 68668ac40d2SMark McLoughlin const char *tftp_export; 68768ac40d2SMark McLoughlin const char *bootfile; 68868ac40d2SMark McLoughlin const char *smb_export; 68968ac40d2SMark McLoughlin const char *vsmbsrv; 69068ac40d2SMark McLoughlin char *vnet = NULL; 69168ac40d2SMark McLoughlin int restricted = 0; 69268ac40d2SMark McLoughlin int ret; 69368ac40d2SMark McLoughlin 69468ac40d2SMark McLoughlin vhost = qemu_opt_get(opts, "host"); 69568ac40d2SMark McLoughlin vhostname = qemu_opt_get(opts, "hostname"); 69668ac40d2SMark McLoughlin vdhcp_start = qemu_opt_get(opts, "dhcpstart"); 69768ac40d2SMark McLoughlin vnamesrv = qemu_opt_get(opts, "dns"); 69868ac40d2SMark McLoughlin tftp_export = qemu_opt_get(opts, "tftp"); 69968ac40d2SMark McLoughlin bootfile = qemu_opt_get(opts, "bootfile"); 70068ac40d2SMark McLoughlin smb_export = qemu_opt_get(opts, "smb"); 70168ac40d2SMark McLoughlin vsmbsrv = qemu_opt_get(opts, "smbserver"); 70268ac40d2SMark McLoughlin 70368ac40d2SMark McLoughlin if (qemu_opt_get(opts, "ip")) { 70468ac40d2SMark McLoughlin const char *ip = qemu_opt_get(opts, "ip"); 70568ac40d2SMark McLoughlin int l = strlen(ip) + strlen("/24") + 1; 70668ac40d2SMark McLoughlin 70768ac40d2SMark McLoughlin vnet = qemu_malloc(l); 70868ac40d2SMark McLoughlin 70968ac40d2SMark McLoughlin /* emulate legacy ip= parameter */ 71068ac40d2SMark McLoughlin pstrcpy(vnet, l, ip); 71168ac40d2SMark McLoughlin pstrcat(vnet, l, "/24"); 71268ac40d2SMark McLoughlin } 71368ac40d2SMark McLoughlin 71468ac40d2SMark McLoughlin if (qemu_opt_get(opts, "net")) { 71568ac40d2SMark McLoughlin if (vnet) { 71668ac40d2SMark McLoughlin qemu_free(vnet); 71768ac40d2SMark McLoughlin } 71868ac40d2SMark McLoughlin vnet = qemu_strdup(qemu_opt_get(opts, "net")); 71968ac40d2SMark McLoughlin } 72068ac40d2SMark McLoughlin 72168ac40d2SMark McLoughlin if (qemu_opt_get(opts, "restrict") && 72268ac40d2SMark McLoughlin qemu_opt_get(opts, "restrict")[0] == 'y') { 72368ac40d2SMark McLoughlin restricted = 1; 72468ac40d2SMark McLoughlin } 72568ac40d2SMark McLoughlin 72668ac40d2SMark McLoughlin qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0); 72768ac40d2SMark McLoughlin 72868ac40d2SMark McLoughlin ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost, 72968ac40d2SMark McLoughlin vhostname, tftp_export, bootfile, vdhcp_start, 73068ac40d2SMark McLoughlin vnamesrv, smb_export, vsmbsrv); 73168ac40d2SMark McLoughlin 73268ac40d2SMark McLoughlin while (slirp_configs) { 73368ac40d2SMark McLoughlin config = slirp_configs; 73468ac40d2SMark McLoughlin slirp_configs = config->next; 73568ac40d2SMark McLoughlin qemu_free(config); 73668ac40d2SMark McLoughlin } 73768ac40d2SMark McLoughlin 73868ac40d2SMark McLoughlin if (ret != -1 && vlan) { 73968ac40d2SMark McLoughlin vlan->nb_host_devs++; 74068ac40d2SMark McLoughlin } 74168ac40d2SMark McLoughlin 74268ac40d2SMark McLoughlin qemu_free(vnet); 74368ac40d2SMark McLoughlin 74468ac40d2SMark McLoughlin return ret; 74568ac40d2SMark McLoughlin } 74668ac40d2SMark McLoughlin 74768ac40d2SMark McLoughlin int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret) 74868ac40d2SMark McLoughlin { 74968ac40d2SMark McLoughlin if (strcmp(opts_list->name, "net") != 0 || 75068ac40d2SMark McLoughlin strncmp(optarg, "channel,", strlen("channel,")) != 0) { 75168ac40d2SMark McLoughlin return 0; 75268ac40d2SMark McLoughlin } 75368ac40d2SMark McLoughlin 75468ac40d2SMark McLoughlin /* handle legacy -net channel,port:chr */ 75568ac40d2SMark McLoughlin optarg += strlen("channel,"); 75668ac40d2SMark McLoughlin 75768ac40d2SMark McLoughlin if (QTAILQ_EMPTY(&slirp_stacks)) { 75868ac40d2SMark McLoughlin struct slirp_config_str *config; 75968ac40d2SMark McLoughlin 76068ac40d2SMark McLoughlin config = qemu_malloc(sizeof(*config)); 76168ac40d2SMark McLoughlin pstrcpy(config->str, sizeof(config->str), optarg); 76268ac40d2SMark McLoughlin config->flags = SLIRP_CFG_LEGACY; 76368ac40d2SMark McLoughlin config->next = slirp_configs; 76468ac40d2SMark McLoughlin slirp_configs = config; 76568ac40d2SMark McLoughlin *ret = 0; 76668ac40d2SMark McLoughlin } else { 76768ac40d2SMark McLoughlin *ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1); 76868ac40d2SMark McLoughlin } 76968ac40d2SMark McLoughlin 77068ac40d2SMark McLoughlin return 1; 77168ac40d2SMark McLoughlin } 77268ac40d2SMark McLoughlin 773