diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-02-07 18:53:25 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-02-07 18:53:25 +0000 |
commit | e47f81b617684c4546af286d307b69014a83538a (patch) | |
tree | 11e4e8c6482d092d91ed9faed327f341f3cc69f8 | |
parent | ff372bb5c469e14d6d64f788710b7c3e37c12e01 (diff) | |
parent | ee261c02332ea856352f250b295a8ecd1eeb748e (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>
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 @@ -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" |