From: Mark McLoughlin <markmc@redhat.com>
To: qemu-devel@nongnu.org
Cc: Mark McLoughlin <markmc@redhat.com>
Subject: [Qemu-devel] [PATCH 01/44] net: move slirp code from net.c to net/slirp.c
Date: Wed, 25 Nov 2009 18:48:54 +0000 [thread overview]
Message-ID: <1259174977-26212-2-git-send-email-markmc@redhat.com> (raw)
In-Reply-To: <1259174977-26212-1-git-send-email-markmc@redhat.com>
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
Makefile | 1 +
monitor.c | 1 +
net.c | 718 +-------------------------------------------------------
net.h | 8 +-
net/slirp.c | 752 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
net/slirp.h | 51 ++++
vl.c | 1 +
7 files changed, 814 insertions(+), 718 deletions(-)
create mode 100644 net/slirp.c
create mode 100644 net/slirp.h
diff --git a/Makefile b/Makefile
index 63a7128..45362fa 100644
--- a/Makefile
+++ b/Makefile
@@ -106,6 +106,7 @@ net-nested-$(CONFIG_WIN32) += tap-win32.o
net-nested-$(CONFIG_BSD) += tap-bsd.o
net-nested-$(CONFIG_SOLARIS) += tap-solaris.o
net-nested-$(CONFIG_AIX) += tap-aix.o
+net-nested-$(CONFIG_SLIRP) += slirp.o
net-obj-y += $(addprefix net/, $(net-nested-y))
######################################################################
diff --git a/monitor.c b/monitor.c
index 3286ba2..fa1561a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -32,6 +32,7 @@
#include "hw/loader.h"
#include "gdbstub.h"
#include "net.h"
+#include "net/slirp.h"
#include "qemu-char.h"
#include "sysemu.h"
#include "monitor.h"
diff --git a/net.c b/net.c
index 9ea66e3..9b030a1 100644
--- a/net.c
+++ b/net.c
@@ -40,9 +40,7 @@
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/socket.h>
-#include <netinet/in.h>
#include <net/if.h>
-#include <arpa/inet.h>
#include <dirent.h>
#include <netdb.h>
#include <sys/select.h>
@@ -98,6 +96,7 @@
#include "qemu-common.h"
#include "net.h"
#include "net/tap.h"
+#include "net/slirp.h"
#include "monitor.h"
#include "sysemu.h"
#include "qemu-timer.h"
@@ -107,15 +106,13 @@
#include "qemu-log.h"
#include "qemu-config.h"
-#include "slirp/libslirp.h"
-
static QTAILQ_HEAD(, VLANState) vlans;
static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
/***********************************************************/
/* network device redirectors */
-#if defined(DEBUG_NET) || defined(DEBUG_SLIRP)
+#if defined(DEBUG_NET)
static void hex_dump(FILE *f, const uint8_t *buf, int size)
{
int len, i, j, c;
@@ -406,7 +403,7 @@ VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque)
return NULL;
}
-static VLANClientState *
+VLANClientState *
qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id,
const char *client_str)
{
@@ -725,597 +722,6 @@ qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt)
return qemu_sendv_packet_async(vc, iov, iovcnt, NULL);
}
-#if defined(CONFIG_SLIRP)
-
-/* slirp network adapter */
-
-#define SLIRP_CFG_HOSTFWD 1
-#define SLIRP_CFG_LEGACY 2
-
-struct slirp_config_str {
- struct slirp_config_str *next;
- int flags;
- char str[1024];
- int legacy_format;
-};
-
-typedef struct SlirpState {
- QTAILQ_ENTRY(SlirpState) entry;
- VLANClientState *vc;
- Slirp *slirp;
-#ifndef _WIN32
- char smb_dir[128];
-#endif
-} SlirpState;
-
-static struct slirp_config_str *slirp_configs;
-const char *legacy_tftp_prefix;
-const char *legacy_bootp_filename;
-static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks =
- QTAILQ_HEAD_INITIALIZER(slirp_stacks);
-
-static int slirp_hostfwd(SlirpState *s, const char *redir_str,
- int legacy_format);
-static int slirp_guestfwd(SlirpState *s, const char *config_str,
- int legacy_format);
-
-#ifndef _WIN32
-static const char *legacy_smb_export;
-
-static int slirp_smb(SlirpState *s, const char *exported_dir,
- struct in_addr vserver_addr);
-static void slirp_smb_cleanup(SlirpState *s);
-#else
-static inline void slirp_smb_cleanup(SlirpState *s) { }
-#endif
-
-int slirp_can_output(void *opaque)
-{
- SlirpState *s = opaque;
-
- return qemu_can_send_packet(s->vc);
-}
-
-void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len)
-{
- SlirpState *s = opaque;
-
-#ifdef DEBUG_SLIRP
- printf("slirp output:\n");
- hex_dump(stdout, pkt, pkt_len);
-#endif
- qemu_send_packet(s->vc, pkt, pkt_len);
-}
-
-static ssize_t slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
-{
- SlirpState *s = vc->opaque;
-
-#ifdef DEBUG_SLIRP
- printf("slirp input:\n");
- hex_dump(stdout, buf, size);
-#endif
- slirp_input(s->slirp, buf, size);
- return size;
-}
-
-static void net_slirp_cleanup(VLANClientState *vc)
-{
- SlirpState *s = vc->opaque;
-
- slirp_cleanup(s->slirp);
- slirp_smb_cleanup(s);
- QTAILQ_REMOVE(&slirp_stacks, s, entry);
- qemu_free(s);
-}
-
-static int net_slirp_init(VLANState *vlan, const char *model,
- const char *name, int restricted,
- const char *vnetwork, const char *vhost,
- const char *vhostname, const char *tftp_export,
- const char *bootfile, const char *vdhcp_start,
- const char *vnameserver, const char *smb_export,
- const char *vsmbserver)
-{
- /* default settings according to historic slirp */
- struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
- struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
- struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
- struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
- struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
-#ifndef _WIN32
- struct in_addr smbsrv = { .s_addr = 0 };
-#endif
- SlirpState *s;
- char buf[20];
- uint32_t addr;
- int shift;
- char *end;
- struct slirp_config_str *config;
-
- if (!tftp_export) {
- tftp_export = legacy_tftp_prefix;
- }
- if (!bootfile) {
- bootfile = legacy_bootp_filename;
- }
-
- if (vnetwork) {
- if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) {
- if (!inet_aton(vnetwork, &net)) {
- return -1;
- }
- addr = ntohl(net.s_addr);
- if (!(addr & 0x80000000)) {
- mask.s_addr = htonl(0xff000000); /* class A */
- } else if ((addr & 0xfff00000) == 0xac100000) {
- mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */
- } else if ((addr & 0xc0000000) == 0x80000000) {
- mask.s_addr = htonl(0xffff0000); /* class B */
- } else if ((addr & 0xffff0000) == 0xc0a80000) {
- mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */
- } else if ((addr & 0xffff0000) == 0xc6120000) {
- mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */
- } else if ((addr & 0xe0000000) == 0xe0000000) {
- mask.s_addr = htonl(0xffffff00); /* class C */
- } else {
- mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */
- }
- } else {
- if (!inet_aton(buf, &net)) {
- return -1;
- }
- shift = strtol(vnetwork, &end, 10);
- if (*end != '\0') {
- if (!inet_aton(vnetwork, &mask)) {
- return -1;
- }
- } else if (shift < 4 || shift > 32) {
- return -1;
- } else {
- mask.s_addr = htonl(0xffffffff << (32 - shift));
- }
- }
- net.s_addr &= mask.s_addr;
- host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr);
- dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr);
- dns.s_addr = net.s_addr | (htonl(0x0203) & ~mask.s_addr);
- }
-
- if (vhost && !inet_aton(vhost, &host)) {
- return -1;
- }
- if ((host.s_addr & mask.s_addr) != net.s_addr) {
- return -1;
- }
-
- if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) {
- return -1;
- }
- if ((dhcp.s_addr & mask.s_addr) != net.s_addr ||
- dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) {
- return -1;
- }
-
- if (vnameserver && !inet_aton(vnameserver, &dns)) {
- return -1;
- }
- if ((dns.s_addr & mask.s_addr) != net.s_addr ||
- dns.s_addr == host.s_addr) {
- return -1;
- }
-
-#ifndef _WIN32
- if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
- return -1;
- }
-#endif
-
- s = qemu_mallocz(sizeof(SlirpState));
- s->slirp = slirp_init(restricted, net, mask, host, vhostname,
- tftp_export, bootfile, dhcp, dns, s);
- QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
-
- for (config = slirp_configs; config; config = config->next) {
- if (config->flags & SLIRP_CFG_HOSTFWD) {
- if (slirp_hostfwd(s, config->str,
- config->flags & SLIRP_CFG_LEGACY) < 0)
- return -1;
- } else {
- if (slirp_guestfwd(s, config->str,
- config->flags & SLIRP_CFG_LEGACY) < 0)
- return -1;
- }
- }
-#ifndef _WIN32
- if (!smb_export) {
- smb_export = legacy_smb_export;
- }
- if (smb_export) {
- if (slirp_smb(s, smb_export, smbsrv) < 0)
- return -1;
- }
-#endif
-
- s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SLIRP,
- vlan, NULL, model, name, NULL,
- slirp_receive, NULL, NULL,
- net_slirp_cleanup, s);
- snprintf(s->vc->info_str, sizeof(s->vc->info_str),
- "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n');
- return 0;
-}
-
-static SlirpState *slirp_lookup(Monitor *mon, const char *vlan,
- const char *stack)
-{
- VLANClientState *vc;
-
- if (vlan) {
- vc = qemu_find_vlan_client_by_name(mon, strtol(vlan, NULL, 0), stack);
- if (!vc) {
- return NULL;
- }
- if (strcmp(vc->model, "user")) {
- monitor_printf(mon, "invalid device specified\n");
- return NULL;
- }
- return vc->opaque;
- } else {
- if (QTAILQ_EMPTY(&slirp_stacks)) {
- monitor_printf(mon, "user mode network stack not in use\n");
- return NULL;
- }
- return QTAILQ_FIRST(&slirp_stacks);
- }
-}
-
-void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict)
-{
- struct in_addr host_addr = { .s_addr = INADDR_ANY };
- int host_port;
- char buf[256] = "";
- const char *src_str, *p;
- SlirpState *s;
- int is_udp = 0;
- int err;
- const char *arg1 = qdict_get_str(qdict, "arg1");
- const char *arg2 = qdict_get_try_str(qdict, "arg2");
- const char *arg3 = qdict_get_try_str(qdict, "arg3");
-
- if (arg2) {
- s = slirp_lookup(mon, arg1, arg2);
- src_str = arg3;
- } else {
- s = slirp_lookup(mon, NULL, NULL);
- src_str = arg1;
- }
- if (!s) {
- return;
- }
-
- if (!src_str || !src_str[0])
- goto fail_syntax;
-
- p = src_str;
- get_str_sep(buf, sizeof(buf), &p, ':');
-
- if (!strcmp(buf, "tcp") || buf[0] == '\0') {
- is_udp = 0;
- } else if (!strcmp(buf, "udp")) {
- is_udp = 1;
- } else {
- goto fail_syntax;
- }
-
- if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
- goto fail_syntax;
- }
- if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
- goto fail_syntax;
- }
-
- host_port = atoi(p);
-
- err = slirp_remove_hostfwd(QTAILQ_FIRST(&slirp_stacks)->slirp, is_udp,
- host_addr, host_port);
-
- monitor_printf(mon, "host forwarding rule for %s %s\n", src_str,
- err ? "removed" : "not found");
- return;
-
- fail_syntax:
- monitor_printf(mon, "invalid format\n");
-}
-
-static int slirp_hostfwd(SlirpState *s, const char *redir_str,
- int legacy_format)
-{
- struct in_addr host_addr = { .s_addr = INADDR_ANY };
- struct in_addr guest_addr = { .s_addr = 0 };
- int host_port, guest_port;
- const char *p;
- char buf[256];
- int is_udp;
- char *end;
-
- p = redir_str;
- if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
- goto fail_syntax;
- }
- if (!strcmp(buf, "tcp") || buf[0] == '\0') {
- is_udp = 0;
- } else if (!strcmp(buf, "udp")) {
- is_udp = 1;
- } else {
- goto fail_syntax;
- }
-
- if (!legacy_format) {
- if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
- goto fail_syntax;
- }
- if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
- goto fail_syntax;
- }
- }
-
- if (get_str_sep(buf, sizeof(buf), &p, legacy_format ? ':' : '-') < 0) {
- goto fail_syntax;
- }
- host_port = strtol(buf, &end, 0);
- if (*end != '\0' || host_port < 1 || host_port > 65535) {
- goto fail_syntax;
- }
-
- if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
- goto fail_syntax;
- }
- if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) {
- goto fail_syntax;
- }
-
- guest_port = strtol(p, &end, 0);
- if (*end != '\0' || guest_port < 1 || guest_port > 65535) {
- goto fail_syntax;
- }
-
- if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr,
- guest_port) < 0) {
- qemu_error("could not set up host forwarding rule '%s'\n",
- redir_str);
- return -1;
- }
- return 0;
-
- fail_syntax:
- qemu_error("invalid host forwarding rule '%s'\n", redir_str);
- return -1;
-}
-
-void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict)
-{
- const char *redir_str;
- SlirpState *s;
- const char *arg1 = qdict_get_str(qdict, "arg1");
- const char *arg2 = qdict_get_try_str(qdict, "arg2");
- const char *arg3 = qdict_get_try_str(qdict, "arg3");
-
- if (arg2) {
- s = slirp_lookup(mon, arg1, arg2);
- redir_str = arg3;
- } else {
- s = slirp_lookup(mon, NULL, NULL);
- redir_str = arg1;
- }
- if (s) {
- slirp_hostfwd(s, redir_str, 0);
- }
-
-}
-
-int net_slirp_redir(const char *redir_str)
-{
- struct slirp_config_str *config;
-
- if (QTAILQ_EMPTY(&slirp_stacks)) {
- config = qemu_malloc(sizeof(*config));
- pstrcpy(config->str, sizeof(config->str), redir_str);
- config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY;
- config->next = slirp_configs;
- slirp_configs = config;
- return 0;
- }
-
- return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1);
-}
-
-#ifndef _WIN32
-
-/* automatic user mode samba server configuration */
-static void slirp_smb_cleanup(SlirpState *s)
-{
- char cmd[128];
-
- if (s->smb_dir[0] != '\0') {
- snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir);
- system(cmd);
- s->smb_dir[0] = '\0';
- }
-}
-
-static int slirp_smb(SlirpState* s, const char *exported_dir,
- struct in_addr vserver_addr)
-{
- static int instance;
- char smb_conf[128];
- char smb_cmdline[128];
- FILE *f;
-
- snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d",
- (long)getpid(), instance++);
- if (mkdir(s->smb_dir, 0700) < 0) {
- qemu_error("could not create samba server dir '%s'\n", s->smb_dir);
- return -1;
- }
- snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf");
-
- f = fopen(smb_conf, "w");
- if (!f) {
- slirp_smb_cleanup(s);
- qemu_error("could not create samba server configuration file '%s'\n",
- smb_conf);
- return -1;
- }
- fprintf(f,
- "[global]\n"
- "private dir=%s\n"
- "smb ports=0\n"
- "socket address=127.0.0.1\n"
- "pid directory=%s\n"
- "lock directory=%s\n"
- "log file=%s/log.smbd\n"
- "smb passwd file=%s/smbpasswd\n"
- "security = share\n"
- "[qemu]\n"
- "path=%s\n"
- "read only=no\n"
- "guest ok=yes\n",
- s->smb_dir,
- s->smb_dir,
- s->smb_dir,
- s->smb_dir,
- s->smb_dir,
- exported_dir
- );
- fclose(f);
-
- snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
- SMBD_COMMAND, smb_conf);
-
- if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) {
- slirp_smb_cleanup(s);
- qemu_error("conflicting/invalid smbserver address\n");
- return -1;
- }
- return 0;
-}
-
-/* automatic user mode samba server configuration (legacy interface) */
-int net_slirp_smb(const char *exported_dir)
-{
- struct in_addr vserver_addr = { .s_addr = 0 };
-
- if (legacy_smb_export) {
- fprintf(stderr, "-smb given twice\n");
- return -1;
- }
- legacy_smb_export = exported_dir;
- if (!QTAILQ_EMPTY(&slirp_stacks)) {
- return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir,
- vserver_addr);
- }
- return 0;
-}
-
-#endif /* !defined(_WIN32) */
-
-struct GuestFwd {
- CharDriverState *hd;
- struct in_addr server;
- int port;
- Slirp *slirp;
-};
-
-static int guestfwd_can_read(void *opaque)
-{
- struct GuestFwd *fwd = opaque;
- return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port);
-}
-
-static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
-{
- struct GuestFwd *fwd = opaque;
- slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size);
-}
-
-static int slirp_guestfwd(SlirpState *s, const char *config_str,
- int legacy_format)
-{
- struct in_addr server = { .s_addr = 0 };
- struct GuestFwd *fwd;
- const char *p;
- char buf[128];
- char *end;
- int port;
-
- p = config_str;
- if (legacy_format) {
- if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
- goto fail_syntax;
- }
- } else {
- if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
- goto fail_syntax;
- }
- if (strcmp(buf, "tcp") && buf[0] != '\0') {
- goto fail_syntax;
- }
- if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
- goto fail_syntax;
- }
- if (buf[0] != '\0' && !inet_aton(buf, &server)) {
- goto fail_syntax;
- }
- if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
- goto fail_syntax;
- }
- }
- port = strtol(buf, &end, 10);
- if (*end != '\0' || port < 1 || port > 65535) {
- goto fail_syntax;
- }
-
- fwd = qemu_malloc(sizeof(struct GuestFwd));
- snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port);
- fwd->hd = qemu_chr_open(buf, p, NULL);
- if (!fwd->hd) {
- qemu_error("could not open guest forwarding device '%s'\n", buf);
- qemu_free(fwd);
- return -1;
- }
-
- if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) {
- qemu_error("conflicting/invalid host:port in guest forwarding "
- "rule '%s'\n", config_str);
- qemu_free(fwd);
- return -1;
- }
- fwd->server = server;
- fwd->port = port;
- fwd->slirp = s->slirp;
-
- qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
- NULL, fwd);
- return 0;
-
- fail_syntax:
- qemu_error("invalid guest forwarding rule '%s'\n", config_str);
- return -1;
-}
-
-void do_info_usernet(Monitor *mon)
-{
- SlirpState *s;
-
- QTAILQ_FOREACH(s, &slirp_stacks, entry) {
- monitor_printf(mon, "VLAN %d (%s):\n", s->vc->vlan->id, s->vc->name);
- slirp_connection_info(s->slirp, mon);
- }
-}
-
-#endif /* CONFIG_SLIRP */
-
#if defined(CONFIG_VDE)
typedef struct VDEState {
VLANClientState *vc;
@@ -2116,101 +1522,6 @@ static int net_init_nic(QemuOpts *opts,
return idx;
}
-#if defined(CONFIG_SLIRP)
-static int net_init_slirp_configs(const char *name, const char *value, void *opaque)
-{
- struct slirp_config_str *config;
-
- if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) {
- return 0;
- }
-
- config = qemu_mallocz(sizeof(*config));
-
- pstrcpy(config->str, sizeof(config->str), value);
-
- if (!strcmp(name, "hostfwd")) {
- config->flags = SLIRP_CFG_HOSTFWD;
- }
-
- config->next = slirp_configs;
- slirp_configs = config;
-
- return 0;
-}
-
-static int net_init_slirp(QemuOpts *opts,
- Monitor *mon,
- const char *name,
- VLANState *vlan)
-{
- struct slirp_config_str *config;
- const char *vhost;
- const char *vhostname;
- const char *vdhcp_start;
- const char *vnamesrv;
- const char *tftp_export;
- const char *bootfile;
- const char *smb_export;
- const char *vsmbsrv;
- char *vnet = NULL;
- int restricted = 0;
- int ret;
-
- vhost = qemu_opt_get(opts, "host");
- vhostname = qemu_opt_get(opts, "hostname");
- vdhcp_start = qemu_opt_get(opts, "dhcpstart");
- vnamesrv = qemu_opt_get(opts, "dns");
- tftp_export = qemu_opt_get(opts, "tftp");
- bootfile = qemu_opt_get(opts, "bootfile");
- smb_export = qemu_opt_get(opts, "smb");
- vsmbsrv = qemu_opt_get(opts, "smbserver");
-
- if (qemu_opt_get(opts, "ip")) {
- const char *ip = qemu_opt_get(opts, "ip");
- int l = strlen(ip) + strlen("/24") + 1;
-
- vnet = qemu_malloc(l);
-
- /* emulate legacy ip= parameter */
- pstrcpy(vnet, l, ip);
- pstrcat(vnet, l, "/24");
- }
-
- if (qemu_opt_get(opts, "net")) {
- if (vnet) {
- qemu_free(vnet);
- }
- vnet = qemu_strdup(qemu_opt_get(opts, "net"));
- }
-
- if (qemu_opt_get(opts, "restrict") &&
- qemu_opt_get(opts, "restrict")[0] == 'y') {
- restricted = 1;
- }
-
- qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0);
-
- ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost,
- vhostname, tftp_export, bootfile, vdhcp_start,
- vnamesrv, smb_export, vsmbsrv);
-
- while (slirp_configs) {
- config = slirp_configs;
- slirp_configs = config->next;
- qemu_free(config);
- }
-
- if (ret != -1 && vlan) {
- vlan->nb_host_devs++;
- }
-
- qemu_free(vnet);
-
- return ret;
-}
-#endif /* CONFIG_SLIRP */
-
static int net_init_socket(QemuOpts *opts,
Monitor *mon,
const char *name,
@@ -2860,29 +2171,12 @@ int net_init_clients(void)
int net_client_parse(QemuOptsList *opts_list, const char *optarg)
{
#if defined(CONFIG_SLIRP)
- /* handle legacy -net channel,port:chr */
- if (!strcmp(opts_list->name, "net") &&
- !strncmp(optarg, "channel,", strlen("channel,"))) {
- int ret;
-
- optarg += strlen("channel,");
-
- if (QTAILQ_EMPTY(&slirp_stacks)) {
- struct slirp_config_str *config;
-
- config = qemu_malloc(sizeof(*config));
- pstrcpy(config->str, sizeof(config->str), optarg);
- config->flags = SLIRP_CFG_LEGACY;
- config->next = slirp_configs;
- slirp_configs = config;
- ret = 0;
- } else {
- ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1);
- }
-
+ int ret;
+ if (net_slirp_parse_legacy(opts_list, optarg, &ret)) {
return ret;
}
#endif
+
if (!qemu_opts_parse(opts_list, optarg, "type")) {
return -1;
}
diff --git a/net.h b/net.h
index 4ffce91..42ac42d 100644
--- a/net.h
+++ b/net.h
@@ -87,6 +87,8 @@ VLANClientState *qemu_new_vlan_client(net_client_type type,
void *opaque);
void qemu_del_vlan_client(VLANClientState *vc);
VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque);
+VLANClientState *qemu_find_vlan_client_by_name(Monitor *mon, int vlan_id,
+ const char *client_str);
int qemu_can_send_packet(VLANClientState *vc);
ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov,
int iovcnt);
@@ -108,8 +110,6 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models,
void do_info_network(Monitor *mon);
void do_set_link(Monitor *mon, const QDict *qdict);
-void do_info_usernet(Monitor *mon);
-
/* NIC info */
#define MAX_NICS 8
@@ -156,10 +156,6 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev);
void net_client_uninit(NICInfo *nd);
int net_client_parse(QemuOptsList *opts_list, const char *str);
int net_init_clients(void);
-int net_slirp_smb(const char *exported_dir);
-void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict);
-void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict);
-int net_slirp_redir(const char *redir_str);
void net_cleanup(void);
void net_set_boot_mask(int boot_mask);
void net_host_device_add(Monitor *mon, const QDict *qdict);
diff --git a/net/slirp.c b/net/slirp.c
new file mode 100644
index 0000000..d6d5772
--- /dev/null
+++ b/net/slirp.c
@@ -0,0 +1,752 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-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.
+ */
+#include "net/slirp.h"
+
+#include "config-host.h"
+
+#include "net.h"
+#include "monitor.h"
+#include "sysemu.h"
+#include "qemu_socket.h"
+#include "slirp/libslirp.h"
+
+static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
+{
+ const char *p, *p1;
+ int len;
+ p = *pp;
+ p1 = strchr(p, sep);
+ if (!p1)
+ return -1;
+ len = p1 - p;
+ p1++;
+ if (buf_size > 0) {
+ if (len > buf_size - 1)
+ len = buf_size - 1;
+ memcpy(buf, p, len);
+ buf[len] = '\0';
+ }
+ *pp = p1;
+ return 0;
+}
+
+/* slirp network adapter */
+
+#define SLIRP_CFG_HOSTFWD 1
+#define SLIRP_CFG_LEGACY 2
+
+struct slirp_config_str {
+ struct slirp_config_str *next;
+ int flags;
+ char str[1024];
+ int legacy_format;
+};
+
+typedef struct SlirpState {
+ QTAILQ_ENTRY(SlirpState) entry;
+ VLANClientState *vc;
+ Slirp *slirp;
+#ifndef _WIN32
+ char smb_dir[128];
+#endif
+} SlirpState;
+
+static struct slirp_config_str *slirp_configs;
+const char *legacy_tftp_prefix;
+const char *legacy_bootp_filename;
+static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks =
+ QTAILQ_HEAD_INITIALIZER(slirp_stacks);
+
+static int slirp_hostfwd(SlirpState *s, const char *redir_str,
+ int legacy_format);
+static int slirp_guestfwd(SlirpState *s, const char *config_str,
+ int legacy_format);
+
+#ifndef _WIN32
+static const char *legacy_smb_export;
+
+static int slirp_smb(SlirpState *s, const char *exported_dir,
+ struct in_addr vserver_addr);
+static void slirp_smb_cleanup(SlirpState *s);
+#else
+static inline void slirp_smb_cleanup(SlirpState *s) { }
+#endif
+
+int slirp_can_output(void *opaque)
+{
+ SlirpState *s = opaque;
+
+ return qemu_can_send_packet(s->vc);
+}
+
+void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len)
+{
+ SlirpState *s = opaque;
+
+ qemu_send_packet(s->vc, pkt, pkt_len);
+}
+
+static ssize_t slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+ SlirpState *s = vc->opaque;
+
+ slirp_input(s->slirp, buf, size);
+
+ return size;
+}
+
+static void net_slirp_cleanup(VLANClientState *vc)
+{
+ SlirpState *s = vc->opaque;
+
+ slirp_cleanup(s->slirp);
+ slirp_smb_cleanup(s);
+ QTAILQ_REMOVE(&slirp_stacks, s, entry);
+ qemu_free(s);
+}
+
+static int net_slirp_init(VLANState *vlan, const char *model,
+ const char *name, int restricted,
+ const char *vnetwork, const char *vhost,
+ const char *vhostname, const char *tftp_export,
+ const char *bootfile, const char *vdhcp_start,
+ const char *vnameserver, const char *smb_export,
+ const char *vsmbserver)
+{
+ /* default settings according to historic slirp */
+ struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
+ struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
+ struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
+ struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
+ struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
+#ifndef _WIN32
+ struct in_addr smbsrv = { .s_addr = 0 };
+#endif
+ SlirpState *s;
+ char buf[20];
+ uint32_t addr;
+ int shift;
+ char *end;
+ struct slirp_config_str *config;
+
+ if (!tftp_export) {
+ tftp_export = legacy_tftp_prefix;
+ }
+ if (!bootfile) {
+ bootfile = legacy_bootp_filename;
+ }
+
+ if (vnetwork) {
+ if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) {
+ if (!inet_aton(vnetwork, &net)) {
+ return -1;
+ }
+ addr = ntohl(net.s_addr);
+ if (!(addr & 0x80000000)) {
+ mask.s_addr = htonl(0xff000000); /* class A */
+ } else if ((addr & 0xfff00000) == 0xac100000) {
+ mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */
+ } else if ((addr & 0xc0000000) == 0x80000000) {
+ mask.s_addr = htonl(0xffff0000); /* class B */
+ } else if ((addr & 0xffff0000) == 0xc0a80000) {
+ mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */
+ } else if ((addr & 0xffff0000) == 0xc6120000) {
+ mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */
+ } else if ((addr & 0xe0000000) == 0xe0000000) {
+ mask.s_addr = htonl(0xffffff00); /* class C */
+ } else {
+ mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */
+ }
+ } else {
+ if (!inet_aton(buf, &net)) {
+ return -1;
+ }
+ shift = strtol(vnetwork, &end, 10);
+ if (*end != '\0') {
+ if (!inet_aton(vnetwork, &mask)) {
+ return -1;
+ }
+ } else if (shift < 4 || shift > 32) {
+ return -1;
+ } else {
+ mask.s_addr = htonl(0xffffffff << (32 - shift));
+ }
+ }
+ net.s_addr &= mask.s_addr;
+ host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr);
+ dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr);
+ dns.s_addr = net.s_addr | (htonl(0x0203) & ~mask.s_addr);
+ }
+
+ if (vhost && !inet_aton(vhost, &host)) {
+ return -1;
+ }
+ if ((host.s_addr & mask.s_addr) != net.s_addr) {
+ return -1;
+ }
+
+ if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) {
+ return -1;
+ }
+ if ((dhcp.s_addr & mask.s_addr) != net.s_addr ||
+ dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) {
+ return -1;
+ }
+
+ if (vnameserver && !inet_aton(vnameserver, &dns)) {
+ return -1;
+ }
+ if ((dns.s_addr & mask.s_addr) != net.s_addr ||
+ dns.s_addr == host.s_addr) {
+ return -1;
+ }
+
+#ifndef _WIN32
+ if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
+ return -1;
+ }
+#endif
+
+ s = qemu_mallocz(sizeof(SlirpState));
+ s->slirp = slirp_init(restricted, net, mask, host, vhostname,
+ tftp_export, bootfile, dhcp, dns, s);
+ QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
+
+ for (config = slirp_configs; config; config = config->next) {
+ if (config->flags & SLIRP_CFG_HOSTFWD) {
+ if (slirp_hostfwd(s, config->str,
+ config->flags & SLIRP_CFG_LEGACY) < 0)
+ return -1;
+ } else {
+ if (slirp_guestfwd(s, config->str,
+ config->flags & SLIRP_CFG_LEGACY) < 0)
+ return -1;
+ }
+ }
+#ifndef _WIN32
+ if (!smb_export) {
+ smb_export = legacy_smb_export;
+ }
+ if (smb_export) {
+ if (slirp_smb(s, smb_export, smbsrv) < 0)
+ return -1;
+ }
+#endif
+
+ s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SLIRP,
+ vlan, NULL, model, name, NULL,
+ slirp_receive, NULL, NULL,
+ net_slirp_cleanup, s);
+ snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+ "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n');
+ return 0;
+}
+
+static SlirpState *slirp_lookup(Monitor *mon, const char *vlan,
+ const char *stack)
+{
+ VLANClientState *vc;
+
+ if (vlan) {
+ vc = qemu_find_vlan_client_by_name(mon, strtol(vlan, NULL, 0), stack);
+ if (!vc) {
+ return NULL;
+ }
+ if (strcmp(vc->model, "user")) {
+ monitor_printf(mon, "invalid device specified\n");
+ return NULL;
+ }
+ return vc->opaque;
+ } else {
+ if (QTAILQ_EMPTY(&slirp_stacks)) {
+ monitor_printf(mon, "user mode network stack not in use\n");
+ return NULL;
+ }
+ return QTAILQ_FIRST(&slirp_stacks);
+ }
+}
+
+void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict)
+{
+ struct in_addr host_addr = { .s_addr = INADDR_ANY };
+ int host_port;
+ char buf[256] = "";
+ const char *src_str, *p;
+ SlirpState *s;
+ int is_udp = 0;
+ int err;
+ const char *arg1 = qdict_get_str(qdict, "arg1");
+ const char *arg2 = qdict_get_try_str(qdict, "arg2");
+ const char *arg3 = qdict_get_try_str(qdict, "arg3");
+
+ if (arg2) {
+ s = slirp_lookup(mon, arg1, arg2);
+ src_str = arg3;
+ } else {
+ s = slirp_lookup(mon, NULL, NULL);
+ src_str = arg1;
+ }
+ if (!s) {
+ return;
+ }
+
+ if (!src_str || !src_str[0])
+ goto fail_syntax;
+
+ p = src_str;
+ get_str_sep(buf, sizeof(buf), &p, ':');
+
+ if (!strcmp(buf, "tcp") || buf[0] == '\0') {
+ is_udp = 0;
+ } else if (!strcmp(buf, "udp")) {
+ is_udp = 1;
+ } else {
+ goto fail_syntax;
+ }
+
+ if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+ goto fail_syntax;
+ }
+ if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
+ goto fail_syntax;
+ }
+
+ host_port = atoi(p);
+
+ err = slirp_remove_hostfwd(QTAILQ_FIRST(&slirp_stacks)->slirp, is_udp,
+ host_addr, host_port);
+
+ monitor_printf(mon, "host forwarding rule for %s %s\n", src_str,
+ err ? "removed" : "not found");
+ return;
+
+ fail_syntax:
+ monitor_printf(mon, "invalid format\n");
+}
+
+static int slirp_hostfwd(SlirpState *s, const char *redir_str,
+ int legacy_format)
+{
+ struct in_addr host_addr = { .s_addr = INADDR_ANY };
+ struct in_addr guest_addr = { .s_addr = 0 };
+ int host_port, guest_port;
+ const char *p;
+ char buf[256];
+ int is_udp;
+ char *end;
+
+ p = redir_str;
+ if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+ goto fail_syntax;
+ }
+ if (!strcmp(buf, "tcp") || buf[0] == '\0') {
+ is_udp = 0;
+ } else if (!strcmp(buf, "udp")) {
+ is_udp = 1;
+ } else {
+ goto fail_syntax;
+ }
+
+ if (!legacy_format) {
+ if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+ goto fail_syntax;
+ }
+ if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
+ goto fail_syntax;
+ }
+ }
+
+ if (get_str_sep(buf, sizeof(buf), &p, legacy_format ? ':' : '-') < 0) {
+ goto fail_syntax;
+ }
+ host_port = strtol(buf, &end, 0);
+ if (*end != '\0' || host_port < 1 || host_port > 65535) {
+ goto fail_syntax;
+ }
+
+ if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+ goto fail_syntax;
+ }
+ if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) {
+ goto fail_syntax;
+ }
+
+ guest_port = strtol(p, &end, 0);
+ if (*end != '\0' || guest_port < 1 || guest_port > 65535) {
+ goto fail_syntax;
+ }
+
+ if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr,
+ guest_port) < 0) {
+ qemu_error("could not set up host forwarding rule '%s'\n",
+ redir_str);
+ return -1;
+ }
+ return 0;
+
+ fail_syntax:
+ qemu_error("invalid host forwarding rule '%s'\n", redir_str);
+ return -1;
+}
+
+void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict)
+{
+ const char *redir_str;
+ SlirpState *s;
+ const char *arg1 = qdict_get_str(qdict, "arg1");
+ const char *arg2 = qdict_get_try_str(qdict, "arg2");
+ const char *arg3 = qdict_get_try_str(qdict, "arg3");
+
+ if (arg2) {
+ s = slirp_lookup(mon, arg1, arg2);
+ redir_str = arg3;
+ } else {
+ s = slirp_lookup(mon, NULL, NULL);
+ redir_str = arg1;
+ }
+ if (s) {
+ slirp_hostfwd(s, redir_str, 0);
+ }
+
+}
+
+int net_slirp_redir(const char *redir_str)
+{
+ struct slirp_config_str *config;
+
+ if (QTAILQ_EMPTY(&slirp_stacks)) {
+ config = qemu_malloc(sizeof(*config));
+ pstrcpy(config->str, sizeof(config->str), redir_str);
+ config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY;
+ config->next = slirp_configs;
+ slirp_configs = config;
+ return 0;
+ }
+
+ return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1);
+}
+
+#ifndef _WIN32
+
+/* automatic user mode samba server configuration */
+static void slirp_smb_cleanup(SlirpState *s)
+{
+ char cmd[128];
+
+ if (s->smb_dir[0] != '\0') {
+ snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir);
+ system(cmd);
+ s->smb_dir[0] = '\0';
+ }
+}
+
+static int slirp_smb(SlirpState* s, const char *exported_dir,
+ struct in_addr vserver_addr)
+{
+ static int instance;
+ char smb_conf[128];
+ char smb_cmdline[128];
+ FILE *f;
+
+ snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d",
+ (long)getpid(), instance++);
+ if (mkdir(s->smb_dir, 0700) < 0) {
+ qemu_error("could not create samba server dir '%s'\n", s->smb_dir);
+ return -1;
+ }
+ snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf");
+
+ f = fopen(smb_conf, "w");
+ if (!f) {
+ slirp_smb_cleanup(s);
+ qemu_error("could not create samba server configuration file '%s'\n",
+ smb_conf);
+ return -1;
+ }
+ fprintf(f,
+ "[global]\n"
+ "private dir=%s\n"
+ "smb ports=0\n"
+ "socket address=127.0.0.1\n"
+ "pid directory=%s\n"
+ "lock directory=%s\n"
+ "log file=%s/log.smbd\n"
+ "smb passwd file=%s/smbpasswd\n"
+ "security = share\n"
+ "[qemu]\n"
+ "path=%s\n"
+ "read only=no\n"
+ "guest ok=yes\n",
+ s->smb_dir,
+ s->smb_dir,
+ s->smb_dir,
+ s->smb_dir,
+ s->smb_dir,
+ exported_dir
+ );
+ fclose(f);
+
+ snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
+ SMBD_COMMAND, smb_conf);
+
+ if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) {
+ slirp_smb_cleanup(s);
+ qemu_error("conflicting/invalid smbserver address\n");
+ return -1;
+ }
+ return 0;
+}
+
+/* automatic user mode samba server configuration (legacy interface) */
+int net_slirp_smb(const char *exported_dir)
+{
+ struct in_addr vserver_addr = { .s_addr = 0 };
+
+ if (legacy_smb_export) {
+ fprintf(stderr, "-smb given twice\n");
+ return -1;
+ }
+ legacy_smb_export = exported_dir;
+ if (!QTAILQ_EMPTY(&slirp_stacks)) {
+ return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir,
+ vserver_addr);
+ }
+ return 0;
+}
+
+#endif /* !defined(_WIN32) */
+
+struct GuestFwd {
+ CharDriverState *hd;
+ struct in_addr server;
+ int port;
+ Slirp *slirp;
+};
+
+static int guestfwd_can_read(void *opaque)
+{
+ struct GuestFwd *fwd = opaque;
+ return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port);
+}
+
+static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
+{
+ struct GuestFwd *fwd = opaque;
+ slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size);
+}
+
+static int slirp_guestfwd(SlirpState *s, const char *config_str,
+ int legacy_format)
+{
+ struct in_addr server = { .s_addr = 0 };
+ struct GuestFwd *fwd;
+ const char *p;
+ char buf[128];
+ char *end;
+ int port;
+
+ p = config_str;
+ if (legacy_format) {
+ if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+ goto fail_syntax;
+ }
+ } else {
+ if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+ goto fail_syntax;
+ }
+ if (strcmp(buf, "tcp") && buf[0] != '\0') {
+ goto fail_syntax;
+ }
+ if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
+ goto fail_syntax;
+ }
+ if (buf[0] != '\0' && !inet_aton(buf, &server)) {
+ goto fail_syntax;
+ }
+ if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
+ goto fail_syntax;
+ }
+ }
+ port = strtol(buf, &end, 10);
+ if (*end != '\0' || port < 1 || port > 65535) {
+ goto fail_syntax;
+ }
+
+ fwd = qemu_malloc(sizeof(struct GuestFwd));
+ snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port);
+ fwd->hd = qemu_chr_open(buf, p, NULL);
+ if (!fwd->hd) {
+ qemu_error("could not open guest forwarding device '%s'\n", buf);
+ qemu_free(fwd);
+ return -1;
+ }
+
+ if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) {
+ qemu_error("conflicting/invalid host:port in guest forwarding "
+ "rule '%s'\n", config_str);
+ qemu_free(fwd);
+ return -1;
+ }
+ fwd->server = server;
+ fwd->port = port;
+ fwd->slirp = s->slirp;
+
+ qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
+ NULL, fwd);
+ return 0;
+
+ fail_syntax:
+ qemu_error("invalid guest forwarding rule '%s'\n", config_str);
+ return -1;
+}
+
+void do_info_usernet(Monitor *mon)
+{
+ SlirpState *s;
+
+ QTAILQ_FOREACH(s, &slirp_stacks, entry) {
+ monitor_printf(mon, "VLAN %d (%s):\n", s->vc->vlan->id, s->vc->name);
+ slirp_connection_info(s->slirp, mon);
+ }
+}
+
+static int net_init_slirp_configs(const char *name, const char *value, void *opaque)
+{
+ struct slirp_config_str *config;
+
+ if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) {
+ return 0;
+ }
+
+ config = qemu_mallocz(sizeof(*config));
+
+ pstrcpy(config->str, sizeof(config->str), value);
+
+ if (!strcmp(name, "hostfwd")) {
+ config->flags = SLIRP_CFG_HOSTFWD;
+ }
+
+ config->next = slirp_configs;
+ slirp_configs = config;
+
+ return 0;
+}
+
+int net_init_slirp(QemuOpts *opts,
+ Monitor *mon,
+ const char *name,
+ VLANState *vlan)
+{
+ struct slirp_config_str *config;
+ const char *vhost;
+ const char *vhostname;
+ const char *vdhcp_start;
+ const char *vnamesrv;
+ const char *tftp_export;
+ const char *bootfile;
+ const char *smb_export;
+ const char *vsmbsrv;
+ char *vnet = NULL;
+ int restricted = 0;
+ int ret;
+
+ vhost = qemu_opt_get(opts, "host");
+ vhostname = qemu_opt_get(opts, "hostname");
+ vdhcp_start = qemu_opt_get(opts, "dhcpstart");
+ vnamesrv = qemu_opt_get(opts, "dns");
+ tftp_export = qemu_opt_get(opts, "tftp");
+ bootfile = qemu_opt_get(opts, "bootfile");
+ smb_export = qemu_opt_get(opts, "smb");
+ vsmbsrv = qemu_opt_get(opts, "smbserver");
+
+ if (qemu_opt_get(opts, "ip")) {
+ const char *ip = qemu_opt_get(opts, "ip");
+ int l = strlen(ip) + strlen("/24") + 1;
+
+ vnet = qemu_malloc(l);
+
+ /* emulate legacy ip= parameter */
+ pstrcpy(vnet, l, ip);
+ pstrcat(vnet, l, "/24");
+ }
+
+ if (qemu_opt_get(opts, "net")) {
+ if (vnet) {
+ qemu_free(vnet);
+ }
+ vnet = qemu_strdup(qemu_opt_get(opts, "net"));
+ }
+
+ if (qemu_opt_get(opts, "restrict") &&
+ qemu_opt_get(opts, "restrict")[0] == 'y') {
+ restricted = 1;
+ }
+
+ qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0);
+
+ ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost,
+ vhostname, tftp_export, bootfile, vdhcp_start,
+ vnamesrv, smb_export, vsmbsrv);
+
+ while (slirp_configs) {
+ config = slirp_configs;
+ slirp_configs = config->next;
+ qemu_free(config);
+ }
+
+ if (ret != -1 && vlan) {
+ vlan->nb_host_devs++;
+ }
+
+ qemu_free(vnet);
+
+ return ret;
+}
+
+int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret)
+{
+ if (strcmp(opts_list->name, "net") != 0 ||
+ strncmp(optarg, "channel,", strlen("channel,")) != 0) {
+ return 0;
+ }
+
+ /* handle legacy -net channel,port:chr */
+ optarg += strlen("channel,");
+
+ if (QTAILQ_EMPTY(&slirp_stacks)) {
+ struct slirp_config_str *config;
+
+ config = qemu_malloc(sizeof(*config));
+ pstrcpy(config->str, sizeof(config->str), optarg);
+ config->flags = SLIRP_CFG_LEGACY;
+ config->next = slirp_configs;
+ slirp_configs = config;
+ *ret = 0;
+ } else {
+ *ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1);
+ }
+
+ return 1;
+}
+
diff --git a/net/slirp.h b/net/slirp.h
new file mode 100644
index 0000000..c17de8e
--- /dev/null
+++ b/net/slirp.h
@@ -0,0 +1,51 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-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.
+ */
+#ifndef QEMU_NET_SLIRP_H
+#define QEMU_NET_SLIRP_H
+
+#include "qemu-common.h"
+#include "qdict.h"
+#include "qemu-option.h"
+
+#ifdef CONFIG_SLIRP
+
+int net_init_slirp(QemuOpts *opts,
+ Monitor *mon,
+ const char *name,
+ VLANState *vlan);
+
+void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict);
+void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict);
+
+int net_slirp_redir(const char *redir_str);
+
+int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret);
+
+int net_slirp_smb(const char *exported_dir);
+
+void do_info_usernet(Monitor *mon);
+
+#endif
+
+#endif /* QEMU_NET_SLIRP_H */
diff --git a/vl.c b/vl.c
index ee43808..6038e2d 100644
--- a/vl.c
+++ b/vl.c
@@ -140,6 +140,7 @@ int main(int argc, char **argv)
#include "hw/loader.h"
#include "bt-host.h"
#include "net.h"
+#include "net/slirp.h"
#include "monitor.h"
#include "console.h"
#include "sysemu.h"
--
1.6.5.2
next prev parent reply other threads:[~2009-11-25 18:52 UTC|newest]
Thread overview: 47+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-11-25 18:48 [Qemu-devel] [PATCH 00/44] Fix announce_self(), misc net fixes and cleanups Mark McLoughlin
2009-11-25 18:48 ` Mark McLoughlin [this message]
2009-11-25 18:48 ` [Qemu-devel] [PATCH 02/44] net: move vde code from net.c to net/vde.c Mark McLoughlin
2009-11-25 18:48 ` [Qemu-devel] [PATCH 03/44] net: move socket backend code from net.c to net/socket.c Mark McLoughlin
2009-11-25 18:48 ` [Qemu-devel] [PATCH 04/44] net: move dump backend code from net.c to net/dump.c Mark McLoughlin
2009-11-25 18:48 ` [Qemu-devel] [PATCH 05/44] net: clean up includes in net.c Mark McLoughlin
2009-11-25 18:48 ` [Qemu-devel] [PATCH 06/44] net: remove NICInfo::vc Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 07/44] net: remove NICInfo::private Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 08/44] net: introduce NetClientInfo Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 09/44] net: introduce qemu_new_net_client() Mark McLoughlin
2009-11-25 20:36 ` Blue Swirl
2009-11-26 18:06 ` Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 10/44] qdev: move DO_UPCAST() into osdep.h Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 11/44] net: convert tap to NetClientInfo Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 12/44] net: convert tap-win32 " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 13/44] net: convert slirp " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 14/44] net: convert vde " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 15/44] net: convert socket " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 16/44] net: convert dump " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 17/44] net: introduce NICState and qemu_new_nic() Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 18/44] net: convert virtio to NICState Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 19/44] net: convert e1000 " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 20/44] net: convert rtl8139 " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 21/44] net: convert ne2000 " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 22/44] net: convert pcnet " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 23/44] net: convert eepro100 " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 24/44] net: convert dp8393x " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 25/44] net: convert etrax " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 26/44] net: convert LAN9118 " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 27/44] net: convert mcf_fec " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 28/44] net: convert mipsnet " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 29/44] net: convert musicpal " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 30/44] net: convert smc91c111 " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 31/44] net: convert stellaris " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 32/44] net: convert usb-net " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 33/44] net: convert xilinx_ethlite " Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 34/44] net: move parse_macaddr() to net/util.[ch] Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 35/44] net: convert xen to NICState Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 36/44] net: remove qemu_new_vlan_client() Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 37/44] net: remove VLANClientState members now in NetClientInfo Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 38/44] net: add qemu_foreach_nic() Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 39/44] net: fix qemu_announce_self() Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 40/44] net: print correct error for '-netdev ""' Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 41/44] net: fix TAP networking on host kernels without IFF_VNET_HDR support Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 42/44] net: check for TUNSETOFFLOAD support before trying to enable offload features Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 43/44] net: initialize vnet_hdr in net_init_tap() Mark McLoughlin
2009-11-25 18:49 ` [Qemu-devel] [PATCH 44/44] net: fix vnet_hdr handling in solaris tap code Mark McLoughlin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1259174977-26212-2-git-send-email-markmc@redhat.com \
--to=markmc@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.