aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-02-07 18:53:25 +0000
committerPeter Maydell <peter.maydell@linaro.org>2019-02-07 18:53:25 +0000
commite47f81b617684c4546af286d307b69014a83538a (patch)
tree11e4e8c6482d092d91ed9faed327f341f3cc69f8
parentff372bb5c469e14d6d64f788710b7c3e37c12e01 (diff)
parentee261c02332ea856352f250b295a8ecd1eeb748e (diff)
Merge remote-tracking branch 'remotes/thibault/tags/samuel-thibault' into staging
More work towards libslirp Marc-André Lureau (27): slirp: generalize guestfwd with a callback based approach net/slirp: simplify checking for cmd: prefix net/slirp: free forwarding rules on cleanup net/slirp: fix leaks on forwarding rule registration error slirp: add callbacks for timer slirp: replace trace functions with DEBUG calls slirp: replace QEMU_PACKED with SLIRP_PACKED slirp: replace most qemu socket utilities with slirp own version slirp: replace qemu_set_nonblock() slirp: add unregister_poll_fd() callback slirp: replace qemu_notify_event() with a callback slirp: move QEMU state saving to a separate unit slirp: do not include qemu headers in libslirp.h public API header slirp: improve windows headers inclusion slirp: add slirp own version of pstrcpy slirp: remove qemu timer.h dependency slirp: remove now useless QEMU headers inclusions slirp: replace net/eth.h inclusion with own defines slirp: replace qemu qtailq with slirp own copy slirp: replace remaining qemu headers dependency slirp: prefer c99 types over BSD kind slirp: improve send_packet() callback slirp: replace global polling with per-instance & notifier slirp: remove slirp_instances list slirp: use polling callbacks, drop glib requirement slirp: pass opaque to all callbacks slirp: API is extern C Peter Maydell (2): slirp: Avoid marking naturally packed structs as QEMU_PACKED slirp: Don't mark struct ipq or struct ipasfrag as packed Samuel Thibault (3): slirp: Avoid unaligned 16bit memory access slirp: replace QEMU_BUILD_BUG_ON with G_STATIC_ASSERT slirp: Move g_spawn_async_with_fds_qemu compatibility to slirp/ # gpg: Signature made Thu 07 Feb 2019 14:02:41 GMT # gpg: using RSA key E61DBB15D4172BDEC97E92D9DB550E89F0FA54F3 # gpg: Good signature from "Samuel Thibault <samuel.thibault@aquilenet.fr>" [unknown] # gpg: aka "Samuel Thibault <sthibault@debian.org>" [marginal] # gpg: aka "Samuel Thibault <samuel.thibault@gnu.org>" [unknown] # gpg: aka "Samuel Thibault <samuel.thibault@inria.fr>" [marginal] # gpg: aka "Samuel Thibault <samuel.thibault@labri.fr>" [marginal] # gpg: aka "Samuel Thibault <samuel.thibault@ens-lyon.org>" [marginal] # gpg: aka "Samuel Thibault <samuel.thibault@u-bordeaux.fr>" [unknown] # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 900C B024 B679 31D4 0F82 304B D017 8C76 7D06 9EE6 # Subkey fingerprint: E61D BB15 D417 2BDE C97E 92D9 DB55 0E89 F0FA 54F3 * remotes/thibault/tags/samuel-thibault: (32 commits) slirp: API is extern C slirp: pass opaque to all callbacks slirp: use polling callbacks, drop glib requirement slirp: remove slirp_instances list slirp: replace global polling with per-instance & notifier slirp: improve send_packet() callback slirp: prefer c99 types over BSD kind slirp: replace remaining qemu headers dependency slirp: Move g_spawn_async_with_fds_qemu compatibility to slirp/ slirp: replace QEMU_BUILD_BUG_ON with G_STATIC_ASSERT slirp: replace qemu qtailq with slirp own copy slirp: replace net/eth.h inclusion with own defines slirp: remove now useless QEMU headers inclusions slirp: remove qemu timer.h dependency slirp: add slirp own version of pstrcpy slirp: improve windows headers inclusion slirp: do not include qemu headers in libslirp.h public API header slirp: move QEMU state saving to a separate unit slirp: replace qemu_notify_event() with a callback slirp: add unregister_poll_fd() callback ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--Makefile.objs1
-rw-r--r--include/glib-compat.h57
-rw-r--r--include/net/net.h2
-rw-r--r--include/qemu/main-loop.h15
-rw-r--r--net/net.c4
-rw-r--r--net/slirp.c185
-rw-r--r--slirp/Makefile.objs4
-rw-r--r--slirp/arp_table.c3
-rw-r--r--slirp/bootp.c1
-rw-r--r--slirp/cksum.c1
-rw-r--r--slirp/debug.h13
-rw-r--r--slirp/dhcpv6.c4
-rw-r--r--slirp/dnssearch.c1
-rw-r--r--slirp/if.c4
-rw-r--r--slirp/ip.h17
-rw-r--r--slirp/ip6.h14
-rw-r--r--slirp/ip6_icmp.c27
-rw-r--r--slirp/ip6_icmp.h26
-rw-r--r--slirp/ip6_input.c1
-rw-r--r--slirp/ip6_output.c2
-rw-r--r--slirp/ip_icmp.c14
-rw-r--r--slirp/ip_icmp.h18
-rw-r--r--slirp/ip_input.c5
-rw-r--r--slirp/ip_output.c1
-rw-r--r--slirp/libslirp.h71
-rw-r--r--slirp/main.h2
-rw-r--r--slirp/mbuf.c1
-rw-r--r--slirp/mbuf.h2
-rw-r--r--slirp/misc.c126
-rw-r--r--slirp/misc.h15
-rw-r--r--slirp/ncsi.c3
-rw-r--r--slirp/ndp_table.c2
-rw-r--r--slirp/qtailq.h193
-rw-r--r--slirp/sbuf.c8
-rw-r--r--slirp/sbuf.h2
-rw-r--r--slirp/slirp.c981
-rw-r--r--slirp/slirp.h45
-rw-r--r--slirp/socket.c33
-rw-r--r--slirp/socket.h9
-rw-r--r--slirp/state.c394
-rw-r--r--slirp/state.h9
-rw-r--r--slirp/tcp_input.c29
-rw-r--r--slirp/tcp_output.c13
-rw-r--r--slirp/tcp_subr.c49
-rw-r--r--slirp/tcp_timer.c3
-rw-r--r--slirp/tcp_var.h14
-rw-r--r--slirp/tftp.c16
-rw-r--r--slirp/trace-events5
-rw-r--r--slirp/udp.c16
-rw-r--r--slirp/udp.h2
-rw-r--r--slirp/udp6.c2
-rw-r--r--slirp/util.c207
-rw-r--r--slirp/util.h127
-rw-r--r--stubs/Makefile.objs3
-rw-r--r--stubs/slirp.c13
-rw-r--r--util/main-loop.c30
-rw-r--r--util/osdep.c2
57 files changed, 1828 insertions, 1019 deletions
diff --git a/Makefile.objs b/Makefile.objs
index 67a054b08a..b7aae33367 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -192,7 +192,6 @@ trace-events-subdirs += net
trace-events-subdirs += qapi
trace-events-subdirs += qom
trace-events-subdirs += scsi
-trace-events-subdirs += slirp
trace-events-subdirs += target/arm
trace-events-subdirs += target/i386
trace-events-subdirs += target/mips
diff --git a/include/glib-compat.h b/include/glib-compat.h
index 8a078c5288..1291628e09 100644
--- a/include/glib-compat.h
+++ b/include/glib-compat.h
@@ -83,63 +83,6 @@ static inline gboolean g_strv_contains_qemu(const gchar *const *strv,
}
#define g_strv_contains(a, b) g_strv_contains_qemu(a, b)
-#if !GLIB_CHECK_VERSION(2, 58, 0)
-typedef struct QemuGSpawnFds {
- GSpawnChildSetupFunc child_setup;
- gpointer user_data;
- gint stdin_fd;
- gint stdout_fd;
- gint stderr_fd;
-} QemuGSpawnFds;
-
-static inline void
-qemu_gspawn_fds_setup(gpointer user_data)
-{
- QemuGSpawnFds *q = (QemuGSpawnFds *)user_data;
-
- dup2(q->stdin_fd, 0);
- dup2(q->stdout_fd, 1);
- dup2(q->stderr_fd, 2);
- q->child_setup(q->user_data);
-}
-#endif
-
-static inline gboolean
-g_spawn_async_with_fds_qemu(const gchar *working_directory,
- gchar **argv,
- gchar **envp,
- GSpawnFlags flags,
- GSpawnChildSetupFunc child_setup,
- gpointer user_data,
- GPid *child_pid,
- gint stdin_fd,
- gint stdout_fd,
- gint stderr_fd,
- GError **error)
-{
-#if GLIB_CHECK_VERSION(2, 58, 0)
- return g_spawn_async_with_fds(working_directory, argv, envp, flags,
- child_setup, user_data,
- child_pid, stdin_fd, stdout_fd, stderr_fd,
- error);
-#else
- QemuGSpawnFds setup = {
- .child_setup = child_setup,
- .user_data = user_data,
- .stdin_fd = stdin_fd,
- .stdout_fd = stdout_fd,
- .stderr_fd = stderr_fd,
- };
-
- return g_spawn_async(working_directory, argv, envp, flags,
- qemu_gspawn_fds_setup, &setup,
- child_pid, error);
-#endif
-}
-
-#define g_spawn_async_with_fds(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) \
- g_spawn_async_with_fds_qemu(wd, argv, env, f, c, d, p, ifd, ofd, efd, err)
-
#if defined(_WIN32) && !GLIB_CHECK_VERSION(2, 50, 0)
/*
* g_poll has a problem on Windows when using
diff --git a/include/net/net.h b/include/net/net.h
index 643295d163..075cc01267 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -146,7 +146,7 @@ ssize_t qemu_sendv_packet(NetClientState *nc, const struct iovec *iov,
int iovcnt);
ssize_t qemu_sendv_packet_async(NetClientState *nc, const struct iovec *iov,
int iovcnt, NetPacketSent *sent_cb);
-void qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size);
+ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size);
ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size);
ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf,
int size, NetPacketSent *sent_cb);
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index e59f9ae1e9..f6ba78ea73 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -302,4 +302,19 @@ void qemu_fd_register(int fd);
QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
void qemu_bh_schedule_idle(QEMUBH *bh);
+enum {
+ MAIN_LOOP_POLL_FILL,
+ MAIN_LOOP_POLL_ERR,
+ MAIN_LOOP_POLL_OK,
+};
+
+typedef struct MainLoopPoll {
+ int state;
+ uint32_t timeout;
+ GArray *pollfds;
+} MainLoopPoll;
+
+void main_loop_poll_add_notifier(Notifier *notify);
+void main_loop_poll_remove_notifier(Notifier *notify);
+
#endif
diff --git a/net/net.c b/net/net.c
index 3acbdccd61..5dcff7fe2a 100644
--- a/net/net.c
+++ b/net/net.c
@@ -668,9 +668,9 @@ ssize_t qemu_send_packet_async(NetClientState *sender,
buf, size, sent_cb);
}
-void qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size)
+ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size)
{
- qemu_send_packet_async(nc, buf, size, NULL);
+ return qemu_send_packet_async(nc, buf, size, NULL);
}
ssize_t qemu_send_packet_raw(NetClientState *nc, const uint8_t *buf, int size)
diff --git a/net/slirp.c b/net/slirp.c
index f98425ee9f..7a16d8d615 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -75,14 +75,23 @@ struct slirp_config_str {
char str[1024];
};
+struct GuestFwd {
+ CharBackend hd;
+ struct in_addr server;
+ int port;
+ Slirp *slirp;
+};
+
typedef struct SlirpState {
NetClientState nc;
QTAILQ_ENTRY(SlirpState) entry;
Slirp *slirp;
+ Notifier poll_notifier;
Notifier exit_notifier;
#ifndef _WIN32
gchar *smb_dir;
#endif
+ GSList *fwd;
} SlirpState;
static struct slirp_config_str *slirp_configs;
@@ -100,11 +109,12 @@ static void slirp_smb_cleanup(SlirpState *s);
static inline void slirp_smb_cleanup(SlirpState *s) { }
#endif
-static void net_slirp_output(void *opaque, const uint8_t *pkt, int pkt_len)
+static ssize_t net_slirp_send_packet(const void *pkt, size_t pkt_len,
+ void *opaque)
{
SlirpState *s = opaque;
- qemu_send_packet(&s->nc, pkt, pkt_len);
+ return qemu_send_packet(&s->nc, pkt, pkt_len);
}
static ssize_t net_slirp_receive(NetClientState *nc, const uint8_t *buf, size_t size)
@@ -122,10 +132,20 @@ static void slirp_smb_exit(Notifier *n, void *data)
slirp_smb_cleanup(s);
}
+static void slirp_free_fwd(gpointer data)
+{
+ struct GuestFwd *fwd = data;
+
+ qemu_chr_fe_deinit(&fwd->hd, true);
+ g_free(data);
+}
+
static void net_slirp_cleanup(NetClientState *nc)
{
SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
+ g_slist_free_full(s->fwd, slirp_free_fwd);
+ main_loop_poll_remove_notifier(&s->poll_notifier);
slirp_cleanup(s->slirp);
if (s->exit_notifier.notify) {
qemu_remove_exit_notifier(&s->exit_notifier);
@@ -141,22 +161,148 @@ static NetClientInfo net_slirp_info = {
.cleanup = net_slirp_cleanup,
};
-static void net_slirp_guest_error(const char *msg)
+static void net_slirp_guest_error(const char *msg, void *opaque)
{
qemu_log_mask(LOG_GUEST_ERROR, "%s", msg);
}
-static int64_t net_slirp_clock_get_ns(void)
+static int64_t net_slirp_clock_get_ns(void *opaque)
{
return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
}
+static void *net_slirp_timer_new(SlirpTimerCb cb,
+ void *cb_opaque, void *opaque)
+{
+ return timer_new_full(NULL, QEMU_CLOCK_VIRTUAL,
+ SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
+ cb, cb_opaque);
+}
+
+static void net_slirp_timer_free(void *timer, void *opaque)
+{
+ timer_del(timer);
+ timer_free(timer);
+}
+
+static void net_slirp_timer_mod(void *timer, int64_t expire_timer,
+ void *opaque)
+{
+ timer_mod(timer, expire_timer);
+}
+
+static void net_slirp_register_poll_fd(int fd, void *opaque)
+{
+ qemu_fd_register(fd);
+}
+
+static void net_slirp_unregister_poll_fd(int fd, void *opaque)
+{
+ /* no qemu_fd_unregister */
+}
+
+static void net_slirp_notify(void *opaque)
+{
+ qemu_notify_event();
+}
+
static const SlirpCb slirp_cb = {
- .output = net_slirp_output,
+ .send_packet = net_slirp_send_packet,
.guest_error = net_slirp_guest_error,
.clock_get_ns = net_slirp_clock_get_ns,
+ .timer_new = net_slirp_timer_new,
+ .timer_free = net_slirp_timer_free,
+ .timer_mod = net_slirp_timer_mod,
+ .register_poll_fd = net_slirp_register_poll_fd,
+ .unregister_poll_fd = net_slirp_unregister_poll_fd,
+ .notify = net_slirp_notify,
};
+static int slirp_poll_to_gio(int events)
+{
+ int ret = 0;
+
+ if (events & SLIRP_POLL_IN) {
+ ret |= G_IO_IN;
+ }
+ if (events & SLIRP_POLL_OUT) {
+ ret |= G_IO_OUT;
+ }
+ if (events & SLIRP_POLL_PRI) {
+ ret |= G_IO_PRI;
+ }
+ if (events & SLIRP_POLL_ERR) {
+ ret |= G_IO_ERR;
+ }
+ if (events & SLIRP_POLL_HUP) {
+ ret |= G_IO_HUP;
+ }
+
+ return ret;
+}
+
+static int net_slirp_add_poll(int fd, int events, void *opaque)
+{
+ GArray *pollfds = opaque;
+ GPollFD pfd = {
+ .fd = fd,
+ .events = slirp_poll_to_gio(events),
+ };
+ int idx = pollfds->len;
+ g_array_append_val(pollfds, pfd);
+ return idx;
+}
+
+static int slirp_gio_to_poll(int events)
+{
+ int ret = 0;
+
+ if (events & G_IO_IN) {
+ ret |= SLIRP_POLL_IN;
+ }
+ if (events & G_IO_OUT) {
+ ret |= SLIRP_POLL_OUT;
+ }
+ if (events & G_IO_PRI) {
+ ret |= SLIRP_POLL_PRI;
+ }
+ if (events & G_IO_ERR) {
+ ret |= SLIRP_POLL_ERR;
+ }
+ if (events & G_IO_HUP) {
+ ret |= SLIRP_POLL_HUP;
+ }
+
+ return ret;
+}
+
+static int net_slirp_get_revents(int idx, void *opaque)
+{
+ GArray *pollfds = opaque;
+
+ return slirp_gio_to_poll(g_array_index(pollfds, GPollFD, idx).revents);
+}
+
+static void net_slirp_poll_notify(Notifier *notifier, void *data)
+{
+ MainLoopPoll *poll = data;
+ SlirpState *s = container_of(notifier, SlirpState, poll_notifier);
+
+ switch (poll->state) {
+ case MAIN_LOOP_POLL_FILL:
+ slirp_pollfds_fill(s->slirp, &poll->timeout,
+ net_slirp_add_poll, poll->pollfds);
+ break;
+ case MAIN_LOOP_POLL_OK:
+ case MAIN_LOOP_POLL_ERR:
+ slirp_pollfds_poll(s->slirp, poll->state == MAIN_LOOP_POLL_ERR,
+ net_slirp_get_revents, poll->pollfds);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
static int net_slirp_init(NetClientState *peer, const char *model,
const char *name, int restricted,
bool ipv4, const char *vnetwork, const char *vhost,
@@ -377,6 +523,9 @@ static int net_slirp_init(NetClientState *peer, const char *model,
&slirp_cb, s);
QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
+ s->poll_notifier.notify = net_slirp_poll_notify;
+ main_loop_poll_add_notifier(&s->poll_notifier);
+
for (config = slirp_configs; config; config = config->next) {
if (config->flags & SLIRP_CFG_HOSTFWD) {
if (slirp_hostfwd(s, config->str, errp) < 0) {
@@ -704,8 +853,8 @@ static int slirp_smb(SlirpState* s, const char *exported_dir,
CONFIG_SMBD_COMMAND, s->smb_dir, smb_conf);
g_free(smb_conf);
- if (slirp_add_exec(s->slirp, NULL, smb_cmdline, &vserver_addr, 139) < 0 ||
- slirp_add_exec(s->slirp, NULL, smb_cmdline, &vserver_addr, 445) < 0) {
+ if (slirp_add_exec(s->slirp, smb_cmdline, &vserver_addr, 139) < 0 ||
+ slirp_add_exec(s->slirp, smb_cmdline, &vserver_addr, 445) < 0) {
slirp_smb_cleanup(s);
g_free(smb_cmdline);
error_setg(errp, "Conflicting/invalid smbserver address");
@@ -717,13 +866,6 @@ static int slirp_smb(SlirpState* s, const char *exported_dir,
#endif /* !defined(_WIN32) */
-struct GuestFwd {
- CharBackend hd;
- struct in_addr server;
- int port;
- Slirp *slirp;
-};
-
static int guestfwd_can_read(void *opaque)
{
struct GuestFwd *fwd = opaque;
@@ -736,6 +878,11 @@ static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size);
}
+static ssize_t guestfwd_write(const void *buf, size_t len, void *chr)
+{
+ return qemu_chr_fe_write_all(chr, buf, len);
+}
+
static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp)
{
struct in_addr server = { .s_addr = 0 };
@@ -768,8 +915,8 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp)
snprintf(buf, sizeof(buf), "guestfwd.tcp.%d", port);
- if ((strlen(p) > 4) && !strncmp(p, "cmd:", 4)) {
- if (slirp_add_exec(s->slirp, NULL, &p[4], &server, port) < 0) {
+ if (g_str_has_prefix(p, "cmd:")) {
+ if (slirp_add_exec(s->slirp, &p[4], &server, port) < 0) {
error_setg(errp, "Conflicting/invalid host:port in guest "
"forwarding rule '%s'", config_str);
return -1;
@@ -792,13 +939,16 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp)
qemu_chr_fe_init(&fwd->hd, chr, &err);
if (err) {
error_propagate(errp, err);
+ object_unparent(OBJECT(chr));
g_free(fwd);
return -1;
}
- if (slirp_add_exec(s->slirp, &fwd->hd, NULL, &server, port) < 0) {
+ if (slirp_add_guestfwd(s->slirp, guestfwd_write, &fwd->hd,
+ &server, port) < 0) {
error_setg(errp, "Conflicting/invalid host:port in guest "
"forwarding rule '%s'", config_str);
+ qemu_chr_fe_deinit(&fwd->hd, true);
g_free(fwd);
return -1;
}
@@ -808,6 +958,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp)
qemu_chr_fe_set_handlers(&fwd->hd, guestfwd_can_read, guestfwd_read,
NULL, NULL, fwd, NULL, true);
+ s->fwd = g_slist_append(s->fwd, fwd);
}
return 0;
diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs
index 959558c732..88340a583b 100644
--- a/slirp/Makefile.objs
+++ b/slirp/Makefile.objs
@@ -20,6 +20,7 @@ slirp.mo-objs = \
sbuf.o \
slirp.o \
socket.o \
+ state.o \
tcp_input.o \
tcp_output.o \
tcp_subr.o \
@@ -27,6 +28,7 @@ slirp.mo-objs = \
tftp.o \
udp.o \
udp6.o \
+ util.o \
$(NULL)
-slirp.mo-cflags = -DG_LOG_DOMAIN=\"Slirp\"
+slirp.mo-cflags = -DG_LOG_DOMAIN=\"Slirp\" -DWITH_QEMU
diff --git a/slirp/arp_table.c b/slirp/arp_table.c
index bf71b984ad..58eafdcfd8 100644
--- a/slirp/arp_table.c
+++ b/slirp/arp_table.c
@@ -22,9 +22,10 @@
* THE SOFTWARE.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
+#include <string.h>
+
void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
{
const uint32_t broadcast_addr =
diff --git a/slirp/bootp.c b/slirp/bootp.c
index 4c9a77eb98..d396849a05 100644
--- a/slirp/bootp.c
+++ b/slirp/bootp.c
@@ -21,7 +21,6 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
#if defined(_WIN32)
diff --git a/slirp/cksum.c b/slirp/cksum.c
index 84c858fafb..25bfa67348 100644
--- a/slirp/cksum.c
+++ b/slirp/cksum.c
@@ -30,7 +30,6 @@
* in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp
*/
-#include "qemu/osdep.h"
#include "slirp.h"
/*
diff --git a/slirp/debug.h b/slirp/debug.h
index 269d97d807..44d922df37 100644
--- a/slirp/debug.h
+++ b/slirp/debug.h
@@ -8,9 +8,10 @@
#ifndef DEBUG_H_
#define DEBUG_H_
-#define DBG_CALL 0x1
-#define DBG_MISC 0x2
-#define DBG_ERROR 0x4
+#define DBG_CALL (1 << 0)
+#define DBG_MISC (1 << 1)
+#define DBG_ERROR (1 << 2)
+#define DBG_TFTP (1 << 3)
extern int slirp_debug;
@@ -38,4 +39,10 @@ extern int slirp_debug;
} \
} while (0)
+#define DEBUG_TFTP(fmt, ...) do { \
+ if (G_UNLIKELY(slirp_debug & DBG_TFTP)) { \
+ g_debug(fmt, ##__VA_ARGS__); \
+ } \
+} while (0)
+
#endif /* DEBUG_H_ */
diff --git a/slirp/dhcpv6.c b/slirp/dhcpv6.c
index 752df40536..e655c7d5b1 100644
--- a/slirp/dhcpv6.c
+++ b/slirp/dhcpv6.c
@@ -20,8 +20,6 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "qemu/osdep.h"
-#include "qemu/log.h"
#include "slirp.h"
#include "dhcpv6.h"
@@ -61,7 +59,7 @@ static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen,
int len = odata[2] << 8 | odata[3];
if (len + 4 > olen) {
- slirp->cb->guest_error("Guest sent bad DHCPv6 packet!");
+ slirp->cb->guest_error("Guest sent bad DHCPv6 packet!", slirp->opaque);
return -E2BIG;
}
diff --git a/slirp/dnssearch.c b/slirp/dnssearch.c
index 8fb563321b..c459cece8d 100644
--- a/slirp/dnssearch.c
+++ b/slirp/dnssearch.c
@@ -22,7 +22,6 @@
* THE SOFTWARE.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
static const uint8_t RFC3397_OPT_DOMAIN_SEARCH = 119;
diff --git a/slirp/if.c b/slirp/if.c
index 73e3705740..1830cc396c 100644
--- a/slirp/if.c
+++ b/slirp/if.c
@@ -5,9 +5,7 @@
* terms and conditions of the copyright.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
-#include "qemu/timer.h"
static void
ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead)
@@ -148,7 +146,7 @@ diddit:
*/
void if_start(Slirp *slirp)
{
- uint64_t now = slirp->cb->clock_get_ns();
+ uint64_t now = slirp->cb->clock_get_ns(slirp->opaque);
bool from_batchq = false;
struct mbuf *ifm, *ifm_next, *ifqt;
diff --git a/slirp/ip.h b/slirp/ip.h
index 243b6c8b24..73a4d2a3d2 100644
--- a/slirp/ip.h
+++ b/slirp/ip.h
@@ -89,7 +89,7 @@ struct ip {
uint8_t ip_p; /* protocol */
uint16_t ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
-} QEMU_PACKED;
+} SLIRP_PACKED;
#define IP_MAXPACKET 65535 /* maximum packet size */
@@ -151,7 +151,7 @@ struct ip_timestamp {
n_long ipt_time;
} ipt_ta[1];
} ipt_timestamp;
-} QEMU_PACKED;
+} SLIRP_PACKED;
/* flag bits for ipt_flg */
#define IPOPT_TS_TSONLY 0 /* timestamps only */
@@ -181,11 +181,11 @@ struct ip_timestamp {
struct mbuf_ptr {
struct mbuf *mptr;
uint32_t dummy;
-} QEMU_PACKED;
+} SLIRP_PACKED;
#else
struct mbuf_ptr {
struct mbuf *mptr;
-} QEMU_PACKED;
+} SLIRP_PACKED;
#endif
struct qlink {
void *next, *prev;
@@ -201,7 +201,7 @@ struct ipovly {
uint16_t ih_len; /* protocol length */
struct in_addr ih_src; /* source internet address */
struct in_addr ih_dst; /* destination internet address */
-} QEMU_PACKED;
+} SLIRP_PACKED;
/*
* Ip reassembly queue structure. Each fragment
@@ -217,7 +217,7 @@ struct ipq {
uint8_t ipq_p; /* protocol of this fragment */
uint16_t ipq_id; /* sequence id for reassembly */
struct in_addr ipq_src,ipq_dst;
-} QEMU_PACKED;
+};
/*
* Ip header, when holding a fragment.
@@ -227,7 +227,10 @@ struct ipq {
struct ipasfrag {
struct qlink ipf_link;
struct ip ipf_ip;
-} QEMU_PACKED;
+};
+
+G_STATIC_ASSERT(offsetof(struct ipq, frag_link) ==
+ offsetof(struct ipasfrag, ipf_link));
#define ipf_off ipf_ip.ip_off
#define ipf_tos ipf_ip.ip_tos
diff --git a/slirp/ip6.h b/slirp/ip6.h
index 14e9c78735..1b3364f960 100644
--- a/slirp/ip6.h
+++ b/slirp/ip6.h
@@ -7,7 +7,7 @@
#define SLIRP_IP6_H
#include <glib.h>
-#include "net/eth.h"
+#include <string.h>
#define ALLNODES_MULTICAST { .s6_addr = \
{ 0xff, 0x02, 0x00, 0x00,\
@@ -133,7 +133,7 @@ struct ip6 {
uint8_t ip_nh; /* next header */
uint8_t ip_hl; /* hop limit */
struct in6_addr ip_src, ip_dst; /* source and dest address */
-} QEMU_PACKED;
+};
/*
* IPv6 pseudo-header used by upper-layer protocols
@@ -145,7 +145,15 @@ struct ip6_pseudohdr {
uint16_t ih_zero_hi; /* zero */
uint8_t ih_zero_lo; /* zero */
uint8_t ih_nh; /* next header */
-} QEMU_PACKED;
+};
+/*
+ * We don't want to mark these ip6 structs as packed as they are naturally
+ * correctly aligned; instead assert that there is no stray padding.
+ * If we marked the struct as packed then we would be unable to take
+ * the address of any of the fields in it.
+ */
+G_STATIC_ASSERT(sizeof(struct ip6) == 40);
+G_STATIC_ASSERT(sizeof(struct ip6_pseudohdr) == 40);
#endif
diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c
index 5261baae27..c1e3d30470 100644
--- a/slirp/ip6_icmp.c
+++ b/slirp/ip6_icmp.c
@@ -3,12 +3,8 @@
* Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
#include "ip6_icmp.h"
-#include "qemu/timer.h"
-#include "qemu/error-report.h"
-#include "qemu/log.h"
#define NDP_Interval g_rand_int_range(slirp->grand, \
NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval)
@@ -16,8 +12,10 @@
static void ra_timer_handler(void *opaque)
{
Slirp *slirp = opaque;
- timer_mod(slirp->ra_timer,
- slirp->cb->clock_get_ns() / SCALE_MS + NDP_Interval);
+
+ slirp->cb->timer_mod(slirp->ra_timer,
+ slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS + NDP_Interval,
+ slirp->opaque);
ndp_send_ra(slirp);
}
@@ -27,11 +25,10 @@ void icmp6_init(Slirp *slirp)
return;
}
- slirp->ra_timer = timer_new_full(NULL, QEMU_CLOCK_VIRTUAL,
- SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
- ra_timer_handler, slirp);
- timer_mod(slirp->ra_timer,
- slirp->cb->clock_get_ns() / SCALE_MS + NDP_Interval);
+ slirp->ra_timer = slirp->cb->timer_new(ra_timer_handler, slirp, slirp->opaque);
+ slirp->cb->timer_mod(slirp->ra_timer,
+ slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS + NDP_Interval,
+ slirp->opaque);
}
void icmp6_cleanup(Slirp *slirp)
@@ -40,8 +37,7 @@ void icmp6_cleanup(Slirp *slirp)
return;
}
- timer_del(slirp->ra_timer);
- timer_free(slirp->ra_timer);
+ slirp->cb->timer_free(slirp->ra_timer, slirp->opaque);
}
static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
@@ -340,7 +336,8 @@ static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
case ICMP6_NDP_RA:
DEBUG_CALL(" type = Router Advertisement");
- slirp->cb->guest_error("Warning: guest sent NDP RA, but shouldn't");
+ slirp->cb->guest_error("Warning: guest sent NDP RA, but shouldn't",
+ slirp->opaque);
break;
case ICMP6_NDP_NS:
@@ -374,7 +371,7 @@ static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
case ICMP6_NDP_REDIRECT:
DEBUG_CALL(" type = Redirect");
slirp->cb->guest_error(
- "Warning: guest sent NDP REDIRECT, but shouldn't");
+ "Warning: guest sent NDP REDIRECT, but shouldn't", slirp->opaque);
break;
}
}
diff --git a/slirp/ip6_icmp.h b/slirp/ip6_icmp.h
index 32b0914055..e8ed753db5 100644
--- a/slirp/ip6_icmp.h
+++ b/slirp/ip6_icmp.h
@@ -48,12 +48,16 @@ struct ndp_ra { /* Router Advertisement Message */
uint16_t lifetime; /* Router Lifetime */
uint32_t reach_time; /* Reachable Time */
uint32_t retrans_time; /* Retrans Timer */
-} QEMU_PACKED;
+};
+
+G_STATIC_ASSERT(sizeof(struct ndp_ra) == 12);
struct ndp_ns { /* Neighbor Solicitation Message */
uint32_t reserved;
struct in6_addr target; /* Target Address */
-} QEMU_PACKED;
+};
+
+G_STATIC_ASSERT(sizeof(struct ndp_ns) == 20);
struct ndp_na { /* Neighbor Advertisement Message */
#if G_BYTE_ORDER == G_BIG_ENDIAN
@@ -72,13 +76,17 @@ struct ndp_na { /* Neighbor Advertisement Message */
reserved_lo:24;
#endif
struct in6_addr target; /* Target Address */
-} QEMU_PACKED;
+};
+
+G_STATIC_ASSERT(sizeof(struct ndp_na) == 20);
struct ndp_redirect {
uint32_t reserved;
struct in6_addr target; /* Target Address */
struct in6_addr dest; /* Destination Address */
-} QEMU_PACKED;
+};
+
+G_STATIC_ASSERT(sizeof(struct ndp_redirect) == 36);
/*
* Structure of an icmpv6 header.
@@ -103,7 +111,9 @@ struct icmp6 {
#define icmp6_nns icmp6_body.ndp_ns
#define icmp6_nna icmp6_body.ndp_na
#define icmp6_redirect icmp6_body.ndp_redirect
-} QEMU_PACKED;
+};
+
+G_STATIC_ASSERT(sizeof(struct icmp6) == 40);
#define ICMP6_MINLEN 4
#define ICMP6_ERROR_MINLEN 8
@@ -134,16 +144,16 @@ struct ndpopt {
uint32_t pref_lt; /* Preferred Lifetime */
uint32_t reserved2;
struct in6_addr prefix;
- } QEMU_PACKED prefixinfo;
+ } SLIRP_PACKED prefixinfo;
#define ndpopt_prefixinfo ndpopt_body.prefixinfo
struct rdnss {
uint16_t reserved;
uint32_t lifetime;
struct in6_addr addr;
- } QEMU_PACKED rdnss;
+ } SLIRP_PACKED rdnss;
#define ndpopt_rdnss ndpopt_body.rdnss
} ndpopt_body;
-} QEMU_PACKED;
+} SLIRP_PACKED;
/* NDP options type */
#define NDPOPT_LINKLAYER_SOURCE 1 /* Source Link-Layer Address */
diff --git a/slirp/ip6_input.c b/slirp/ip6_input.c
index ab656a0a9d..1b8c003c66 100644
--- a/slirp/ip6_input.c
+++ b/slirp/ip6_input.c
@@ -3,7 +3,6 @@
* Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
#include "ip6_icmp.h"
diff --git a/slirp/ip6_output.c b/slirp/ip6_output.c
index 52c88ad691..19d1ae7748 100644
--- a/slirp/ip6_output.c
+++ b/slirp/ip6_output.c
@@ -3,8 +3,6 @@
* Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
*/
-#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "slirp.h"
/* Number of packets queued before we start sending
diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
index 7c7e042049..ce79c0b051 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -30,7 +30,6 @@
* ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp
*/
-#include "qemu/osdep.h"
#include "slirp.h"
#include "ip_icmp.h"
@@ -83,7 +82,7 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
struct ip *ip = mtod(m, struct ip *);
struct sockaddr_in addr;
- so->s = qemu_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+ so->s = slirp_socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (so->s == -1) {
return -1;
}
@@ -114,7 +113,8 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
void icmp_detach(struct socket *so)
{
- closesocket(so->s);
+ so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
+ slirp_closesocket(so->s);
sofree(so);
}
@@ -240,7 +240,7 @@ end_error:
#define ICMP_MAXDATALEN (IP_MSS-28)
void
-icmp_send_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
+icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
const char *message)
{
unsigned hlen, shlen, s_ip_len;
@@ -388,7 +388,7 @@ icmp_reflect(struct mbuf *m)
* Strip out original options by copying rest of first
* mbuf's data back, and adjust the IP length.
*/
- memmove((caddr_t)(ip + 1), (caddr_t)ip + hlen,
+ memmove((char *)(ip + 1), (char *)ip + hlen,
(unsigned )(m->m_len - hlen));
hlen -= optlen;
ip->ip_hl = hlen >> 2;
@@ -412,7 +412,7 @@ void icmp_receive(struct socket *so)
struct mbuf *m = so->so_m;
struct ip *ip = mtod(m, struct ip *);
int hlen = ip->ip_hl << 2;
- u_char error_code;
+ uint8_t error_code;
struct icmp *icp;
int id, len;
@@ -421,7 +421,7 @@ void icmp_receive(struct socket *so)
icp = mtod(m, struct icmp *);
id = icp->icmp_id;
- len = qemu_recv(so->s, icp, M_ROOM(m), 0);
+ len = slirp_recv(so->s, icp, M_ROOM(m), 0);
/*
* The behavior of reading SOCK_DGRAM+IPPROTO_ICMP sockets is inconsistent
* between host OSes. On Linux, only the ICMP header and payload is
diff --git a/slirp/ip_icmp.h b/slirp/ip_icmp.h
index d88ab34c1b..a4e5b8b265 100644
--- a/slirp/ip_icmp.h
+++ b/slirp/ip_icmp.h
@@ -44,22 +44,22 @@ typedef uint32_t n_time;
* Structure of an icmp header.
*/
struct icmp {
- u_char icmp_type; /* type of message, see below */
- u_char icmp_code; /* type sub code */
- u_short icmp_cksum; /* ones complement cksum of struct */
+ uint8_t icmp_type; /* type of message, see below */
+ uint8_t icmp_code; /* type sub code */
+ uint16_t icmp_cksum; /* ones complement cksum of struct */
union {
- u_char ih_pptr; /* ICMP_PARAMPROB */
+ uint8_t ih_pptr; /* ICMP_PARAMPROB */
struct in_addr ih_gwaddr; /* ICMP_REDIRECT */
struct ih_idseq {
- u_short icd_id;
- u_short icd_seq;
+ uint16_t icd_id;
+ uint16_t icd_seq;
} ih_idseq;
int ih_void;
/* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
struct ih_pmtu {
- u_short ipm_void;
- u_short ipm_nextmtu;
+ uint16_t ipm_void;
+ uint16_t ipm_nextmtu;
} ih_pmtu;
} icmp_hun;
#define icmp_pptr icmp_hun.ih_pptr
@@ -156,7 +156,7 @@ struct icmp {
void icmp_init(Slirp *slirp);
void icmp_cleanup(Slirp *slirp);
void icmp_input(struct mbuf *, int);
-void icmp_send_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
+void icmp_send_error(struct mbuf *msrc, uint8_t type, uint8_t code, int minsize,
const char *message);
void icmp_reflect(struct mbuf *);
void icmp_receive(struct socket *so);
diff --git a/slirp/ip_input.c b/slirp/ip_input.c
index d360620838..e0b94b0e42 100644
--- a/slirp/ip_input.c
+++ b/slirp/ip_input.c
@@ -38,7 +38,6 @@
* terms and conditions of the copyright.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
#include "ip_icmp.h"
@@ -459,11 +458,11 @@ ip_stripoptions(register struct mbuf *m, struct mbuf *mopt)
{
register int i;
struct ip *ip = mtod(m, struct ip *);
- register caddr_t opts;
+ register char *opts;
int olen;
olen = (ip->ip_hl<<2) - sizeof (struct ip);
- opts = (caddr_t)(ip + 1);
+ opts = (char *)(ip + 1);
i = m->m_len - (sizeof (struct ip) + olen);
memcpy(opts, opts + olen, (unsigned)i);
m->m_len -= olen;
diff --git a/slirp/ip_output.c b/slirp/ip_output.c
index db403f04c1..f6ec141df5 100644
--- a/slirp/ip_output.c
+++ b/slirp/ip_output.c
@@ -38,7 +38,6 @@
* terms and conditions of the copyright.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
/* Number of packets queued before we start sending
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index 4611a7447b..fccab42518 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -1,22 +1,64 @@
#ifndef LIBSLIRP_H
#define LIBSLIRP_H
-#include "qemu-common.h"
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <in6addr.h>
+#else
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
typedef struct Slirp Slirp;
+enum {
+ SLIRP_POLL_IN = 1 << 0,
+ SLIRP_POLL_OUT = 1 << 1,
+ SLIRP_POLL_PRI = 1 << 2,
+ SLIRP_POLL_ERR = 1 << 3,
+ SLIRP_POLL_HUP = 1 << 4,
+};
+
+typedef ssize_t (*SlirpWriteCb)(const void *buf, size_t len, void *opaque);
+typedef void (*SlirpTimerCb)(void *opaque);
+typedef int (*SlirpAddPollCb)(int fd, int events, void *opaque);
+typedef int (*SlirpGetREventsCb)(int idx, void *opaque);
+
/*
* Callbacks from slirp
- *
- * The opaque parameter comes from the opaque parameter given to slirp_init().
*/
typedef struct SlirpCb {
- /* Send an ethernet frame to the guest network. */
- void (*output)(void *opaque, const uint8_t *pkt, int pkt_len);
+ /*
+ * Send an ethernet frame to the guest network. The opaque
+ * parameter is the one given to slirp_init(). The function
+ * doesn't need to send all the data and may return <len (no
+ * buffering is done on libslirp side, so the data will be dropped
+ * in this case). <0 reports an IO error.
+ */
+ SlirpWriteCb send_packet;
/* Print a message for an error due to guest misbehavior. */
- void (*guest_error)(const char *msg);
+ void (*guest_error)(const char *msg, void *opaque);
/* Return the virtual clock value in nanoseconds */
- int64_t (*clock_get_ns)(void);
+ int64_t (*clock_get_ns)(void *opaque);
+ /* Create a new timer with the given callback and opaque data */
+ void *(*timer_new)(SlirpTimerCb cb, void *cb_opaque, void *opaque);
+ /* Remove and free a timer */
+ void (*timer_free)(void *timer, void *opaque);
+ /* Modify a timer to expire at @expire_time */
+ void (*timer_mod)(void *timer, int64_t expire_time, void *opaque);
+ /* Register a fd for future polling */
+ void (*register_poll_fd)(int fd, void *opaque);
+ /* Unregister a fd */
+ void (*unregister_poll_fd)(int fd, void *opaque);
+ /* Kick the io-thread, to signal that new events may be processed */
+ void (*notify)(void *opaque);
} SlirpCb;
@@ -34,9 +76,11 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
void *opaque);
void slirp_cleanup(Slirp *slirp);
-void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout);
+void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
+ SlirpAddPollCb add_poll, void *opaque);
-void slirp_pollfds_poll(GArray *pollfds, int select_error);
+void slirp_pollfds_poll(Slirp *slirp, int select_error,
+ SlirpGetREventsCb get_revents, void *opaque);
void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len);
@@ -45,7 +89,9 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp,
struct in_addr guest_addr, int guest_port);
int slirp_remove_hostfwd(Slirp *slirp, int is_udp,
struct in_addr host_addr, int host_port);
-int slirp_add_exec(Slirp *slirp, void *chardev, const char *cmdline,
+int slirp_add_exec(Slirp *slirp, const char *cmdline,
+ struct in_addr *guest_addr, int guest_port);
+int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
struct in_addr *guest_addr, int guest_port);
char *slirp_connection_info(Slirp *slirp);
@@ -54,5 +100,8 @@ void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr,
int guest_port, const uint8_t *buf, int size);
size_t slirp_socket_can_recv(Slirp *slirp, struct in_addr guest_addr,
int guest_port);
-
+#ifdef __cplusplus
+} /* extern "C" */
#endif
+
+#endif /* LIBSLIRP_H */
diff --git a/slirp/main.h b/slirp/main.h
index 4bc05fb904..f11d4572b7 100644
--- a/slirp/main.h
+++ b/slirp/main.h
@@ -8,7 +8,7 @@
#ifndef SLIRP_MAIN_H
#define SLIRP_MAIN_H
-extern u_int curtime;
+extern unsigned curtime;
extern struct in_addr loopback_addr;
extern unsigned long loopback_mask;
diff --git a/slirp/mbuf.c b/slirp/mbuf.c
index d8d275e0e7..521c02c967 100644
--- a/slirp/mbuf.c
+++ b/slirp/mbuf.c
@@ -15,7 +15,6 @@
* the flags
*/
-#include "qemu/osdep.h"
#include "slirp.h"
#define MBUF_THRESH 30
diff --git a/slirp/mbuf.h b/slirp/mbuf.h
index cbf17e136b..e2d443418a 100644
--- a/slirp/mbuf.h
+++ b/slirp/mbuf.h
@@ -85,7 +85,7 @@ struct mbuf {
int m_size; /* Size of mbuf, from m_dat or m_ext */
struct socket *m_so;
- caddr_t m_data; /* Current location of data */
+ char *m_data; /* Current location of data */
int m_len; /* Amount of data in this mbuf, from m_data */
Slirp *slirp;
diff --git a/slirp/misc.c b/slirp/misc.c
index eae9596a55..3f4cd852f8 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -5,11 +5,7 @@
* terms and conditions of the copyright.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
-#include "libslirp.h"
-#include "qemu/error-report.h"
-#include "qemu/main-loop.h"
inline void
insque(void *a, void *b)
@@ -32,24 +28,33 @@ remque(void *a)
element->qh_rlink = NULL;
}
-int add_exec(struct gfwd_list **ex_ptr, void *chardev, const char *cmdline,
+struct gfwd_list *
+add_guestfwd(struct gfwd_list **ex_ptr,
+ SlirpWriteCb write_cb, void *opaque,
struct in_addr addr, int port)
{
- struct gfwd_list *tmp_ptr;
-
- tmp_ptr = *ex_ptr;
- *ex_ptr = g_new0(struct gfwd_list, 1);
- (*ex_ptr)->ex_fport = port;
- (*ex_ptr)->ex_addr = addr;
- if (chardev) {
- (*ex_ptr)->ex_chardev = chardev;
- } else {
- (*ex_ptr)->ex_exec = g_strdup(cmdline);
- }
- (*ex_ptr)->ex_next = tmp_ptr;
- return 0;
+ struct gfwd_list *f = g_new0(struct gfwd_list, 1);
+
+ f->write_cb = write_cb;
+ f->opaque = opaque;
+ f->ex_fport = port;
+ f->ex_addr = addr;
+ f->ex_next = *ex_ptr;
+ *ex_ptr = f;
+
+ return f;
}
+struct gfwd_list *
+add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
+ struct in_addr addr, int port)
+{
+ struct gfwd_list *f = add_guestfwd(ex_ptr, NULL, NULL, addr, port);
+
+ f->ex_exec = g_strdup(cmdline);
+
+ return f;
+}
static int
slirp_socketpair_with_oob(int sv[2])
@@ -63,14 +68,14 @@ slirp_socketpair_with_oob(int sv[2])
int ret, s;
sv[1] = -1;
- s = qemu_socket(AF_INET, SOCK_STREAM, 0);
+ s = slirp_socket(AF_INET, SOCK_STREAM, 0);
if (s < 0 || bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
listen(s, 1) < 0 ||
getsockname(s, (struct sockaddr *)&addr, &addrlen) < 0) {
goto err;
}
- sv[1] = qemu_socket(AF_INET, SOCK_STREAM, 0);
+ sv[1] = slirp_socket(AF_INET, SOCK_STREAM, 0);
if (sv[1] < 0) {
goto err;
}
@@ -93,16 +98,16 @@ slirp_socketpair_with_oob(int sv[2])
goto err;
}
- closesocket(s);
+ slirp_closesocket(s);
return 0;
err:
g_critical("slirp_socketpair(): %s", strerror(errno));
if (s >= 0) {
- closesocket(s);
+ slirp_closesocket(s);
}
if (sv[1] >= 0) {
- closesocket(sv[1]);
+ slirp_closesocket(sv[1]);
}
return -1;
}
@@ -115,6 +120,68 @@ fork_exec_child_setup(gpointer data)
#endif
}
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+#if !GLIB_CHECK_VERSION(2, 58, 0)
+typedef struct SlirpGSpawnFds {
+ GSpawnChildSetupFunc child_setup;
+ gpointer user_data;
+ gint stdin_fd;
+ gint stdout_fd;
+ gint stderr_fd;
+} SlirpGSpawnFds;
+
+static inline void
+slirp_gspawn_fds_setup(gpointer user_data)
+{
+ SlirpGSpawnFds *q = (SlirpGSpawnFds *)user_data;
+
+ dup2(q->stdin_fd, 0);
+ dup2(q->stdout_fd, 1);
+ dup2(q->stderr_fd, 2);
+ q->child_setup(q->user_data);
+}
+#endif
+
+static inline gboolean
+g_spawn_async_with_fds_slirp(const gchar *working_directory,
+ gchar **argv,
+ gchar **envp,
+ GSpawnFlags flags,
+ GSpawnChildSetupFunc child_setup,
+ gpointer user_data,
+ GPid *child_pid,
+ gint stdin_fd,
+ gint stdout_fd,
+ gint stderr_fd,
+ GError **error)
+{
+#if GLIB_CHECK_VERSION(2, 58, 0)
+ return g_spawn_async_with_fds(working_directory, argv, envp, flags,
+ child_setup, user_data,
+ child_pid, stdin_fd, stdout_fd, stderr_fd,
+ error);
+#else
+ SlirpGSpawnFds setup = {
+ .child_setup = child_setup,
+ .user_data = user_data,
+ .stdin_fd = stdin_fd,
+ .stdout_fd = stdout_fd,
+ .stderr_fd = stderr_fd,
+ };
+
+ return g_spawn_async(working_directory, argv, envp, flags,
+ slirp_gspawn_fds_setup, &setup,
+ child_pid, error);
+#endif
+}
+
+#define g_spawn_async_with_fds(wd, argv, env, f, c, d, p, ifd, ofd, efd, err) \
+ g_spawn_async_with_fds_slirp(wd, argv, env, f, c, d, p, ifd, ofd, efd, err)
+
+#pragma GCC diagnostic pop
+
int
fork_exec(struct socket *so, const char *ex)
{
@@ -144,17 +211,18 @@ fork_exec(struct socket *so, const char *ex)
if (err) {
g_critical("fork_exec: %s", err->message);
g_error_free(err);
- closesocket(sp[0]);
- closesocket(sp[1]);
+ slirp_closesocket(sp[0]);
+ slirp_closesocket(sp[1]);
return 0;
}
so->s = sp[0];
- closesocket(sp[1]);
- socket_set_fast_reuse(so->s);
+ slirp_closesocket(sp[1]);
+ slirp_socket_set_fast_reuse(so->s);
opt = 1;
- qemu_setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
- qemu_set_nonblock(so->s);
+ slirp_setsockopt(so->s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
+ slirp_set_nonblock(so->s);
+ so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
return 1;
}
diff --git a/slirp/misc.h b/slirp/misc.h
index 1df707c052..c2ceadb591 100644
--- a/slirp/misc.h
+++ b/slirp/misc.h
@@ -8,8 +8,11 @@
#ifndef MISC_H
#define MISC_H
+#include "libslirp.h"
+
struct gfwd_list {
- void *ex_chardev;
+ SlirpWriteCb write_cb;
+ void *opaque;
struct in_addr ex_addr; /* Server address */
int ex_fport; /* Port to telnet to */
char *ex_exec; /* Command line of what to exec */
@@ -51,7 +54,15 @@ struct slirp_quehead {
void slirp_insque(void *, void *);
void slirp_remque(void *);
-int add_exec(struct gfwd_list **, void *, const char *, struct in_addr, int);
int fork_exec(struct socket *so, const char *ex);
+struct gfwd_list *
+add_guestfwd(struct gfwd_list **ex_ptr,
+ SlirpWriteCb write_cb, void *opaque,
+ struct in_addr addr, int port);
+
+struct gfwd_list *
+add_exec(struct gfwd_list **ex_ptr, const char *cmdline,
+ struct in_addr addr, int port);
+
#endif
diff --git a/slirp/ncsi.c b/slirp/ncsi.c
index 8594382270..359f52c284 100644
--- a/slirp/ncsi.c
+++ b/slirp/ncsi.c
@@ -6,7 +6,6 @@
* This code is licensed under the GPL version 2 or later. See the
* COPYING file in the top-level directory.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
#include "ncsi-pkt.h"
@@ -163,5 +162,5 @@ void ncsi_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
*pchecksum = htonl(checksum);
ncsi_rsp_len += 4;
- slirp->cb->output(slirp->opaque, ncsi_reply, ETH_HLEN + ncsi_rsp_len);
+ slirp_send_packet_all(slirp, ncsi_reply, ETH_HLEN + ncsi_rsp_len);
}
diff --git a/slirp/ndp_table.c b/slirp/ndp_table.c
index b7b73722f7..34ea4fdf1f 100644
--- a/slirp/ndp_table.c
+++ b/slirp/ndp_table.c
@@ -3,8 +3,6 @@
* Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
*/
-#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "slirp.h"
void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
diff --git a/slirp/qtailq.h b/slirp/qtailq.h
new file mode 100644
index 0000000000..a89b0c439a
--- /dev/null
+++ b/slirp/qtailq.h
@@ -0,0 +1,193 @@
+/* $NetBSD: queue.h,v 1.52 2009/04/20 09:56:08 mschuett Exp $ */
+
+/*
+ * slirp version: Copy from QEMU, removed all but tail queues.
+ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef QTAILQ_H
+#define QTAILQ_H
+
+/*
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ */
+typedef struct QTailQLink {
+ void *tql_next;
+ struct QTailQLink *tql_prev;
+} QTailQLink;
+
+/*
+ * Tail queue definitions. The union acts as a poor man template, as if
+ * it were QTailQLink<type>.
+ */
+#define QTAILQ_HEAD(name, type) \
+ union name { \
+ struct type *tqh_first; /* first element */ \
+ QTailQLink tqh_circ; /* link for circular backwards list */ \
+ }
+
+#define QTAILQ_HEAD_INITIALIZER(head) \
+ { .tqh_circ = { NULL, &(head).tqh_circ } }
+
+#define QTAILQ_ENTRY(type) \
+ union { \
+ struct type *tqe_next; /* next element */ \
+ QTailQLink tqe_circ; /* link for circular backwards list */ \
+ }
+
+#define QTAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_circ.tql_prev = &(head)->tqh_circ; \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_circ.tql_prev = \
+ &(elm)->field.tqe_circ; \
+ else \
+ (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_circ.tql_prev = &(head)->tqh_circ; \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_circ.tql_prev = (head)->tqh_circ.tql_prev; \
+ (head)->tqh_circ.tql_prev->tql_next = (elm); \
+ (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_circ.tql_prev = \
+ &(elm)->field.tqe_circ; \
+ else \
+ (head)->tqh_circ.tql_prev = &(elm)->field.tqe_circ; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_circ.tql_prev = &(listelm)->field.tqe_circ; \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_circ.tql_prev = (listelm)->field.tqe_circ.tql_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ (listelm)->field.tqe_circ.tql_prev->tql_next = (elm); \
+ (listelm)->field.tqe_circ.tql_prev = &(elm)->field.tqe_circ; \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_circ.tql_prev = \
+ (elm)->field.tqe_circ.tql_prev; \
+ else \
+ (head)->tqh_circ.tql_prev = (elm)->field.tqe_circ.tql_prev; \
+ (elm)->field.tqe_circ.tql_prev->tql_next = (elm)->field.tqe_next; \
+ (elm)->field.tqe_circ.tql_prev = NULL; \
+} while (/*CONSTCOND*/0)
+
+#define QTAILQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->tqh_first); \
+ (var); \
+ (var) = ((var)->field.tqe_next))
+
+#define QTAILQ_FOREACH_SAFE(var, head, field, next_var) \
+ for ((var) = ((head)->tqh_first); \
+ (var) && ((next_var) = ((var)->field.tqe_next), 1); \
+ (var) = (next_var))
+
+#define QTAILQ_FOREACH_REVERSE(var, head, field) \
+ for ((var) = QTAILQ_LAST(head); \
+ (var); \
+ (var) = QTAILQ_PREV(var, field))
+
+#define QTAILQ_FOREACH_REVERSE_SAFE(var, head, field, prev_var) \
+ for ((var) = QTAILQ_LAST(head); \
+ (var) && ((prev_var) = QTAILQ_PREV(var, field)); \
+ (var) = (prev_var))
+
+/*
+ * Tail queue access methods.
+ */
+#define QTAILQ_EMPTY(head) ((head)->tqh_first == NULL)
+#define QTAILQ_FIRST(head) ((head)->tqh_first)
+#define QTAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define QTAILQ_IN_USE(elm, field) ((elm)->field.tqe_circ.tql_prev != NULL)
+
+#define QTAILQ_LINK_PREV(link) \
+ ((link).tql_prev->tql_prev->tql_next)
+#define QTAILQ_LAST(head) \
+ ((typeof((head)->tqh_first)) QTAILQ_LINK_PREV((head)->tqh_circ))
+#define QTAILQ_PREV(elm, field) \
+ ((typeof((elm)->field.tqe_next)) QTAILQ_LINK_PREV((elm)->field.tqe_circ))
+
+#define field_at_offset(base, offset, type) \
+ ((type *) (((char *) (base)) + (offset)))
+
+/*
+ * Raw access of elements of a tail queue head. Offsets are all zero
+ * because it's a union.
+ */
+#define QTAILQ_RAW_FIRST(head) \
+ field_at_offset(head, 0, void *)
+#define QTAILQ_RAW_TQH_CIRC(head) \
+ field_at_offset(head, 0, QTailQLink)
+
+/*
+ * Raw access of elements of a tail entry
+ */
+#define QTAILQ_RAW_NEXT(elm, entry) \
+ field_at_offset(elm, entry, void *)
+#define QTAILQ_RAW_TQE_CIRC(elm, entry) \
+ field_at_offset(elm, entry, QTailQLink)
+/*
+ * Tail queue traversal using pointer arithmetic.
+ */
+#define QTAILQ_RAW_FOREACH(elm, head, entry) \
+ for ((elm) = *QTAILQ_RAW_FIRST(head); \
+ (elm); \
+ (elm) = *QTAILQ_RAW_NEXT(elm, entry))
+/*
+ * Tail queue insertion using pointer arithmetic.
+ */
+#define QTAILQ_RAW_INSERT_TAIL(head, elm, entry) do { \
+ *QTAILQ_RAW_NEXT(elm, entry) = NULL; \
+ QTAILQ_RAW_TQE_CIRC(elm, entry)->tql_prev = QTAILQ_RAW_TQH_CIRC(head)->tql_prev; \
+ QTAILQ_RAW_TQH_CIRC(head)->tql_prev->tql_next = (elm); \
+ QTAILQ_RAW_TQH_CIRC(head)->tql_prev = QTAILQ_RAW_TQE_CIRC(elm, entry); \
+} while (/*CONSTCOND*/0)
+
+#endif /* QTAILQ_H */
diff --git a/slirp/sbuf.c b/slirp/sbuf.c
index 912f235f65..51a9f0cc7d 100644
--- a/slirp/sbuf.c
+++ b/slirp/sbuf.c
@@ -5,9 +5,7 @@
* terms and conditions of the copyright.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
-#include "qemu/main-loop.h"
static void sbappendsb(struct sbuf *sb, struct mbuf *m);
@@ -17,7 +15,7 @@ sbfree(struct sbuf *sb)
free(sb->sb_data);
}
-void
+bool
sbdrop(struct sbuf *sb, int num)
{
int limit = sb->sb_datalen / 2;
@@ -34,8 +32,10 @@ sbdrop(struct sbuf *sb, int num)
sb->sb_rptr -= sb->sb_datalen;
if (sb->sb_cc < limit && sb->sb_cc + num >= limit) {
- qemu_notify_event();
+ return true;
}
+
+ return false;
}
void
diff --git a/slirp/sbuf.h b/slirp/sbuf.h
index 644c201341..1cb9a42834 100644
--- a/slirp/sbuf.h
+++ b/slirp/sbuf.h
@@ -21,7 +21,7 @@ struct sbuf {
};
void sbfree(struct sbuf *);
-void sbdrop(struct sbuf *, int);
+bool sbdrop(struct sbuf *, int);
void sbreserve(struct sbuf *, int);
void sbappend(struct socket *, struct mbuf *);
void sbcopy(struct sbuf *, int, int, char *);
diff --git a/slirp/slirp.c b/slirp/slirp.c
index a9674ab090..a746c6fd86 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -21,15 +21,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/timer.h"
-#include "qemu/error-report.h"
-#include "chardev/char-fe.h"
-#include "migration/register.h"
#include "slirp.h"
-#include "hw/hw.h"
-#include "qemu/cutils.h"
+
+#ifdef WITH_QEMU
+#include "state.h"
+#endif
#ifndef _WIN32
#include <net/if.h>
@@ -50,18 +46,15 @@ static const uint8_t special_ethaddr[ETH_ALEN] = {
0x52, 0x55, 0x00, 0x00, 0x00, 0x00
};
-u_int curtime;
-
-static QTAILQ_HEAD(, Slirp) slirp_instances =
- QTAILQ_HEAD_INITIALIZER(slirp_instances);
+unsigned curtime;
static struct in_addr dns_addr;
#ifndef _WIN32
static struct in6_addr dns6_addr;
#endif
-static u_int dns_addr_time;
+static unsigned dns_addr_time;
#ifndef _WIN32
-static u_int dns6_addr_time;
+static unsigned dns6_addr_time;
#endif
#define TIMEOUT_FAST 2 /* milliseconds */
@@ -96,7 +89,7 @@ int get_dns_addr(struct in_addr *pdns_addr)
}
if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
- printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
+ printf("GetNetworkParams failed. ret = %08x\n", (unsigned)ret );
if (FixedInfo) {
GlobalFree(FixedInfo);
FixedInfo = NULL;
@@ -130,7 +123,7 @@ static void winsock_cleanup(void)
static int get_dns_addr_cached(void *pdns_addr, void *cached_addr,
socklen_t addrlen,
- struct stat *cached_stat, u_int *cached_time)
+ struct stat *cached_stat, unsigned *cached_time)
{
struct stat old_stat;
if (curtime - *cached_time < TIMEOUT_DEFAULT) {
@@ -153,7 +146,7 @@ static int get_dns_addr_cached(void *pdns_addr, void *cached_addr,
static int get_dns_addr_resolv_conf(int af, void *pdns_addr, void *cached_addr,
socklen_t addrlen, uint32_t *scope_id,
- u_int *cached_time)
+ unsigned *cached_time)
{
char buff[512];
char buff2[257];
@@ -271,6 +264,7 @@ static void slirp_init_once(void)
{ "call", DBG_CALL },
{ "misc", DBG_MISC },
{ "error", DBG_ERROR },
+ { "tftp", DBG_TFTP },
};
slirp_debug = g_parse_debug_string(debug, keys, G_N_ELEMENTS(keys));
}
@@ -278,14 +272,6 @@ static void slirp_init_once(void)
}
-static void slirp_state_save(QEMUFile *f, void *opaque);
-static int slirp_state_load(QEMUFile *f, void *opaque, int version_id);
-
-static SaveVMHandlers savevm_slirp_state = {
- .save_state = slirp_state_save,
- .load_state = slirp_state_load,
-};
-
Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
struct in_addr vnetmask, struct in_addr vhost,
bool in6_enabled,
@@ -303,6 +289,7 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
slirp_init_once();
+ slirp->opaque = opaque;
slirp->cb = callbacks;
slirp->grand = g_rand_new();
slirp->restricted = restricted;
@@ -324,8 +311,8 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
slirp->vprefix_len = vprefix_len;
slirp->vhost_addr6 = vhost6;
if (vhostname) {
- pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
- vhostname);
+ slirp_pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
+ vhostname);
}
slirp->tftp_prefix = g_strdup(tftp_path);
slirp->bootp_filename = g_strdup(bootfile);
@@ -339,12 +326,9 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork,
translate_dnssearch(slirp, vdnssearch);
}
- slirp->opaque = opaque;
-
- register_savevm_live(NULL, "slirp", 0, 4, &savevm_slirp_state, slirp);
-
- QTAILQ_INSERT_TAIL(&slirp_instances, slirp, entry);
-
+#ifdef WITH_QEMU
+ slirp_state_register(slirp);
+#endif
return slirp;
}
@@ -358,10 +342,9 @@ void slirp_cleanup(Slirp *slirp)
g_free(e);
}
- QTAILQ_REMOVE(&slirp_instances, slirp, entry);
-
- unregister_savevm(NULL, "slirp", slirp);
-
+#ifdef WITH_QEMU
+ slirp_state_unregister(slirp);
+#endif
ip_cleanup(slirp);
ip6_cleanup(slirp);
m_cleanup(slirp);
@@ -378,9 +361,8 @@ void slirp_cleanup(Slirp *slirp)
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
-static void slirp_update_timeout(uint32_t *timeout)
+static void slirp_update_timeout(Slirp *slirp, uint32_t *timeout)
{
- Slirp *slirp;
uint32_t t;
if (*timeout <= TIMEOUT_FAST) {
@@ -392,370 +374,332 @@ static void slirp_update_timeout(uint32_t *timeout)
/* If we have tcp timeout with slirp, then we will fill @timeout with
* more precise value.
*/
- QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
- if (slirp->time_fasttimo) {
- *timeout = TIMEOUT_FAST;
- return;
- }
- if (slirp->do_slowtimo) {
- t = MIN(TIMEOUT_SLOW, t);
- }
+ if (slirp->time_fasttimo) {
+ *timeout = TIMEOUT_FAST;
+ return;
+ }
+ if (slirp->do_slowtimo) {
+ t = MIN(TIMEOUT_SLOW, t);
}
*timeout = t;
}
-void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
+void slirp_pollfds_fill(Slirp *slirp, uint32_t *timeout,
+ SlirpAddPollCb add_poll, void *opaque)
{
- Slirp *slirp;
struct socket *so, *so_next;
- if (QTAILQ_EMPTY(&slirp_instances)) {
- return;
- }
-
/*
* First, TCP sockets
*/
- QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
- /*
- * *_slowtimo needs calling if there are IP fragments
- * in the fragment queue, or there are TCP connections active
- */
- slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
- (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
+ /*
+ * *_slowtimo needs calling if there are IP fragments
+ * in the fragment queue, or there are TCP connections active
+ */
+ slirp->do_slowtimo = ((slirp->tcb.so_next != &slirp->tcb) ||
+ (&slirp->ipq.ip_link != slirp->ipq.ip_link.next));
- for (so = slirp->tcb.so_next; so != &slirp->tcb;
- so = so_next) {
- int events = 0;
+ for (so = slirp->tcb.so_next; so != &slirp->tcb; so = so_next) {
+ int events = 0;
- so_next = so->so_next;
+ so_next = so->so_next;
- so->pollfds_idx = -1;
+ so->pollfds_idx = -1;
- /*
- * See if we need a tcp_fasttimo
- */
- if (slirp->time_fasttimo == 0 &&
- so->so_tcpcb->t_flags & TF_DELACK) {
- slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */
- }
-
- /*
- * NOFDREF can include still connecting to local-host,
- * newly socreated() sockets etc. Don't want to select these.
- */
- if (so->so_state & SS_NOFDREF || so->s == -1) {
- continue;
- }
-
- /*
- * Set for reading sockets which are accepting
- */
- if (so->so_state & SS_FACCEPTCONN) {
- GPollFD pfd = {
- .fd = so->s,
- .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
- };
- so->pollfds_idx = pollfds->len;
- g_array_append_val(pollfds, pfd);
- continue;
- }
+ /*
+ * See if we need a tcp_fasttimo
+ */
+ if (slirp->time_fasttimo == 0 &&
+ so->so_tcpcb->t_flags & TF_DELACK) {
+ slirp->time_fasttimo = curtime; /* Flag when want a fasttimo */
+ }
- /*
- * Set for writing sockets which are connecting
- */
- if (so->so_state & SS_ISFCONNECTING) {
- GPollFD pfd = {
- .fd = so->s,
- .events = G_IO_OUT | G_IO_ERR,
- };
- so->pollfds_idx = pollfds->len;
- g_array_append_val(pollfds, pfd);
- continue;
- }
+ /*
+ * NOFDREF can include still connecting to local-host,
+ * newly socreated() sockets etc. Don't want to select these.
+ */
+ if (so->so_state & SS_NOFDREF || so->s == -1) {
+ continue;
+ }
- /*
- * Set for writing if we are connected, can send more, and
- * we have something to send
- */
- if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
- events |= G_IO_OUT | G_IO_ERR;
- }
+ /*
+ * Set for reading sockets which are accepting
+ */
+ if (so->so_state & SS_FACCEPTCONN) {
+ so->pollfds_idx = add_poll(so->s,
+ SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
+ continue;
+ }
- /*
- * Set for reading (and urgent data) if we are connected, can
- * receive more, and we have room for it XXX /2 ?
- */
- if (CONN_CANFRCV(so) &&
- (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
- events |= G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI;
- }
+ /*
+ * Set for writing sockets which are connecting
+ */
+ if (so->so_state & SS_ISFCONNECTING) {
+ so->pollfds_idx = add_poll(so->s,
+ SLIRP_POLL_OUT | SLIRP_POLL_ERR, opaque);
+ continue;
+ }
- if (events) {
- GPollFD pfd = {
- .fd = so->s,
- .events = events,
- };
- so->pollfds_idx = pollfds->len;
- g_array_append_val(pollfds, pfd);
- }
+ /*
+ * Set for writing if we are connected, can send more, and
+ * we have something to send
+ */
+ if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
+ events |= SLIRP_POLL_OUT | SLIRP_POLL_ERR;
}
/*
- * UDP sockets
+ * Set for reading (and urgent data) if we are connected, can
+ * receive more, and we have room for it XXX /2 ?
*/
- for (so = slirp->udb.so_next; so != &slirp->udb;
- so = so_next) {
- so_next = so->so_next;
+ if (CONN_CANFRCV(so) &&
+ (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
+ events |= SLIRP_POLL_IN | SLIRP_POLL_HUP |
+ SLIRP_POLL_ERR | SLIRP_POLL_PRI;
+ }
- so->pollfds_idx = -1;
+ if (events) {
+ so->pollfds_idx = add_poll(so->s, events, opaque);
+ }
+ }
- /*
- * See if it's timed out
- */
- if (so->so_expire) {
- if (so->so_expire <= curtime) {
- udp_detach(so);
- continue;
- } else {
- slirp->do_slowtimo = true; /* Let socket expire */
- }
- }
+ /*
+ * UDP sockets
+ */
+ for (so = slirp->udb.so_next; so != &slirp->udb; so = so_next) {
+ so_next = so->so_next;
- /*
- * When UDP packets are received from over the
- * link, they're sendto()'d straight away, so
- * no need for setting for writing
- * Limit the number of packets queued by this session
- * to 4. Note that even though we try and limit this
- * to 4 packets, the session could have more queued
- * if the packets needed to be fragmented
- * (XXX <= 4 ?)
- */
- if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
- GPollFD pfd = {
- .fd = so->s,
- .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
- };
- so->pollfds_idx = pollfds->len;
- g_array_append_val(pollfds, pfd);
+ so->pollfds_idx = -1;
+
+ /*
+ * See if it's timed out
+ */
+ if (so->so_expire) {
+ if (so->so_expire <= curtime) {
+ udp_detach(so);
+ continue;
+ } else {
+ slirp->do_slowtimo = true; /* Let socket expire */
}
}
/*
- * ICMP sockets
+ * When UDP packets are received from over the
+ * link, they're sendto()'d straight away, so
+ * no need for setting for writing
+ * Limit the number of packets queued by this session
+ * to 4. Note that even though we try and limit this
+ * to 4 packets, the session could have more queued
+ * if the packets needed to be fragmented
+ * (XXX <= 4 ?)
*/
- for (so = slirp->icmp.so_next; so != &slirp->icmp;
- so = so_next) {
- so_next = so->so_next;
+ if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
+ so->pollfds_idx = add_poll(so->s,
+ SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
+ }
+ }
- so->pollfds_idx = -1;
+ /*
+ * ICMP sockets
+ */
+ for (so = slirp->icmp.so_next; so != &slirp->icmp; so = so_next) {
+ so_next = so->so_next;
- /*
- * See if it's timed out
- */
- if (so->so_expire) {
- if (so->so_expire <= curtime) {
- icmp_detach(so);
- continue;
- } else {
- slirp->do_slowtimo = true; /* Let socket expire */
- }
- }
+ so->pollfds_idx = -1;
- if (so->so_state & SS_ISFCONNECTED) {
- GPollFD pfd = {
- .fd = so->s,
- .events = G_IO_IN | G_IO_HUP | G_IO_ERR,
- };
- so->pollfds_idx = pollfds->len;
- g_array_append_val(pollfds, pfd);
+ /*
+ * See if it's timed out
+ */
+ if (so->so_expire) {
+ if (so->so_expire <= curtime) {
+ icmp_detach(so);
+ continue;
+ } else {
+ slirp->do_slowtimo = true; /* Let socket expire */
}
}
+
+ if (so->so_state & SS_ISFCONNECTED) {
+ so->pollfds_idx = add_poll(so->s,
+ SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR, opaque);
+ }
}
- slirp_update_timeout(timeout);
+
+ slirp_update_timeout(slirp, timeout);
}
-void slirp_pollfds_poll(GArray *pollfds, int select_error)
+void slirp_pollfds_poll(Slirp *slirp, int select_error,
+ SlirpGetREventsCb get_revents, void *opaque)
{
- Slirp *slirp = QTAILQ_FIRST(&slirp_instances);
struct socket *so, *so_next;
int ret;
- if (!slirp) {
- return;
- }
+ curtime = slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS;
- curtime = slirp->cb->clock_get_ns() / SCALE_MS;
+ /*
+ * See if anything has timed out
+ */
+ if (slirp->time_fasttimo &&
+ ((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) {
+ tcp_fasttimo(slirp);
+ slirp->time_fasttimo = 0;
+ }
+ if (slirp->do_slowtimo &&
+ ((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) {
+ ip_slowtimo(slirp);
+ tcp_slowtimo(slirp);
+ slirp->last_slowtimo = curtime;
+ }
- QTAILQ_FOREACH(slirp, &slirp_instances, entry) {
+ /*
+ * Check sockets
+ */
+ if (!select_error) {
/*
- * See if anything has timed out
+ * Check TCP sockets
*/
- if (slirp->time_fasttimo &&
- ((curtime - slirp->time_fasttimo) >= TIMEOUT_FAST)) {
- tcp_fasttimo(slirp);
- slirp->time_fasttimo = 0;
- }
- if (slirp->do_slowtimo &&
- ((curtime - slirp->last_slowtimo) >= TIMEOUT_SLOW)) {
- ip_slowtimo(slirp);
- tcp_slowtimo(slirp);
- slirp->last_slowtimo = curtime;
- }
+ for (so = slirp->tcb.so_next; so != &slirp->tcb;
+ so = so_next) {
+ int revents;
- /*
- * Check sockets
- */
- if (!select_error) {
- /*
- * Check TCP sockets
- */
- for (so = slirp->tcb.so_next; so != &slirp->tcb;
- so = so_next) {
- int revents;
+ so_next = so->so_next;
- so_next = so->so_next;
+ revents = 0;
+ if (so->pollfds_idx != -1) {
+ revents = get_revents(so->pollfds_idx, opaque);
+ }
- revents = 0;
- if (so->pollfds_idx != -1) {
- revents = g_array_index(pollfds, GPollFD,
- so->pollfds_idx).revents;
- }
+ if (so->so_state & SS_NOFDREF || so->s == -1) {
+ continue;
+ }
- if (so->so_state & SS_NOFDREF || so->s == -1) {
+ /*
+ * Check for URG data
+ * This will soread as well, so no need to
+ * test for SLIRP_POLL_IN below if this succeeds
+ */
+ if (revents & SLIRP_POLL_PRI) {
+ ret = sorecvoob(so);
+ if (ret < 0) {
+ /* Socket error might have resulted in the socket being
+ * removed, do not try to do anything more with it. */
continue;
}
-
+ }
+ /*
+ * Check sockets for reading
+ */
+ else if (revents &
+ (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR)) {
/*
- * Check for URG data
- * This will soread as well, so no need to
- * test for G_IO_IN below if this succeeds
+ * Check for incoming connections
*/
- if (revents & G_IO_PRI) {
- ret = sorecvoob(so);
- if (ret < 0) {
- /* Socket error might have resulted in the socket being
- * removed, do not try to do anything more with it. */
- continue;
- }
+ if (so->so_state & SS_FACCEPTCONN) {
+ tcp_connect(so);
+ continue;
+ } /* else */
+ ret = soread(so);
+
+ /* Output it if we read something */
+ if (ret > 0) {
+ tcp_output(sototcpcb(so));
+ }
+ if (ret < 0) {
+ /* Socket error might have resulted in the socket being
+ * removed, do not try to do anything more with it. */
+ continue;
}
+ }
+
+ /*
+ * Check sockets for writing
+ */
+ if (!(so->so_state & SS_NOFDREF) &&
+ (revents & (SLIRP_POLL_OUT | SLIRP_POLL_ERR))) {
/*
- * Check sockets for reading
+ * Check for non-blocking, still-connecting sockets
*/
- else if (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
- /*
- * Check for incoming connections
- */
- if (so->so_state & SS_FACCEPTCONN) {
- tcp_connect(so);
- continue;
- } /* else */
- ret = soread(so);
+ if (so->so_state & SS_ISFCONNECTING) {
+ /* Connected */
+ so->so_state &= ~SS_ISFCONNECTING;
- /* Output it if we read something */
- if (ret > 0) {
- tcp_output(sototcpcb(so));
- }
+ ret = send(so->s, (const void *) &ret, 0, 0);
if (ret < 0) {
- /* Socket error might have resulted in the socket being
- * removed, do not try to do anything more with it. */
- continue;
+ /* XXXXX Must fix, zero bytes is a NOP */
+ if (errno == EAGAIN || errno == EWOULDBLOCK ||
+ errno == EINPROGRESS || errno == ENOTCONN) {
+ continue;
+ }
+
+ /* else failed */
+ so->so_state &= SS_PERSISTENT_MASK;
+ so->so_state |= SS_NOFDREF;
}
- }
+ /* else so->so_state &= ~SS_ISFCONNECTING; */
- /*
- * Check sockets for writing
- */
- if (!(so->so_state & SS_NOFDREF) &&
- (revents & (G_IO_OUT | G_IO_ERR))) {
/*
- * Check for non-blocking, still-connecting sockets
+ * Continue tcp_input
*/
- if (so->so_state & SS_ISFCONNECTING) {
- /* Connected */
- so->so_state &= ~SS_ISFCONNECTING;
-
- ret = send(so->s, (const void *) &ret, 0, 0);
- if (ret < 0) {
- /* XXXXX Must fix, zero bytes is a NOP */
- if (errno == EAGAIN || errno == EWOULDBLOCK ||
- errno == EINPROGRESS || errno == ENOTCONN) {
- continue;
- }
-
- /* else failed */
- so->so_state &= SS_PERSISTENT_MASK;
- so->so_state |= SS_NOFDREF;
- }
- /* else so->so_state &= ~SS_ISFCONNECTING; */
-
- /*
- * Continue tcp_input
- */
- tcp_input((struct mbuf *)NULL, sizeof(struct ip), so,
- so->so_ffamily);
- /* continue; */
- } else {
- ret = sowrite(so);
- if (ret > 0) {
- /* Call tcp_output in case we need to send a window
- * update to the guest, otherwise it will be stuck
- * until it sends a window probe. */
- tcp_output(sototcpcb(so));
- }
+ tcp_input((struct mbuf *)NULL, sizeof(struct ip), so,
+ so->so_ffamily);
+ /* continue; */
+ } else {
+ ret = sowrite(so);
+ if (ret > 0) {
+ /* Call tcp_output in case we need to send a window
+ * update to the guest, otherwise it will be stuck
+ * until it sends a window probe. */
+ tcp_output(sototcpcb(so));
}
}
}
+ }
- /*
- * Now UDP sockets.
- * Incoming packets are sent straight away, they're not buffered.
- * Incoming UDP data isn't buffered either.
- */
- for (so = slirp->udb.so_next; so != &slirp->udb;
- so = so_next) {
- int revents;
+ /*
+ * Now UDP sockets.
+ * Incoming packets are sent straight away, they're not buffered.
+ * Incoming UDP data isn't buffered either.
+ */
+ for (so = slirp->udb.so_next; so != &slirp->udb;
+ so = so_next) {
+ int revents;
- so_next = so->so_next;
+ so_next = so->so_next;
- revents = 0;
- if (so->pollfds_idx != -1) {
- revents = g_array_index(pollfds, GPollFD,
- so->pollfds_idx).revents;
- }
+ revents = 0;
+ if (so->pollfds_idx != -1) {
+ revents = get_revents(so->pollfds_idx, opaque);
+ }
- if (so->s != -1 &&
- (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
- sorecvfrom(so);
- }
+ if (so->s != -1 &&
+ (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) {
+ sorecvfrom(so);
}
+ }
- /*
- * Check incoming ICMP relies.
- */
- for (so = slirp->icmp.so_next; so != &slirp->icmp;
- so = so_next) {
- int revents;
+ /*
+ * Check incoming ICMP relies.
+ */
+ for (so = slirp->icmp.so_next; so != &slirp->icmp;
+ so = so_next) {
+ int revents;
- so_next = so->so_next;
+ so_next = so->so_next;
- revents = 0;
- if (so->pollfds_idx != -1) {
- revents = g_array_index(pollfds, GPollFD,
- so->pollfds_idx).revents;
- }
+ revents = 0;
+ if (so->pollfds_idx != -1) {
+ revents = get_revents(so->pollfds_idx, opaque);
+ }
- if (so->s != -1 &&
- (revents & (G_IO_IN | G_IO_HUP | G_IO_ERR))) {
- icmp_receive(so);
- }
+ if (so->s != -1 &&
+ (revents & (SLIRP_POLL_IN | SLIRP_POLL_HUP | SLIRP_POLL_ERR))) {
+ icmp_receive(so);
}
}
-
- if_start(slirp);
}
+
+ if_start(slirp);
}
static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
@@ -810,7 +754,7 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
rah->ar_sip = ah->ar_tip;
memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
rah->ar_tip = ah->ar_sip;
- slirp->cb->output(slirp->opaque, arp_reply, sizeof(arp_reply));
+ slirp_send_packet_all(slirp, arp_reply, sizeof(arp_reply));
}
break;
case ARPOP_REPLY:
@@ -829,7 +773,7 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
if (pkt_len < ETH_HLEN)
return;
- proto = ntohs(*(uint16_t *)(pkt + 12));
+ proto = (((uint16_t) pkt[12]) << 8) + pkt[13];
switch(proto) {
case ETH_P_ARP:
arp_input(slirp, pkt, pkt_len);
@@ -910,11 +854,12 @@ static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
/* target IP */
rah->ar_tip = iph->ip_dst.s_addr;
slirp->client_ipaddr = iph->ip_dst;
- slirp->cb->output(slirp->opaque, arp_req, sizeof(arp_req));
+ slirp_send_packet_all(slirp, arp_req, sizeof(arp_req));
ifm->resolution_requested = true;
/* Expire request and drop outgoing packet after 1 second */
- ifm->expiration_date = slirp->cb->clock_get_ns() + 1000000000ULL;
+ ifm->expiration_date =
+ slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
}
return 0;
} else {
@@ -940,7 +885,7 @@ static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
if (!ifm->resolution_requested) {
ndp_send_ns(slirp, ip6h->ip_dst);
ifm->resolution_requested = true;
- ifm->expiration_date = slirp->cb->clock_get_ns() + 1000000000ULL;
+ ifm->expiration_date = slirp->cb->clock_get_ns(slirp->opaque) + 1000000000ULL;
}
return 0;
} else {
@@ -995,7 +940,7 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]);
memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
- slirp->cb->output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
+ slirp_send_packet_all(slirp, buf, ifm->m_len + ETH_HLEN);
return 1;
}
@@ -1015,7 +960,8 @@ int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
addr.sin_addr.s_addr == host_addr.s_addr &&
addr.sin_port == port) {
- close(so->s);
+ so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
+ slirp_closesocket(so->s);
sofree(so);
return 0;
}
@@ -1068,23 +1014,35 @@ check_guestfwd(Slirp *slirp, struct in_addr *guest_addr, int guest_port)
return true;
}
-int slirp_add_exec(Slirp *slirp, void *chardev, const char *cmdline,
+int slirp_add_exec(Slirp *slirp, const char *cmdline,
struct in_addr *guest_addr, int guest_port)
{
if (!check_guestfwd(slirp, guest_addr, guest_port)) {
return -1;
}
- return add_exec(&slirp->guestfwd_list, chardev, cmdline, *guest_addr,
- htons(guest_port));
+ add_exec(&slirp->guestfwd_list, cmdline, *guest_addr, htons(guest_port));
+ return 0;
+}
+
+int slirp_add_guestfwd(Slirp *slirp, SlirpWriteCb write_cb, void *opaque,
+ struct in_addr *guest_addr, int guest_port)
+{
+ if (!check_guestfwd(slirp, guest_addr, guest_port)) {
+ return -1;
+ }
+
+ add_guestfwd(&slirp->guestfwd_list, write_cb, opaque,
+ *guest_addr, htons(guest_port));
+ return 0;
}
ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
{
- if (so->s == -1 && so->chardev) {
+ if (so->s == -1 && so->guestfwd) {
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(so->chardev, buf, len);
+ so->guestfwd->write_cb(buf, len, so->guestfwd->opaque);
return len;
}
@@ -1102,7 +1060,7 @@ ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
return send(so->s, buf, len, flags);
}
-static struct socket *
+struct socket *
slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port)
{
struct socket *so;
@@ -1150,349 +1108,14 @@ void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
tcp_output(sototcpcb(so));
}
-static int slirp_tcp_post_load(void *opaque, int version)
+void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len)
{
- tcp_template((struct tcpcb *)opaque);
-
- return 0;
-}
+ ssize_t ret = slirp->cb->send_packet(buf, len, slirp->opaque);
-static const VMStateDescription vmstate_slirp_tcp = {
- .name = "slirp-tcp",
- .version_id = 0,
- .post_load = slirp_tcp_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_INT16(t_state, struct tcpcb),
- VMSTATE_INT16_ARRAY(t_timer, struct tcpcb, TCPT_NTIMERS),
- VMSTATE_INT16(t_rxtshift, struct tcpcb),
- VMSTATE_INT16(t_rxtcur, struct tcpcb),
- VMSTATE_INT16(t_dupacks, struct tcpcb),
- VMSTATE_UINT16(t_maxseg, struct tcpcb),
- VMSTATE_UINT8(t_force, struct tcpcb),
- VMSTATE_UINT16(t_flags, struct tcpcb),
- VMSTATE_UINT32(snd_una, struct tcpcb),
- VMSTATE_UINT32(snd_nxt, struct tcpcb),
- VMSTATE_UINT32(snd_up, struct tcpcb),
- VMSTATE_UINT32(snd_wl1, struct tcpcb),
- VMSTATE_UINT32(snd_wl2, struct tcpcb),
- VMSTATE_UINT32(iss, struct tcpcb),
- VMSTATE_UINT32(snd_wnd, struct tcpcb),
- VMSTATE_UINT32(rcv_wnd, struct tcpcb),
- VMSTATE_UINT32(rcv_nxt, struct tcpcb),
- VMSTATE_UINT32(rcv_up, struct tcpcb),
- VMSTATE_UINT32(irs, struct tcpcb),
- VMSTATE_UINT32(rcv_adv, struct tcpcb),
- VMSTATE_UINT32(snd_max, struct tcpcb),
- VMSTATE_UINT32(snd_cwnd, struct tcpcb),
- VMSTATE_UINT32(snd_ssthresh, struct tcpcb),
- VMSTATE_INT16(t_idle, struct tcpcb),
- VMSTATE_INT16(t_rtt, struct tcpcb),
- VMSTATE_UINT32(t_rtseq, struct tcpcb),
- VMSTATE_INT16(t_srtt, struct tcpcb),
- VMSTATE_INT16(t_rttvar, struct tcpcb),
- VMSTATE_UINT16(t_rttmin, struct tcpcb),
- VMSTATE_UINT32(max_sndwnd, struct tcpcb),
- VMSTATE_UINT8(t_oobflags, struct tcpcb),
- VMSTATE_UINT8(t_iobc, struct tcpcb),
- VMSTATE_INT16(t_softerror, struct tcpcb),
- VMSTATE_UINT8(snd_scale, struct tcpcb),
- VMSTATE_UINT8(rcv_scale, struct tcpcb),
- VMSTATE_UINT8(request_r_scale, struct tcpcb),
- VMSTATE_UINT8(requested_s_scale, struct tcpcb),
- VMSTATE_UINT32(ts_recent, struct tcpcb),
- VMSTATE_UINT32(ts_recent_age, struct tcpcb),
- VMSTATE_UINT32(last_ack_sent, struct tcpcb),
- VMSTATE_END_OF_LIST()
+ if (ret < 0) {
+ g_critical("Failed to send packet, ret: %ld", (long) ret);
+ } else if (ret < len) {
+ DEBUG_ERROR("send_packet() didn't send all data: %ld < %lu",
+ (long) ret, (unsigned long) len);
}
-};
-
-/* The sbuf has a pair of pointers that are migrated as offsets;
- * we calculate the offsets and restore the pointers using
- * pre_save/post_load on a tmp structure.
- */
-struct sbuf_tmp {
- struct sbuf *parent;
- uint32_t roff, woff;
-};
-
-static int sbuf_tmp_pre_save(void *opaque)
-{
- struct sbuf_tmp *tmp = opaque;
- tmp->woff = tmp->parent->sb_wptr - tmp->parent->sb_data;
- tmp->roff = tmp->parent->sb_rptr - tmp->parent->sb_data;
-
- return 0;
-}
-
-static int sbuf_tmp_post_load(void *opaque, int version)
-{
- struct sbuf_tmp *tmp = opaque;
- uint32_t requested_len = tmp->parent->sb_datalen;
-
- /* Allocate the buffer space used by the field after the tmp */
- sbreserve(tmp->parent, tmp->parent->sb_datalen);
-
- if (tmp->parent->sb_datalen != requested_len) {
- return -ENOMEM;
- }
- if (tmp->woff >= requested_len ||
- tmp->roff >= requested_len) {
- g_critical("invalid sbuf offsets r/w=%u/%u len=%u",
- tmp->roff, tmp->woff, requested_len);
- return -EINVAL;
- }
-
- tmp->parent->sb_wptr = tmp->parent->sb_data + tmp->woff;
- tmp->parent->sb_rptr = tmp->parent->sb_data + tmp->roff;
-
- return 0;
-}
-
-
-static const VMStateDescription vmstate_slirp_sbuf_tmp = {
- .name = "slirp-sbuf-tmp",
- .post_load = sbuf_tmp_post_load,
- .pre_save = sbuf_tmp_pre_save,
- .version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(woff, struct sbuf_tmp),
- VMSTATE_UINT32(roff, struct sbuf_tmp),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_slirp_sbuf = {
- .name = "slirp-sbuf",
- .version_id = 0,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(sb_cc, struct sbuf),
- VMSTATE_UINT32(sb_datalen, struct sbuf),
- VMSTATE_WITH_TMP(struct sbuf, struct sbuf_tmp, vmstate_slirp_sbuf_tmp),
- VMSTATE_VBUFFER_UINT32(sb_data, struct sbuf, 0, NULL, sb_datalen),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static bool slirp_older_than_v4(void *opaque, int version_id)
-{
- return version_id < 4;
-}
-
-static bool slirp_family_inet(void *opaque, int version_id)
-{
- union slirp_sockaddr *ssa = (union slirp_sockaddr *)opaque;
- return ssa->ss.ss_family == AF_INET;
-}
-
-static int slirp_socket_pre_load(void *opaque)
-{
- struct socket *so = opaque;
- if (tcp_attach(so) < 0) {
- return -ENOMEM;
- }
- /* Older versions don't load these fields */
- so->so_ffamily = AF_INET;
- so->so_lfamily = AF_INET;
- return 0;
-}
-
-#ifndef _WIN32
-#define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_UINT32_TEST(f, s, t)
-#else
-/* Win uses u_long rather than uint32_t - but it's still 32bits long */
-#define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_SINGLE_TEST(f, s, t, 0, \
- vmstate_info_uint32, u_long)
-#endif
-
-/* The OS provided ss_family field isn't that portable; it's size
- * and type varies (16/8 bit, signed, unsigned)
- * and the values it contains aren't fully portable.
- */
-typedef struct SS_FamilyTmpStruct {
- union slirp_sockaddr *parent;
- uint16_t portable_family;
-} SS_FamilyTmpStruct;
-
-#define SS_FAMILY_MIG_IPV4 2 /* Linux, BSD, Win... */
-#define SS_FAMILY_MIG_IPV6 10 /* Linux */
-#define SS_FAMILY_MIG_OTHER 0xffff
-
-static int ss_family_pre_save(void *opaque)
-{
- SS_FamilyTmpStruct *tss = opaque;
-
- tss->portable_family = SS_FAMILY_MIG_OTHER;
-
- if (tss->parent->ss.ss_family == AF_INET) {
- tss->portable_family = SS_FAMILY_MIG_IPV4;
- } else if (tss->parent->ss.ss_family == AF_INET6) {
- tss->portable_family = SS_FAMILY_MIG_IPV6;
- }
-
- return 0;
-}
-
-static int ss_family_post_load(void *opaque, int version_id)
-{
- SS_FamilyTmpStruct *tss = opaque;
-
- switch (tss->portable_family) {
- case SS_FAMILY_MIG_IPV4:
- tss->parent->ss.ss_family = AF_INET;
- break;
- case SS_FAMILY_MIG_IPV6:
- case 23: /* compatibility: AF_INET6 from mingw */
- case 28: /* compatibility: AF_INET6 from FreeBSD sys/socket.h */
- tss->parent->ss.ss_family = AF_INET6;
- break;
- default:
- g_critical("invalid ss_family type %x", tss->portable_family);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static const VMStateDescription vmstate_slirp_ss_family = {
- .name = "slirp-socket-addr/ss_family",
- .pre_save = ss_family_pre_save,
- .post_load = ss_family_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(portable_family, SS_FamilyTmpStruct),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_slirp_socket_addr = {
- .name = "slirp-socket-addr",
- .version_id = 4,
- .fields = (VMStateField[]) {
- VMSTATE_WITH_TMP(union slirp_sockaddr, SS_FamilyTmpStruct,
- vmstate_slirp_ss_family),
- VMSTATE_SIN4_ADDR(sin.sin_addr.s_addr, union slirp_sockaddr,
- slirp_family_inet),
- VMSTATE_UINT16_TEST(sin.sin_port, union slirp_sockaddr,
- slirp_family_inet),
-
-#if 0
- /* Untested: Needs checking by someone with IPv6 test */
- VMSTATE_BUFFER_TEST(sin6.sin6_addr, union slirp_sockaddr,
- slirp_family_inet6),
- VMSTATE_UINT16_TEST(sin6.sin6_port, union slirp_sockaddr,
- slirp_family_inet6),
- VMSTATE_UINT32_TEST(sin6.sin6_flowinfo, union slirp_sockaddr,
- slirp_family_inet6),
- VMSTATE_UINT32_TEST(sin6.sin6_scope_id, union slirp_sockaddr,
- slirp_family_inet6),
-#endif
-
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_slirp_socket = {
- .name = "slirp-socket",
- .version_id = 4,
- .pre_load = slirp_socket_pre_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(so_urgc, struct socket),
- /* Pre-v4 versions */
- VMSTATE_SIN4_ADDR(so_faddr.s_addr, struct socket,
- slirp_older_than_v4),
- VMSTATE_SIN4_ADDR(so_laddr.s_addr, struct socket,
- slirp_older_than_v4),
- VMSTATE_UINT16_TEST(so_fport, struct socket, slirp_older_than_v4),
- VMSTATE_UINT16_TEST(so_lport, struct socket, slirp_older_than_v4),
- /* v4 and newer */
- VMSTATE_STRUCT(fhost, struct socket, 4, vmstate_slirp_socket_addr,
- union slirp_sockaddr),
- VMSTATE_STRUCT(lhost, struct socket, 4, vmstate_slirp_socket_addr,
- union slirp_sockaddr),
-
- VMSTATE_UINT8(so_iptos, struct socket),
- VMSTATE_UINT8(so_emu, struct socket),
- VMSTATE_UINT8(so_type, struct socket),
- VMSTATE_INT32(so_state, struct socket),
- VMSTATE_STRUCT(so_rcv, struct socket, 0, vmstate_slirp_sbuf,
- struct sbuf),
- VMSTATE_STRUCT(so_snd, struct socket, 0, vmstate_slirp_sbuf,
- struct sbuf),
- VMSTATE_STRUCT_POINTER(so_tcpcb, struct socket, vmstate_slirp_tcp,
- struct tcpcb),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_slirp_bootp_client = {
- .name = "slirp_bootpclient",
- .fields = (VMStateField[]) {
- VMSTATE_UINT16(allocated, BOOTPClient),
- VMSTATE_BUFFER(macaddr, BOOTPClient),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_slirp = {
- .name = "slirp",
- .version_id = 4,
- .fields = (VMStateField[]) {
- VMSTATE_UINT16_V(ip_id, Slirp, 2),
- VMSTATE_STRUCT_ARRAY(bootp_clients, Slirp, NB_BOOTP_CLIENTS, 3,
- vmstate_slirp_bootp_client, BOOTPClient),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void slirp_state_save(QEMUFile *f, void *opaque)
-{
- Slirp *slirp = opaque;
- struct gfwd_list *ex_ptr;
-
- for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
- if (ex_ptr->ex_chardev) {
- struct socket *so;
- so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
- ntohs(ex_ptr->ex_fport));
- if (!so)
- continue;
-
- qemu_put_byte(f, 42);
- vmstate_save_state(f, &vmstate_slirp_socket, so, NULL);
- }
- qemu_put_byte(f, 0);
-
- vmstate_save_state(f, &vmstate_slirp, slirp, NULL);
-}
-
-
-static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
-{
- Slirp *slirp = opaque;
- struct gfwd_list *ex_ptr;
-
- while (qemu_get_byte(f)) {
- int ret;
- struct socket *so = socreate(slirp);
-
- ret = vmstate_load_state(f, &vmstate_slirp_socket, so, version_id);
-
- if (ret < 0)
- return ret;
-
- if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) !=
- slirp->vnetwork_addr.s_addr) {
- return -EINVAL;
- }
- for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
- if (ex_ptr->ex_chardev &&
- so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
- so->so_fport == ex_ptr->ex_fport) {
- break;
- }
- }
- if (!ex_ptr)
- return -EINVAL;
- }
-
- return vmstate_load_state(f, &vmstate_slirp, slirp, version_id);
}
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 9aa245715d..752a4cd8c8 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -3,10 +3,17 @@
#ifdef _WIN32
-typedef char *caddr_t;
+/* as defined in sdkddkver.h */
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0600 /* Vista */
+#endif
+/* reduces the number of implicitly included headers */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
-# include <windows.h>
# include <winsock2.h>
+# include <windows.h>
# include <ws2tcpip.h>
# include <sys/timeb.h>
# include <iphlpapi.h>
@@ -19,19 +26,10 @@ typedef char *caddr_t;
#ifndef _WIN32
#include <sys/uio.h>
-#endif
-
-#ifndef _WIN32
#include <netinet/in.h>
#include <arpa/inet.h>
-#endif
-
-#ifndef _WIN32
#include <sys/socket.h>
-#endif
-
-#ifndef _WIN32
-# include <sys/ioctl.h>
+#include <sys/ioctl.h>
#endif
#ifdef __APPLE__
@@ -45,10 +43,8 @@ typedef char *caddr_t;
#define quehead slirp_quehead
#include "debug.h"
-
-#include "qemu/queue.h"
-#include "qemu/sockets.h"
-#include "net/eth.h"
+#include "util.h"
+#include "qtailq.h"
#include "libslirp.h"
#include "ip.h"
@@ -93,7 +89,7 @@ struct slirp_arphdr {
uint32_t ar_sip; /* sender IP address */
unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
uint32_t ar_tip; /* target IP address */
-} QEMU_PACKED;
+} SLIRP_PACKED;
#define ARP_TABLE_SIZE 16
@@ -110,7 +106,7 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
struct ndpentry {
unsigned char eth_addr[ETH_ALEN]; /* sender hardware address */
struct in6_addr ip_addr; /* sender IP address */
-} QEMU_PACKED;
+} SLIRP_PACKED;
#define NDP_TABLE_SIZE 16
@@ -126,8 +122,8 @@ bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
struct Slirp {
QTAILQ_ENTRY(Slirp) entry;
- u_int time_fasttimo;
- u_int last_slowtimo;
+ unsigned time_fasttimo;
+ unsigned last_slowtimo;
bool do_slowtimo;
bool in_enabled, in6_enabled;
@@ -193,7 +189,7 @@ struct Slirp {
NdpTable ndp_table;
GRand *grand;
- QEMUTimer *ra_timer;
+ void *ra_timer;
const SlirpCb *cb;
void *opaque;
@@ -247,7 +243,7 @@ int ip6_output(struct socket *, struct mbuf *, int fast);
/* tcp_input.c */
void tcp_input(register struct mbuf *, int, struct socket *, unsigned short af);
-int tcp_mss(register struct tcpcb *, u_int);
+int tcp_mss(register struct tcpcb *, unsigned);
/* tcp_output.c */
int tcp_output(register struct tcpcb *);
@@ -270,4 +266,9 @@ int tcp_emu(struct socket *, struct mbuf *);
int tcp_ctl(struct socket *);
struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
+struct socket *
+slirp_find_ctl_socket(Slirp *slirp, struct in_addr guest_addr, int guest_port);
+
+void slirp_send_packet_all(Slirp *slirp, const void *buf, size_t len);
+
#endif
diff --git a/slirp/socket.c b/slirp/socket.c
index 5ffbaa064a..ce1d6ffa1d 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -5,8 +5,6 @@
* terms and conditions of the copyright.
*/
-#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "slirp.h"
#include "ip_icmp.h"
#ifdef __sun__
@@ -187,7 +185,7 @@ soread(struct socket *so)
*/
sopreprbuf(so, iov, &n);
- nn = qemu_recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
+ nn = slirp_recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
if (nn <= 0) {
if (nn < 0 && (errno == EINTR || errno == EAGAIN))
return 0;
@@ -203,7 +201,7 @@ soread(struct socket *so)
if (getpeername(so->s, paddr, &alen) < 0) {
err = errno;
} else {
- getsockopt(so->s, SOL_SOCKET, SO_ERROR,
+ slirp_getsockopt(so->s, SOL_SOCKET, SO_ERROR,
&err, &elen);
}
}
@@ -233,7 +231,7 @@ soread(struct socket *so)
*/
if (n == 2 && nn == iov[0].iov_len) {
int ret;
- ret = qemu_recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
+ ret = slirp_recv(so->s, iov[1].iov_base, iov[1].iov_len,0);
if (ret > 0)
nn += ret;
}
@@ -508,7 +506,7 @@ sorecvfrom(struct socket *so)
/* XXX Check if reply is "correct"? */
if(len == -1 || len == 0) {
- u_char code=ICMP_UNREACH_PORT;
+ uint8_t code=ICMP_UNREACH_PORT;
if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
@@ -554,7 +552,7 @@ sorecvfrom(struct socket *so)
*/
len = M_FREEROOM(m);
/* if (so->so_fport != htons(53)) { */
- ioctlsocket(so->s, FIONREAD, &n);
+ slirp_ioctlsocket(so->s, FIONREAD, &n);
if (n > len) {
n = (m->m_data - m->m_dat) + m->m_len + n + 1;
@@ -678,8 +676,8 @@ sosendto(struct socket *so, struct mbuf *m)
* Listen for incoming TCP connections
*/
struct socket *
-tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
- u_int lport, int flags)
+tcp_listen(Slirp *slirp, uint32_t haddr, unsigned hport, uint32_t laddr,
+ unsigned lport, int flags)
{
struct sockaddr_in addr;
struct socket *so;
@@ -719,14 +717,14 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
addr.sin_addr.s_addr = haddr;
addr.sin_port = hport;
- if (((s = qemu_socket(AF_INET,SOCK_STREAM,0)) < 0) ||
- (socket_set_fast_reuse(s) < 0) ||
+ if (((s = slirp_socket(AF_INET,SOCK_STREAM,0)) < 0) ||
+ (slirp_socket_set_fast_reuse(s) < 0) ||
(bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
(listen(s,1) < 0)) {
int tmperrno = errno; /* Don't clobber the real reason we failed */
if (s >= 0) {
- closesocket(s);
+ slirp_closesocket(s);
}
sofree(so);
/* Restore the real errno */
@@ -737,9 +735,9 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
#endif
return NULL;
}
- qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
+ slirp_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
opt = 1;
- qemu_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int));
+ slirp_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int));
getsockname(s,(struct sockaddr *)&addr,&addrlen);
so->so_ffamily = AF_INET;
@@ -928,3 +926,10 @@ void sotranslate_accept(struct socket *so)
break;
}
}
+
+void sodrop(struct socket *s, int num)
+{
+ if (sbdrop(&s->so_snd, num)) {
+ s->slirp->cb->notify(s->slirp->opaque);
+ }
+}
diff --git a/slirp/socket.h b/slirp/socket.h
index 930ed95972..e4d12cd591 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -8,6 +8,8 @@
#ifndef SLIRP_SOCKET_H
#define SLIRP_SOCKET_H
+#include "misc.h"
+
#define SO_EXPIRE 240000
#define SO_EXPIREFAST 10000
@@ -25,6 +27,7 @@ struct socket {
struct socket *so_next,*so_prev; /* For a linked list of sockets */
int s; /* The actual socket */
+ struct gfwd_list *guestfwd;
int pollfds_idx; /* GPollFD GArray index */
@@ -58,7 +61,7 @@ struct socket {
int32_t so_state; /* internal state flags SS_*, below */
struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */
- u_int so_expire; /* When the socket will expire */
+ unsigned so_expire; /* When the socket will expire */
int so_queued; /* Number of packets queued from this socket */
int so_nqueued; /* Number of packets queued in a row
@@ -67,7 +70,6 @@ struct socket {
struct sbuf so_rcv; /* Receive buffer */
struct sbuf so_snd; /* Send buffer */
- void * chardev;
};
@@ -142,7 +144,7 @@ int sosendoob(struct socket *);
int sowrite(struct socket *);
void sorecvfrom(struct socket *);
int sosendto(struct socket *, struct mbuf *);
-struct socket * tcp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int,
+struct socket * tcp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned,
int);
void soisfconnecting(register struct socket *);
void soisfconnected(register struct socket *);
@@ -154,6 +156,7 @@ int soreadbuf(struct socket *so, const char *buf, int size);
void sotranslate_out(struct socket *, struct sockaddr_storage *);
void sotranslate_in(struct socket *, struct sockaddr_storage *);
void sotranslate_accept(struct socket *);
+void sodrop(struct socket *, int num);
#endif /* SLIRP_SOCKET_H */
diff --git a/slirp/state.c b/slirp/state.c
new file mode 100644
index 0000000000..0e5a706e87
--- /dev/null
+++ b/slirp/state.c
@@ -0,0 +1,394 @@
+/*
+ * libslirp
+ *
+ * Copyright (c) 2004-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "qemu/osdep.h"
+
+#include "slirp.h"
+#include "state.h"
+#include "migration/vmstate.h"
+#include "migration/qemu-file-types.h"
+#include "migration/register.h"
+
+static int slirp_tcp_post_load(void *opaque, int version)
+{
+ tcp_template((struct tcpcb *)opaque);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_slirp_tcp = {
+ .name = "slirp-tcp",
+ .version_id = 0,
+ .post_load = slirp_tcp_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT16(t_state, struct tcpcb),
+ VMSTATE_INT16_ARRAY(t_timer, struct tcpcb, TCPT_NTIMERS),
+ VMSTATE_INT16(t_rxtshift, struct tcpcb),
+ VMSTATE_INT16(t_rxtcur, struct tcpcb),
+ VMSTATE_INT16(t_dupacks, struct tcpcb),
+ VMSTATE_UINT16(t_maxseg, struct tcpcb),
+ VMSTATE_UINT8(t_force, struct tcpcb),
+ VMSTATE_UINT16(t_flags, struct tcpcb),
+ VMSTATE_UINT32(snd_una, struct tcpcb),
+ VMSTATE_UINT32(snd_nxt, struct tcpcb),
+ VMSTATE_UINT32(snd_up, struct tcpcb),
+ VMSTATE_UINT32(snd_wl1, struct tcpcb),
+ VMSTATE_UINT32(snd_wl2, struct tcpcb),
+ VMSTATE_UINT32(iss, struct tcpcb),
+ VMSTATE_UINT32(snd_wnd, struct tcpcb),
+ VMSTATE_UINT32(rcv_wnd, struct tcpcb),
+ VMSTATE_UINT32(rcv_nxt, struct tcpcb),
+ VMSTATE_UINT32(rcv_up, struct tcpcb),
+ VMSTATE_UINT32(irs, struct tcpcb),
+ VMSTATE_UINT32(rcv_adv, struct tcpcb),
+ VMSTATE_UINT32(snd_max, struct tcpcb),
+ VMSTATE_UINT32(snd_cwnd, struct tcpcb),
+ VMSTATE_UINT32(snd_ssthresh, struct tcpcb),
+ VMSTATE_INT16(t_idle, struct tcpcb),
+ VMSTATE_INT16(t_rtt, struct tcpcb),
+ VMSTATE_UINT32(t_rtseq, struct tcpcb),
+ VMSTATE_INT16(t_srtt, struct tcpcb),
+ VMSTATE_INT16(t_rttvar, struct tcpcb),
+ VMSTATE_UINT16(t_rttmin, struct tcpcb),
+ VMSTATE_UINT32(max_sndwnd, struct tcpcb),
+ VMSTATE_UINT8(t_oobflags, struct tcpcb),
+ VMSTATE_UINT8(t_iobc, struct tcpcb),
+ VMSTATE_INT16(t_softerror, struct tcpcb),
+ VMSTATE_UINT8(snd_scale, struct tcpcb),
+ VMSTATE_UINT8(rcv_scale, struct tcpcb),
+ VMSTATE_UINT8(request_r_scale, struct tcpcb),
+ VMSTATE_UINT8(requested_s_scale, struct tcpcb),
+ VMSTATE_UINT32(ts_recent, struct tcpcb),
+ VMSTATE_UINT32(ts_recent_age, struct tcpcb),
+ VMSTATE_UINT32(last_ack_sent, struct tcpcb),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+/* The sbuf has a pair of pointers that are migrated as offsets;
+ * we calculate the offsets and restore the pointers using
+ * pre_save/post_load on a tmp structure.
+ */
+struct sbuf_tmp {
+ struct sbuf *parent;
+ uint32_t roff, woff;
+};
+
+static int sbuf_tmp_pre_save(void *opaque)
+{
+ struct sbuf_tmp *tmp = opaque;
+ tmp->woff = tmp->parent->sb_wptr - tmp->parent->sb_data;
+ tmp->roff = tmp->parent->sb_rptr - tmp->parent->sb_data;
+
+ return 0;
+}
+
+static int sbuf_tmp_post_load(void *opaque, int version)
+{
+ struct sbuf_tmp *tmp = opaque;
+ uint32_t requested_len = tmp->parent->sb_datalen;
+
+ /* Allocate the buffer space used by the field after the tmp */
+ sbreserve(tmp->parent, tmp->parent->sb_datalen);
+
+ if (tmp->parent->sb_datalen != requested_len) {
+ return -ENOMEM;
+ }
+ if (tmp->woff >= requested_len ||
+ tmp->roff >= requested_len) {
+ g_critical("invalid sbuf offsets r/w=%u/%u len=%u",
+ tmp->roff, tmp->woff, requested_len);
+ return -EINVAL;
+ }
+
+ tmp->parent->sb_wptr = tmp->parent->sb_data + tmp->woff;
+ tmp->parent->sb_rptr = tmp->parent->sb_data + tmp->roff;
+
+ return 0;
+}
+
+
+static const VMStateDescription vmstate_slirp_sbuf_tmp = {
+ .name = "slirp-sbuf-tmp",
+ .post_load = sbuf_tmp_post_load,
+ .pre_save = sbuf_tmp_pre_save,
+ .version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(woff, struct sbuf_tmp),
+ VMSTATE_UINT32(roff, struct sbuf_tmp),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_slirp_sbuf = {
+ .name = "slirp-sbuf",
+ .version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(sb_cc, struct sbuf),
+ VMSTATE_UINT32(sb_datalen, struct sbuf),
+ VMSTATE_WITH_TMP(struct sbuf, struct sbuf_tmp, vmstate_slirp_sbuf_tmp),
+ VMSTATE_VBUFFER_UINT32(sb_data, struct sbuf, 0, NULL, sb_datalen),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool slirp_older_than_v4(void *opaque, int version_id)
+{
+ return version_id < 4;
+}
+
+static bool slirp_family_inet(void *opaque, int version_id)
+{
+ union slirp_sockaddr *ssa = (union slirp_sockaddr *)opaque;
+ return ssa->ss.ss_family == AF_INET;
+}
+
+static int slirp_socket_pre_load(void *opaque)
+{
+ struct socket *so = opaque;
+ if (tcp_attach(so) < 0) {
+ return -ENOMEM;
+ }
+ /* Older versions don't load these fields */
+ so->so_ffamily = AF_INET;
+ so->so_lfamily = AF_INET;
+ return 0;
+}
+
+#ifndef _WIN32
+#define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_UINT32_TEST(f, s, t)
+#else
+/* Win uses u_long rather than uint32_t - but it's still 32bits long */
+#define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_SINGLE_TEST(f, s, t, 0, \
+ vmstate_info_uint32, u_long)
+#endif
+
+/* The OS provided ss_family field isn't that portable; it's size
+ * and type varies (16/8 bit, signed, unsigned)
+ * and the values it contains aren't fully portable.
+ */
+typedef struct SS_FamilyTmpStruct {
+ union slirp_sockaddr *parent;
+ uint16_t portable_family;
+} SS_FamilyTmpStruct;
+
+#define SS_FAMILY_MIG_IPV4 2 /* Linux, BSD, Win... */
+#define SS_FAMILY_MIG_IPV6 10 /* Linux */
+#define SS_FAMILY_MIG_OTHER 0xffff
+
+static int ss_family_pre_save(void *opaque)
+{
+ SS_FamilyTmpStruct *tss = opaque;
+
+ tss->portable_family = SS_FAMILY_MIG_OTHER;
+
+ if (tss->parent->ss.ss_family == AF_INET) {
+ tss->portable_family = SS_FAMILY_MIG_IPV4;
+ } else if (tss->parent->ss.ss_family == AF_INET6) {
+ tss->portable_family = SS_FAMILY_MIG_IPV6;
+ }
+
+ return 0;
+}
+
+static int ss_family_post_load(void *opaque, int version_id)
+{
+ SS_FamilyTmpStruct *tss = opaque;
+
+ switch (tss->portable_family) {
+ case SS_FAMILY_MIG_IPV4:
+ tss->parent->ss.ss_family = AF_INET;
+ break;
+ case SS_FAMILY_MIG_IPV6:
+ case 23: /* compatibility: AF_INET6 from mingw */
+ case 28: /* compatibility: AF_INET6 from FreeBSD sys/socket.h */
+ tss->parent->ss.ss_family = AF_INET6;
+ break;
+ default:
+ g_critical("invalid ss_family type %x", tss->portable_family);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_slirp_ss_family = {
+ .name = "slirp-socket-addr/ss_family",
+ .pre_save = ss_family_pre_save,
+ .post_load = ss_family_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(portable_family, SS_FamilyTmpStruct),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_slirp_socket_addr = {
+ .name = "slirp-socket-addr",
+ .version_id = 4,
+ .fields = (VMStateField[]) {
+ VMSTATE_WITH_TMP(union slirp_sockaddr, SS_FamilyTmpStruct,
+ vmstate_slirp_ss_family),
+ VMSTATE_SIN4_ADDR(sin.sin_addr.s_addr, union slirp_sockaddr,
+ slirp_family_inet),
+ VMSTATE_UINT16_TEST(sin.sin_port, union slirp_sockaddr,
+ slirp_family_inet),
+
+#if 0
+ /* Untested: Needs checking by someone with IPv6 test */
+ VMSTATE_BUFFER_TEST(sin6.sin6_addr, union slirp_sockaddr,
+ slirp_family_inet6),
+ VMSTATE_UINT16_TEST(sin6.sin6_port, union slirp_sockaddr,
+ slirp_family_inet6),
+ VMSTATE_UINT32_TEST(sin6.sin6_flowinfo, union slirp_sockaddr,
+ slirp_family_inet6),
+ VMSTATE_UINT32_TEST(sin6.sin6_scope_id, union slirp_sockaddr,
+ slirp_family_inet6),
+#endif
+
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_slirp_socket = {
+ .name = "slirp-socket",
+ .version_id = 4,
+ .pre_load = slirp_socket_pre_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(so_urgc, struct socket),
+ /* Pre-v4 versions */
+ VMSTATE_SIN4_ADDR(so_faddr.s_addr, struct socket,
+ slirp_older_than_v4),
+ VMSTATE_SIN4_ADDR(so_laddr.s_addr, struct socket,
+ slirp_older_than_v4),
+ VMSTATE_UINT16_TEST(so_fport, struct socket, slirp_older_than_v4),
+ VMSTATE_UINT16_TEST(so_lport, struct socket, slirp_older_than_v4),
+ /* v4 and newer */
+ VMSTATE_STRUCT(fhost, struct socket, 4, vmstate_slirp_socket_addr,
+ union slirp_sockaddr),
+ VMSTATE_STRUCT(lhost, struct socket, 4, vmstate_slirp_socket_addr,
+ union slirp_sockaddr),
+
+ VMSTATE_UINT8(so_iptos, struct socket),
+ VMSTATE_UINT8(so_emu, struct socket),
+ VMSTATE_UINT8(so_type, struct socket),
+ VMSTATE_INT32(so_state, struct socket),
+ VMSTATE_STRUCT(so_rcv, struct socket, 0, vmstate_slirp_sbuf,
+ struct sbuf),
+ VMSTATE_STRUCT(so_snd, struct socket, 0, vmstate_slirp_sbuf,
+ struct sbuf),
+ VMSTATE_STRUCT_POINTER(so_tcpcb, struct socket, vmstate_slirp_tcp,
+ struct tcpcb),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_slirp_bootp_client = {
+ .name = "slirp_bootpclient",
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(allocated, BOOTPClient),
+ VMSTATE_BUFFER(macaddr, BOOTPClient),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_slirp = {
+ .name = "slirp",
+ .version_id = 4,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16_V(ip_id, Slirp, 2),
+ VMSTATE_STRUCT_ARRAY(bootp_clients, Slirp, NB_BOOTP_CLIENTS, 3,
+ vmstate_slirp_bootp_client, BOOTPClient),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void slirp_state_save(QEMUFile *f, void *opaque)
+{
+ Slirp *slirp = opaque;
+ struct gfwd_list *ex_ptr;
+
+ for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
+ if (ex_ptr->write_cb) {
+ struct socket *so;
+ so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
+ ntohs(ex_ptr->ex_fport));
+ if (!so) {
+ continue;
+ }
+
+ qemu_put_byte(f, 42);
+ vmstate_save_state(f, &vmstate_slirp_socket, so, NULL);
+ }
+ qemu_put_byte(f, 0);
+
+ vmstate_save_state(f, &vmstate_slirp, slirp, NULL);
+}
+
+
+static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
+{
+ Slirp *slirp = opaque;
+ struct gfwd_list *ex_ptr;
+
+ while (qemu_get_byte(f)) {
+ int ret;
+ struct socket *so = socreate(slirp);
+
+ ret = vmstate_load_state(f, &vmstate_slirp_socket, so, version_id);
+ if (ret < 0) {
+ return ret;
+ }
+
+ if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) !=
+ slirp->vnetwork_addr.s_addr) {
+ return -EINVAL;
+ }
+ for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
+ if (ex_ptr->write_cb &&
+ so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
+ so->so_fport == ex_ptr->ex_fport) {
+ break;
+ }
+ }
+ if (!ex_ptr) {
+ return -EINVAL;
+ }
+ }
+
+ return vmstate_load_state(f, &vmstate_slirp, slirp, version_id);
+}
+
+void slirp_state_register(Slirp *slirp)
+{
+ static SaveVMHandlers savevm_slirp_state = {
+ .save_state = slirp_state_save,
+ .load_state = slirp_state_load,
+ };
+
+ register_savevm_live(NULL, "slirp", 0, 4, &savevm_slirp_state, slirp);
+}
+
+void slirp_state_unregister(Slirp *slirp)
+{
+ unregister_savevm(NULL, "slirp", slirp);
+}
diff --git a/slirp/state.h b/slirp/state.h
new file mode 100644
index 0000000000..154866898f
--- /dev/null
+++ b/slirp/state.h
@@ -0,0 +1,9 @@
+#ifndef SLIRP_STATE_H_
+#define SLIRP_STATE_H_
+
+#include "libslirp.h"
+
+void slirp_state_register(Slirp *slirp);
+void slirp_state_unregister(Slirp *slirp);
+
+#endif /* SLIRP_STATE_H_ */
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index de5b74a52b..6749b32f5d 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -38,7 +38,6 @@
* terms and conditions of the copyright.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
#include "ip_icmp.h"
@@ -77,7 +76,7 @@
} \
}
-static void tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt,
+static void tcp_dooptions(struct tcpcb *tp, uint8_t *cp, int cnt,
struct tcpiphdr *ti);
static void tcp_xmit_timer(register struct tcpcb *tp, int rtt);
@@ -198,7 +197,7 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
struct ip save_ip, *ip;
struct ip6 save_ip6, *ip6;
register struct tcpiphdr *ti;
- caddr_t optp = NULL;
+ char *optp = NULL;
int optlen = 0;
int len, tlen, off;
register struct tcpcb *tp = NULL;
@@ -206,7 +205,7 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
struct socket *so = NULL;
int todrop, acked, ourfinisacked, needoutput = 0;
int iss = 0;
- u_long tiwin;
+ uint32_t tiwin;
int ret;
struct sockaddr_storage lhost, fhost;
struct sockaddr_in *lhost4, *fhost4;
@@ -328,7 +327,7 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
ti->ti_len = tlen;
if (off > sizeof (struct tcphdr)) {
optlen = off - sizeof (struct tcphdr);
- optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
+ optp = mtod(m, char *) + sizeof (struct tcpiphdr);
}
tiflags = ti->ti_flags;
@@ -470,7 +469,7 @@ findso:
* else do it below (after getting remote address).
*/
if (optp && tp->t_state != TCPS_LISTEN)
- tcp_dooptions(tp, (u_char *)optp, optlen, ti);
+ tcp_dooptions(tp, (uint8_t *)optp, optlen, ti);
/*
* Header prediction: check for the two common cases
@@ -506,7 +505,7 @@ findso:
SEQ_GT(ti->ti_ack, tp->t_rtseq))
tcp_xmit_timer(tp, tp->t_rtt);
acked = ti->ti_ack - tp->snd_una;
- sbdrop(&so->so_snd, acked);
+ sodrop(so, acked);
tp->snd_una = ti->ti_ack;
m_free(m);
@@ -725,7 +724,7 @@ findso:
tcp_template(tp);
if (optp)
- tcp_dooptions(tp, (u_char *)optp, optlen, ti);
+ tcp_dooptions(tp, (uint8_t *)optp, optlen, ti);
if (iss)
tp->iss = iss;
@@ -1040,7 +1039,7 @@ trimthenstep6:
tp->t_dupacks = 0;
else if (++tp->t_dupacks == TCPREXMTTHRESH) {
tcp_seq onxt = tp->snd_nxt;
- u_int win =
+ unsigned win =
MIN(tp->snd_wnd, tp->snd_cwnd) /
2 / tp->t_maxseg;
@@ -1109,8 +1108,8 @@ trimthenstep6:
* (maxseg^2 / cwnd per packet).
*/
{
- register u_int cw = tp->snd_cwnd;
- register u_int incr = tp->t_maxseg;
+ register unsigned cw = tp->snd_cwnd;
+ register unsigned incr = tp->t_maxseg;
if (cw > tp->snd_ssthresh)
incr = incr * incr / cw;
@@ -1118,10 +1117,10 @@ trimthenstep6:
}
if (acked > so->so_snd.sb_cc) {
tp->snd_wnd -= so->so_snd.sb_cc;
- sbdrop(&so->so_snd, (int )so->so_snd.sb_cc);
+ sodrop(so, (int)so->so_snd.sb_cc);
ourfinisacked = 1;
} else {
- sbdrop(&so->so_snd, acked);
+ sodrop(so, acked);
tp->snd_wnd -= acked;
ourfinisacked = 0;
}
@@ -1382,7 +1381,7 @@ drop:
}
static void
-tcp_dooptions(struct tcpcb *tp, u_char *cp, int cnt, struct tcpiphdr *ti)
+tcp_dooptions(struct tcpcb *tp, uint8_t *cp, int cnt, struct tcpiphdr *ti)
{
uint16_t mss;
int opt, optlen;
@@ -1512,7 +1511,7 @@ tcp_xmit_timer(register struct tcpcb *tp, int rtt)
*/
int
-tcp_mss(struct tcpcb *tp, u_int offer)
+tcp_mss(struct tcpcb *tp, unsigned offer)
{
struct socket *so = tp->t_socket;
int mss;
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index 6dd1ecf5d9..e9674df121 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -38,10 +38,9 @@
* terms and conditions of the copyright.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
-static const u_char tcp_outflags[TCP_NSTATES] = {
+static const uint8_t tcp_outflags[TCP_NSTATES] = {
TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK,
TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK,
TH_FIN|TH_ACK, TH_ACK, TH_ACK,
@@ -64,7 +63,7 @@ tcp_output(struct tcpcb *tp)
register struct tcpiphdr *ti, tcpiph_save;
struct ip *ip;
struct ip6 *ip6;
- u_char opt[MAX_TCPOPTLEN];
+ uint8_t opt[MAX_TCPOPTLEN];
unsigned optlen, hdrlen;
int idle, sendalot;
@@ -272,7 +271,7 @@ send:
opt[0] = TCPOPT_MAXSEG;
opt[1] = 4;
mss = htons((uint16_t) tcp_mss(tp, 0));
- memcpy((caddr_t)(opt + 2), (caddr_t)&mss, sizeof(mss));
+ memcpy((char *)(opt + 2), (char *)&mss, sizeof(mss));
optlen = 4;
}
}
@@ -302,7 +301,7 @@ send:
m->m_data += IF_MAXLINKHDR;
m->m_len = hdrlen;
- sbcopy(&so->so_snd, off, (int) len, mtod(m, caddr_t) + hdrlen);
+ sbcopy(&so->so_snd, off, (int) len, mtod(m, char *) + hdrlen);
m->m_len += len;
/*
@@ -325,7 +324,7 @@ send:
ti = mtod(m, struct tcpiphdr *);
- memcpy((caddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr));
+ memcpy((char *)ti, &tp->t_template, sizeof (struct tcpiphdr));
/*
* Fill in fields, remembering maximum advertised
@@ -354,7 +353,7 @@ send:
ti->ti_seq = htonl(tp->snd_max);
ti->ti_ack = htonl(tp->rcv_nxt);
if (optlen) {
- memcpy((caddr_t)(ti + 1), (caddr_t)opt, optlen);
+ memcpy((char *)(ti + 1), (char *)opt, optlen);
ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2;
}
ti->ti_flags = flags;
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index 23a841f26e..cda94815f6 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -38,7 +38,6 @@
* terms and conditions of the copyright.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
/* patchable/settable parameters for tcp */
@@ -164,7 +163,7 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
* ti points into m so the next line is just making
* the mbuf point to ti
*/
- m->m_data = (caddr_t)ti;
+ m->m_data = (char *)ti;
m->m_len = sizeof (struct tcpiphdr);
tlen = 0;
@@ -183,7 +182,7 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
}
#undef xchg
}
- ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
+ ti->ti_len = htons((uint16_t)(sizeof (struct tcphdr) + tlen));
tlen += sizeof (struct tcpiphdr);
m->m_len = tlen;
@@ -337,7 +336,8 @@ tcp_close(struct tcpcb *tp)
/* clobber input socket cache if we're closing the cached connection */
if (so == slirp->tcp_last_so)
slirp->tcp_last_so = &slirp->tcb;
- closesocket(so->s);
+ so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
+ slirp_closesocket(so->s);
sbfree(&so->so_rcv);
sbfree(&so->so_snd);
sofree(so);
@@ -407,17 +407,18 @@ int tcp_fconnect(struct socket *so, unsigned short af)
DEBUG_CALL("tcp_fconnect");
DEBUG_ARG("so = %p", so);
- ret = so->s = qemu_socket(af, SOCK_STREAM, 0);
+ ret = so->s = slirp_socket(af, SOCK_STREAM, 0);
if (ret >= 0) {
int opt, s=so->s;
struct sockaddr_storage addr;
- qemu_set_nonblock(s);
- socket_set_fast_reuse(s);
+ slirp_set_nonblock(s);
+ so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
+ slirp_socket_set_fast_reuse(s);
opt = 1;
- qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
+ slirp_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
opt = 1;
- qemu_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
+ slirp_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
addr = so->fhost.ss;
DEBUG_CALL(" connect()ing");
@@ -484,11 +485,12 @@ void tcp_connect(struct socket *inso)
tcp_close(sototcpcb(so)); /* This will sofree() as well */
return;
}
- qemu_set_nonblock(s);
- socket_set_fast_reuse(s);
+ slirp_set_nonblock(s);
+ so->slirp->cb->register_poll_fd(so->s, so->slirp->opaque);
+ slirp_socket_set_fast_reuse(s);
opt = 1;
- qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
- socket_set_nodelay(s);
+ slirp_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
+ slirp_socket_set_nodelay(s);
so->fhost.ss = addr;
sotranslate_accept(so);
@@ -496,7 +498,8 @@ void tcp_connect(struct socket *inso)
/* Close the accept() socket, set right state */
if (inso->so_state & SS_FACCEPTONCE) {
/* If we only accept once, close the accept() socket */
- closesocket(so->s);
+ so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
+ slirp_closesocket(so->s);
/* Don't select it yet, even though we have an FD */
/* if it's not FACCEPTONCE, it's already NOFDREF */
@@ -610,10 +613,10 @@ int
tcp_emu(struct socket *so, struct mbuf *m)
{
Slirp *slirp = so->slirp;
- u_int n1, n2, n3, n4, n5, n6;
+ unsigned n1, n2, n3, n4, n5, n6;
char buff[257];
uint32_t laddr;
- u_int lport;
+ unsigned lport;
char *bptr;
DEBUG_CALL("tcp_emu");
@@ -850,7 +853,7 @@ tcp_emu(struct socket *so, struct mbuf *m)
bptr = m->m_data;
while (bptr < m->m_data + m->m_len) {
- u_short p;
+ uint16_t p;
static int ra = 0;
char ra_tbl[4];
@@ -906,8 +909,8 @@ tcp_emu(struct socket *so, struct mbuf *m)
/* This is the field containing the port
* number that RA-player is listening to.
*/
- lport = (((u_char*)bptr)[0] << 8)
- + ((u_char *)bptr)[1];
+ lport = (((uint8_t*)bptr)[0] << 8)
+ + ((uint8_t *)bptr)[1];
if (lport < 6970)
lport += 256; /* don't know why */
if (lport < 6970 || lport > 7170)
@@ -925,8 +928,8 @@ tcp_emu(struct socket *so, struct mbuf *m)
}
if (p == 7071)
p = 0;
- *(u_char *)bptr++ = (p >> 8) & 0xff;
- *(u_char *)bptr = p & 0xff;
+ *(uint8_t *)bptr++ = (p >> 8) & 0xff;
+ *(uint8_t *)bptr = p & 0xff;
ra = 0;
return 1; /* port redirected, we're done */
break;
@@ -964,9 +967,9 @@ int tcp_ctl(struct socket *so)
for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
if (ex_ptr->ex_fport == so->so_fport &&
so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
- if (ex_ptr->ex_chardev) {
+ if (ex_ptr->write_cb) {
so->s = -1;
- so->chardev = ex_ptr->ex_chardev;
+ so->guestfwd = ex_ptr;
return 1;
}
DEBUG_MISC(" executing %s", ex_ptr->ex_exec);
diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c
index a843e57a2b..7be54570af 100644
--- a/slirp/tcp_timer.c
+++ b/slirp/tcp_timer.c
@@ -30,7 +30,6 @@
* tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp
*/
-#include "qemu/osdep.h"
#include "slirp.h"
static struct tcpcb *tcp_timers(register struct tcpcb *tp, int timer);
@@ -233,7 +232,7 @@ tcp_timers(register struct tcpcb *tp, int timer)
* to go below this.)
*/
{
- u_int win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
+ unsigned win = MIN(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
if (win < 2)
win = 2;
tp->snd_cwnd = tp->t_maxseg;
diff --git a/slirp/tcp_var.h b/slirp/tcp_var.h
index 895ef6df1e..27ef1a51cb 100644
--- a/slirp/tcp_var.h
+++ b/slirp/tcp_var.h
@@ -47,9 +47,9 @@ struct tcpcb {
short t_rxtshift; /* log(2) of rexmt exp. backoff */
short t_rxtcur; /* current retransmit value */
short t_dupacks; /* consecutive dup acks recd */
- u_short t_maxseg; /* maximum segment size */
+ uint16_t t_maxseg; /* maximum segment size */
uint8_t t_force; /* 1 if forcing out a byte */
- u_short t_flags;
+ uint16_t t_flags;
#define TF_ACKNOW 0x0001 /* ack peer immediately */
#define TF_DELACK 0x0002 /* ack, but try to delay it */
#define TF_NODELAY 0x0004 /* don't delay packets to coalesce */
@@ -105,7 +105,7 @@ struct tcpcb {
tcp_seq t_rtseq; /* sequence number being timed */
short t_srtt; /* smoothed round-trip time */
short t_rttvar; /* variance in round-trip time */
- u_short t_rttmin; /* minimum rtt allowed */
+ uint16_t t_rttmin; /* minimum rtt allowed */
uint32_t max_sndwnd; /* largest window peer has offered */
/* out-of-band data */
@@ -116,10 +116,10 @@ struct tcpcb {
short t_softerror; /* possible error not yet reported */
/* RFC 1323 variables */
- u_char snd_scale; /* window scaling for send window */
- u_char rcv_scale; /* window scaling for recv window */
- u_char request_r_scale; /* pending window scaling */
- u_char requested_s_scale;
+ uint8_t snd_scale; /* window scaling for send window */
+ uint8_t rcv_scale; /* window scaling for recv window */
+ uint8_t request_r_scale; /* pending window scaling */
+ uint8_t requested_s_scale;
uint32_t ts_recent; /* timestamp echo data */
uint32_t ts_recent_age; /* when last updated */
tcp_seq last_ack_sent;
diff --git a/slirp/tftp.c b/slirp/tftp.c
index a9ba1480db..2d8f978786 100644
--- a/slirp/tftp.c
+++ b/slirp/tftp.c
@@ -22,11 +22,11 @@
* THE SOFTWARE.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
-#include "qemu-common.h"
-#include "qemu/cutils.h"
-#include "trace.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
static inline int tftp_session_in_use(struct tftp_session *spt)
{
@@ -205,7 +205,8 @@ static void tftp_send_error(struct tftp_session *spt,
struct mbuf *m;
struct tftp_t *tp;
- trace_slirp_tftp_error(msg);
+ DEBUG_TFTP("tftp error msg: %s", msg);
+
m = m_get(spt->slirp);
if (!m) {
@@ -216,7 +217,7 @@ static void tftp_send_error(struct tftp_session *spt,
tp->tp_op = htons(TFTP_ERROR);
tp->x.tp_error.tp_error_code = htons(errorcode);
- pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg);
+ slirp_pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg);
m->m_len = sizeof(struct tftp_t) - (TFTP_BLOCKSIZE_MAX + 2) + 3 + strlen(msg)
- sizeof(struct udphdr);
@@ -325,7 +326,8 @@ static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
break;
}
}
- trace_slirp_tftp_rrq(req_fname);
+
+ DEBUG_TFTP("tftp rrq file: %s", req_fname);
/* check mode */
if ((pktlen - k) < 6) {
diff --git a/slirp/trace-events b/slirp/trace-events
deleted file mode 100644
index ff8f656e8c..0000000000
--- a/slirp/trace-events
+++ /dev/null
@@ -1,5 +0,0 @@
-# See docs/devel/tracing.txt for syntax documentation.
-
-# slirp/tftp.c
-slirp_tftp_rrq(const char *file) "file: %s"
-slirp_tftp_error(const char *file) "msg: %s"
diff --git a/slirp/udp.c b/slirp/udp.c
index 309feb9aae..29a31e9400 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -38,7 +38,6 @@
* terms and conditions of the copyright.
*/
-#include "qemu/osdep.h"
#include "slirp.h"
#include "ip_icmp.h"
@@ -93,7 +92,7 @@ udp_input(register struct mbuf *m, int iphlen)
* Get IP and UDP header together in first mbuf.
*/
ip = mtod(m, struct ip *);
- uh = (struct udphdr *)((caddr_t)ip + iphlen);
+ uh = (struct udphdr *)((char *)ip + iphlen);
/*
* Make mbuf data length reflect UDP length.
@@ -281,7 +280,7 @@ int udp_output(struct socket *so, struct mbuf *m,
int
udp_attach(struct socket *so, unsigned short af)
{
- so->s = qemu_socket(af, SOCK_DGRAM, 0);
+ so->s = slirp_socket(af, SOCK_DGRAM, 0);
if (so->s != -1) {
so->so_expire = curtime + SO_EXPIRE;
insque(so, &so->slirp->udb);
@@ -292,7 +291,8 @@ udp_attach(struct socket *so, unsigned short af)
void
udp_detach(struct socket *so)
{
- closesocket(so->s);
+ so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque);
+ slirp_closesocket(so->s);
sofree(so);
}
@@ -319,15 +319,15 @@ udp_tos(struct socket *so)
}
struct socket *
-udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
- u_int lport, int flags)
+udp_listen(Slirp *slirp, uint32_t haddr, unsigned hport, uint32_t laddr,
+ unsigned lport, int flags)
{
struct sockaddr_in addr;
struct socket *so;
socklen_t addrlen = sizeof(struct sockaddr_in);
so = socreate(slirp);
- so->s = qemu_socket(AF_INET,SOCK_DGRAM,0);
+ so->s = slirp_socket(AF_INET,SOCK_DGRAM,0);
if (so->s < 0) {
sofree(so);
return NULL;
@@ -343,7 +343,7 @@ udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
udp_detach(so);
return NULL;
}
- socket_set_fast_reuse(so->s);
+ slirp_socket_set_fast_reuse(so->s);
getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
so->fhost.sin = addr;
diff --git a/slirp/udp.h b/slirp/udp.h
index be657cf922..3d29504caa 100644
--- a/slirp/udp.h
+++ b/slirp/udp.h
@@ -78,7 +78,7 @@ void udp_cleanup(Slirp *);
void udp_input(register struct mbuf *, int);
int udp_attach(struct socket *, unsigned short af);
void udp_detach(struct socket *);
-struct socket * udp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int,
+struct socket * udp_listen(Slirp *, uint32_t, unsigned, uint32_t, unsigned,
int);
int udp_output(struct socket *so, struct mbuf *m,
struct sockaddr_in *saddr, struct sockaddr_in *daddr,
diff --git a/slirp/udp6.c b/slirp/udp6.c
index fa531e03c4..be5cba1f54 100644
--- a/slirp/udp6.c
+++ b/slirp/udp6.c
@@ -3,8 +3,6 @@
* Guillaume Subiron
*/
-#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "slirp.h"
#include "udp.h"
#include "dhcpv6.h"
diff --git a/slirp/util.c b/slirp/util.c
new file mode 100644
index 0000000000..84f5afdbc3
--- /dev/null
+++ b/slirp/util.c
@@ -0,0 +1,207 @@
+/*
+ * util.c (mostly based on QEMU os-win32.c)
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010-2016 Red Hat, Inc.
+ *
+ * QEMU library functions for win32 which are shared between QEMU and
+ * the QEMU tools.
+ *
+ * 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 "util.h"
+
+#include <glib.h>
+#include <fcntl.h>
+#include <stdint.h>
+
+#if defined(_WIN32) && !defined(WITH_QEMU)
+int inet_aton(const char *cp, struct in_addr *ia)
+{
+ uint32_t addr = inet_addr(cp);
+ if (addr == 0xffffffff) {
+ return 0;
+ }
+ ia->s_addr = addr;
+ return 1;
+}
+#endif
+
+void slirp_set_nonblock(int fd)
+{
+#ifndef _WIN32
+ int f;
+ f = fcntl(fd, F_GETFL);
+ assert(f != -1);
+ f = fcntl(fd, F_SETFL, f | O_NONBLOCK);
+ assert(f != -1);
+#else
+ unsigned long opt = 1;
+ ioctlsocket(fd, FIONBIO, &opt);
+#endif
+}
+
+static void slirp_set_cloexec(int fd)
+{
+#ifndef _WIN32
+ int f;
+ f = fcntl(fd, F_GETFD);
+ assert(f != -1);
+ f = fcntl(fd, F_SETFD, f | FD_CLOEXEC);
+ assert(f != -1);
+#endif
+}
+
+/*
+ * Opens a socket with FD_CLOEXEC set
+ */
+int slirp_socket(int domain, int type, int protocol)
+{
+ int ret;
+
+#ifdef SOCK_CLOEXEC
+ ret = socket(domain, type | SOCK_CLOEXEC, protocol);
+ if (ret != -1 || errno != EINVAL) {
+ return ret;
+ }
+#endif
+ ret = socket(domain, type, protocol);
+ if (ret >= 0) {
+ slirp_set_cloexec(ret);
+ }
+
+ return ret;
+}
+
+#ifdef _WIN32
+static int socket_error(void)
+{
+ switch (WSAGetLastError()) {
+ case 0:
+ return 0;
+ case WSAEINTR:
+ return EINTR;
+ case WSAEINVAL:
+ return EINVAL;
+ case WSA_INVALID_HANDLE:
+ return EBADF;
+ case WSA_NOT_ENOUGH_MEMORY:
+ return ENOMEM;
+ case WSA_INVALID_PARAMETER:
+ return EINVAL;
+ case WSAENAMETOOLONG:
+ return ENAMETOOLONG;
+ case WSAENOTEMPTY:
+ return ENOTEMPTY;
+ case WSAEWOULDBLOCK:
+ /* not using EWOULDBLOCK as we don't want code to have
+ * to check both EWOULDBLOCK and EAGAIN */
+ return EAGAIN;
+ case WSAEINPROGRESS:
+ return EINPROGRESS;
+ case WSAEALREADY:
+ return EALREADY;
+ case WSAENOTSOCK:
+ return ENOTSOCK;
+ case WSAEDESTADDRREQ:
+ return EDESTADDRREQ;
+ case WSAEMSGSIZE:
+ return EMSGSIZE;
+ case WSAEPROTOTYPE:
+ return EPROTOTYPE;
+ case WSAENOPROTOOPT:
+ return ENOPROTOOPT;
+ case WSAEPROTONOSUPPORT:
+ return EPROTONOSUPPORT;
+ case WSAEOPNOTSUPP:
+ return EOPNOTSUPP;
+ case WSAEAFNOSUPPORT:
+ return EAFNOSUPPORT;
+ case WSAEADDRINUSE:
+ return EADDRINUSE;
+ case WSAEADDRNOTAVAIL:
+ return EADDRNOTAVAIL;
+ case WSAENETDOWN:
+ return ENETDOWN;
+ case WSAENETUNREACH:
+ return ENETUNREACH;
+ case WSAENETRESET:
+ return ENETRESET;
+ case WSAECONNABORTED:
+ return ECONNABORTED;
+ case WSAECONNRESET:
+ return ECONNRESET;
+ case WSAENOBUFS:
+ return ENOBUFS;
+ case WSAEISCONN:
+ return EISCONN;
+ case WSAENOTCONN:
+ return ENOTCONN;
+ case WSAETIMEDOUT:
+ return ETIMEDOUT;
+ case WSAECONNREFUSED:
+ return ECONNREFUSED;
+ case WSAELOOP:
+ return ELOOP;
+ case WSAEHOSTUNREACH:
+ return EHOSTUNREACH;
+ default:
+ return EIO;
+ }
+}
+
+#undef ioctlsocket
+int slirp_ioctlsocket(int fd, int req, void *val)
+{
+ int ret;
+ ret = ioctlsocket(fd, req, val);
+ if (ret < 0) {
+ errno = socket_error();
+ }
+ return ret;
+}
+
+#undef closesocket
+int slirp_closesocket(int fd)
+{
+ int ret;
+ ret = closesocket(fd);
+ if (ret < 0) {
+ errno = socket_error();
+ }
+ return ret;
+}
+#endif /* WIN32 */
+
+void slirp_pstrcpy(char *buf, int buf_size, const char *str)
+{
+ int c;
+ char *q = buf;
+
+ if (buf_size <= 0)
+ return;
+
+ for(;;) {
+ c = *str++;
+ if (c == 0 || q >= buf + buf_size - 1)
+ break;
+ *q++ = c;
+ }
+ *q = '\0';
+}
diff --git a/slirp/util.h b/slirp/util.h
new file mode 100644
index 0000000000..4963747aef
--- /dev/null
+++ b/slirp/util.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2010-2019 Red Hat, Inc.
+ *
+ * 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 UTIL_H_
+#define UTIL_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <windows.h>
+#else
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#endif
+
+#if defined(_WIN32)
+# define SLIRP_PACKED __attribute__((gcc_struct, packed))
+#else
+# define SLIRP_PACKED __attribute__((packed))
+#endif
+
+#ifndef DIV_ROUND_UP
+#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+#endif
+
+#ifndef container_of
+#define container_of(ptr, type, member) __extension__ ({ \
+ void *__mptr = (void *)(ptr); \
+ ((type *)(__mptr - offsetof(type, member))); })
+#endif
+
+#if defined(_WIN32) /* CONFIG_IOVEC */
+# if !defined(IOV_MAX) /* XXX: to avoid duplicate with QEMU osdep.h */
+struct iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+# endif
+#else
+#include <sys/uio.h>
+#endif
+
+#define SCALE_MS 1000000
+
+#define ETH_ALEN 6
+#define ETH_HLEN 14
+#define ETH_P_IP (0x0800) /* Internet Protocol packet */
+#define ETH_P_ARP (0x0806) /* Address Resolution packet */
+#define ETH_P_IPV6 (0x86dd)
+#define ETH_P_VLAN (0x8100)
+#define ETH_P_DVLAN (0x88a8)
+#define ETH_P_NCSI (0x88f8)
+#define ETH_P_UNKNOWN (0xffff)
+
+#ifdef _WIN32
+int slirp_closesocket(int fd);
+int slirp_ioctlsocket(int fd, int req, void *val);
+int inet_aton(const char *cp, struct in_addr *ia);
+#define slirp_getsockopt(sockfd, level, optname, optval, optlen) \
+ getsockopt(sockfd, level, optname, (void *)optval, optlen)
+#define slirp_setsockopt(sockfd, level, optname, optval, optlen) \
+ setsockopt(sockfd, level, optname, (const void *)optval, optlen)
+#define slirp_recv(sockfd, buf, len, flags) recv(sockfd, (void *)buf, len, flags)
+#else
+#define slirp_setsockopt setsockopt
+#define slirp_getsockopt getsockopt
+#define slirp_recv recv
+#define slirp_closesocket close
+#define slirp_ioctlsocket ioctl
+#endif
+
+int slirp_socket(int domain, int type, int protocol);
+void slirp_set_nonblock(int fd);
+
+static inline int slirp_socket_set_nodelay(int fd)
+{
+ int v = 1;
+ return slirp_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
+}
+
+static inline int slirp_socket_set_fast_reuse(int fd)
+{
+#ifndef _WIN32
+ int v = 1;
+ return slirp_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
+#else
+ /* Enabling the reuse of an endpoint that was used by a socket still in
+ * TIME_WAIT state is usually performed by setting SO_REUSEADDR. On Windows
+ * fast reuse is the default and SO_REUSEADDR does strange things. So we
+ * don't have to do anything here. More info can be found at:
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621.aspx */
+ return 0;
+#endif
+}
+
+void slirp_pstrcpy(char *buf, int buf_size, const char *str);
+
+#endif
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
index 5dd0aeeec6..1558ff1fe7 100644
--- a/stubs/Makefile.objs
+++ b/stubs/Makefile.objs
@@ -26,14 +26,13 @@ stub-obj-y += qtest.o
stub-obj-y += replay.o
stub-obj-y += runstate-check.o
stub-obj-y += set-fd-handler.o
-stub-obj-y += slirp.o
stub-obj-y += sysbus.o
stub-obj-y += tpm.o
stub-obj-y += trace-control.o
stub-obj-y += uuid.o
stub-obj-y += vm-stop.o
stub-obj-y += vmstate.o
-stub-obj-$(CONFIG_WIN32) += fd-register.o
+stub-obj-y += fd-register.o
stub-obj-y += qmp_memory_device.o
stub-obj-y += target-monitor-defs.o
stub-obj-y += target-get-monitor-def.o
diff --git a/stubs/slirp.c b/stubs/slirp.c
deleted file mode 100644
index 70704346fd..0000000000
--- a/stubs/slirp.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "qemu/osdep.h"
-#include "qemu-common.h"
-#include "qemu/host-utils.h"
-#include "slirp/libslirp.h"
-
-void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout)
-{
-}
-
-void slirp_pollfds_poll(GArray *pollfds, int select_error)
-{
-}
-
diff --git a/util/main-loop.c b/util/main-loop.c
index 443cb4cfe8..d4a521caeb 100644
--- a/util/main-loop.c
+++ b/util/main-loop.c
@@ -469,25 +469,42 @@ static int os_host_main_loop_wait(int64_t timeout)
}
#endif
+static NotifierList main_loop_poll_notifiers =
+ NOTIFIER_LIST_INITIALIZER(main_loop_poll_notifiers);
+
+void main_loop_poll_add_notifier(Notifier *notify)
+{
+ notifier_list_add(&main_loop_poll_notifiers, notify);
+}
+
+void main_loop_poll_remove_notifier(Notifier *notify)
+{
+ notifier_remove(notify);
+}
+
void main_loop_wait(int nonblocking)
{
+ MainLoopPoll mlpoll = {
+ .state = MAIN_LOOP_POLL_FILL,
+ .timeout = UINT32_MAX,
+ .pollfds = gpollfds,
+ };
int ret;
- uint32_t timeout = UINT32_MAX;
int64_t timeout_ns;
if (nonblocking) {
- timeout = 0;
+ mlpoll.timeout = 0;
}
/* poll any events */
g_array_set_size(gpollfds, 0); /* reset for new iteration */
/* XXX: separate device handlers from system ones */
- slirp_pollfds_fill(gpollfds, &timeout);
+ notifier_list_notify(&main_loop_poll_notifiers, &mlpoll);
- if (timeout == UINT32_MAX) {
+ if (mlpoll.timeout == UINT32_MAX) {
timeout_ns = -1;
} else {
- timeout_ns = (uint64_t)timeout * (int64_t)(SCALE_MS);
+ timeout_ns = (uint64_t)mlpoll.timeout * (int64_t)(SCALE_MS);
}
timeout_ns = qemu_soonest_timeout(timeout_ns,
@@ -495,7 +512,8 @@ void main_loop_wait(int nonblocking)
&main_loop_tlg));
ret = os_host_main_loop_wait(timeout_ns);
- slirp_pollfds_poll(gpollfds, (ret < 0));
+ mlpoll.state = ret < 0 ? MAIN_LOOP_POLL_ERR : MAIN_LOOP_POLL_OK;
+ notifier_list_notify(&main_loop_poll_notifiers, &mlpoll);
/* CPU thread can infinitely wait for event after
missing the warp */
diff --git a/util/osdep.c b/util/osdep.c
index 4b5dc7287d..3f04326040 100644
--- a/util/osdep.c
+++ b/util/osdep.c
@@ -29,7 +29,7 @@
#include <sys/statvfs.h>
/* See MySQL bug #7156 (http://bugs.mysql.com/bug.php?id=7156) for
discussion about Solaris header problems */
-extern int madvise(caddr_t, size_t, int);
+extern int madvise(char *, size_t, int);
#endif
#include "qemu-common.h"