From 0bed71edbc323de12ed1e5390a85a013f6a143f4 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Sat, 25 Feb 2017 22:31:58 +0100 Subject: [PATCH 1/9] slirp: allow host port 0 for hostfwd The OS will allocate automatically a free port. This is useful if you want to be sure to not get any port conflict. You still have to figure out which port you got, for example with "lsof" (this could be exposed in the monitor if needed). Example of use: $ qemu-system-x86_64 -net user,hostfwd=127.0.0.1:0-:22 ... Then, get your port with: $ lsof -np 1474 | grep LISTEN qemu-syst 31777 bernat 12u IPv4 [...] TCP 127.0.0.1:35145 (LISTEN) Signed-off-by: Vincent Bernat Signed-off-by: Samuel Thibault --- net/slirp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/slirp.c b/net/slirp.c index f97ec23345..11b2dd249a 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -487,7 +487,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str, goto fail_syntax; } host_port = strtol(buf, &end, 0); - if (*end != '\0' || host_port < 1 || host_port > 65535) { + if (*end != '\0' || host_port < 0 || host_port > 65535) { goto fail_syntax; } From f95cc8b6cc3ad8c4b687f305a978d67091c28138 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 7 Apr 2017 15:32:54 +0100 Subject: [PATCH 2/9] slirp/smb: Replace constant strings by glib string gcc 7 (on fedora 26) objects to many of the snprintf's in the smb path and command creation because it can't figure out that the smb_dir (i.e. the /tmp dir for the configuration) is known to be short. Replace all these fixed length buffers by g_str* functions that dynamically allocate and use g_dir_make_tmp to make the directory. (It's fairly new glib but we have a compat function for it). Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Eric Blake Signed-off-by: Samuel Thibault --- net/slirp.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/net/slirp.c b/net/slirp.c index 11b2dd249a..c705a60b62 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -80,7 +80,7 @@ typedef struct SlirpState { Slirp *slirp; Notifier exit_notifier; #ifndef _WIN32 - char smb_dir[128]; + gchar *smb_dir; #endif } SlirpState; @@ -558,11 +558,10 @@ int net_slirp_redir(const char *redir_str) /* automatic user mode samba server configuration */ static void slirp_smb_cleanup(SlirpState *s) { - char cmd[128]; int ret; - if (s->smb_dir[0] != '\0') { - snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir); + if (s->smb_dir) { + gchar *cmd = g_strdup_printf("rm -rf %s", s->smb_dir); ret = system(cmd); if (ret == -1 || !WIFEXITED(ret)) { error_report("'%s' failed.", cmd); @@ -570,15 +569,17 @@ static void slirp_smb_cleanup(SlirpState *s) error_report("'%s' failed. Error code: %d", cmd, WEXITSTATUS(ret)); } - s->smb_dir[0] = '\0'; + g_free(cmd); + g_free(s->smb_dir); + s->smb_dir = NULL; } } static int slirp_smb(SlirpState* s, const char *exported_dir, struct in_addr vserver_addr) { - char smb_conf[128]; - char smb_cmdline[128]; + char *smb_conf; + char *smb_cmdline; struct passwd *passwd; FILE *f; @@ -600,19 +601,19 @@ static int slirp_smb(SlirpState* s, const char *exported_dir, return -1; } - snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.XXXXXX"); - if (!mkdtemp(s->smb_dir)) { - error_report("could not create samba server dir '%s'", s->smb_dir); - s->smb_dir[0] = 0; + s->smb_dir = g_dir_make_tmp("qemu-smb.XXXXXX", NULL); + if (!s->smb_dir) { + error_report("could not create samba server dir"); return -1; } - snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf"); + smb_conf = g_strdup_printf("%s/%s", s->smb_dir, "smb.conf"); f = fopen(smb_conf, "w"); if (!f) { slirp_smb_cleanup(s); error_report("could not create samba server configuration file '%s'", smb_conf); + g_free(smb_conf); return -1; } fprintf(f, @@ -651,15 +652,18 @@ static int slirp_smb(SlirpState* s, const char *exported_dir, ); fclose(f); - snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -l %s -s %s", + smb_cmdline = g_strdup_printf("%s -l %s -s %s", CONFIG_SMBD_COMMAND, s->smb_dir, smb_conf); + g_free(smb_conf); if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0 || slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 445) < 0) { slirp_smb_cleanup(s); + g_free(smb_cmdline); error_report("conflicting/invalid smbserver address"); return -1; } + g_free(smb_cmdline); return 0; } From 17eb587aeb492fe68f8130b027154ff0921fc0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Thu, 23 Mar 2017 15:31:56 +0400 Subject: [PATCH 3/9] slirp: tftp, copy sockaddr_size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ASAN detects an "unknown-crash" when running pxe-test: /ppc64/pxe/spapr-vlan: ================================================================= ==7143==ERROR: AddressSanitizer: unknown-crash on address 0x7f6dcd298d30 at pc 0x55e22218830d bp 0x7f6dcd2989e0 sp 0x7f6dcd2989d0 READ of size 128 at 0x7f6dcd298d30 thread T2 #0 0x55e22218830c in tftp_session_allocate /home/elmarco/src/qq/slirp/tftp.c:73 #1 0x55e22218a1f8 in tftp_handle_rrq /home/elmarco/src/qq/slirp/tftp.c:289 #2 0x55e22218b54c in tftp_input /home/elmarco/src/qq/slirp/tftp.c:446 #3 0x55e2221833fe in udp6_input /home/elmarco/src/qq/slirp/udp6.c:82 #4 0x55e222137b17 in ip6_input /home/elmarco/src/qq/slirp/ip6_input.c:67 Address 0x7f6dcd298d30 is located in stack of thread T2 at offset 96 in frame #0 0x55e222182420 in udp6_input /home/elmarco/src/qq/slirp/udp6.c:13 This frame has 3 object(s): [32, 48) '' [96, 124) 'lhost' <== Memory access at offset 96 partially overflows this variable [160, 200) 'save_ip' <== Memory access at offset 96 partially underflows this variable The sockaddr_storage pointer is the sockaddr_in6 lhost on the stack. Copy only the source addr size. Signed-off-by: Marc-André Lureau Reviewed-by: Thomas Huth Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Samuel Thibault --- slirp/tftp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slirp/tftp.c b/slirp/tftp.c index 50e714807d..a9bc4bb1b6 100644 --- a/slirp/tftp.c +++ b/slirp/tftp.c @@ -70,7 +70,7 @@ static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas, found: memset(spt, 0, sizeof(*spt)); - spt->client_addr = *srcsas; + memcpy(&spt->client_addr, srcsas, sockaddr_size(srcsas)); spt->fd = -1; spt->block_size = 512; spt->client_port = tp->udp.uh_sport; From 7d1724976f1f460769f4dddcdb15369cd57cf72e Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sat, 29 Apr 2017 14:37:09 +0200 Subject: [PATCH 4/9] slirp: fix pinging the virtual ipv4 DNS server so that people do not think it is not working at least basically. Signed-off-by: Samuel Thibault --- slirp/ip_icmp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c index 5ffc7a683d..0b667a429a 100644 --- a/slirp/ip_icmp.c +++ b/slirp/ip_icmp.c @@ -152,8 +152,9 @@ icmp_input(struct mbuf *m, int hlen) switch (icp->icmp_type) { case ICMP_ECHO: ip->ip_len += hlen; /* since ip_input subtracts this */ - if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) { - icmp_reflect(m); + if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr || + ip->ip_dst.s_addr == slirp->vnameserver_addr.s_addr) { + icmp_reflect(m); } else if (slirp->restricted) { goto freeit; } else { From e3ec38ffd6eeff3c3db9f0fd942e37a60f36e86c Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 20 Feb 2017 18:50:16 +0000 Subject: [PATCH 5/9] slirp: VMState conversion; tcpcb Convert the migration of the struct tcpcb to use a VMStateDescription, the rest of it will come later. Mostly mechanical, except for conversion of some 'char' to uint8_t to ensure portability. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Samuel Thibault Reviewed-by: Juan Quintela Signed-off-by: Samuel Thibault --- slirp/slirp.c | 149 ++++++++++++++++++------------------------------ slirp/tcp_var.h | 6 +- 2 files changed, 57 insertions(+), 98 deletions(-) diff --git a/slirp/slirp.c b/slirp/slirp.c index 9a50918346..2c2a589303 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -1133,53 +1133,62 @@ void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port, tcp_output(sototcpcb(so)); } -static void slirp_tcp_save(QEMUFile *f, struct tcpcb *tp) +static int slirp_tcp_post_load(void *opaque, int version) { - int i; + tcp_template((struct tcpcb *)opaque); - qemu_put_sbe16(f, tp->t_state); - for (i = 0; i < TCPT_NTIMERS; i++) - qemu_put_sbe16(f, tp->t_timer[i]); - qemu_put_sbe16(f, tp->t_rxtshift); - qemu_put_sbe16(f, tp->t_rxtcur); - qemu_put_sbe16(f, tp->t_dupacks); - qemu_put_be16(f, tp->t_maxseg); - qemu_put_sbyte(f, tp->t_force); - qemu_put_be16(f, tp->t_flags); - qemu_put_be32(f, tp->snd_una); - qemu_put_be32(f, tp->snd_nxt); - qemu_put_be32(f, tp->snd_up); - qemu_put_be32(f, tp->snd_wl1); - qemu_put_be32(f, tp->snd_wl2); - qemu_put_be32(f, tp->iss); - qemu_put_be32(f, tp->snd_wnd); - qemu_put_be32(f, tp->rcv_wnd); - qemu_put_be32(f, tp->rcv_nxt); - qemu_put_be32(f, tp->rcv_up); - qemu_put_be32(f, tp->irs); - qemu_put_be32(f, tp->rcv_adv); - qemu_put_be32(f, tp->snd_max); - qemu_put_be32(f, tp->snd_cwnd); - qemu_put_be32(f, tp->snd_ssthresh); - qemu_put_sbe16(f, tp->t_idle); - qemu_put_sbe16(f, tp->t_rtt); - qemu_put_be32(f, tp->t_rtseq); - qemu_put_sbe16(f, tp->t_srtt); - qemu_put_sbe16(f, tp->t_rttvar); - qemu_put_be16(f, tp->t_rttmin); - qemu_put_be32(f, tp->max_sndwnd); - qemu_put_byte(f, tp->t_oobflags); - qemu_put_byte(f, tp->t_iobc); - qemu_put_sbe16(f, tp->t_softerror); - qemu_put_byte(f, tp->snd_scale); - qemu_put_byte(f, tp->rcv_scale); - qemu_put_byte(f, tp->request_r_scale); - qemu_put_byte(f, tp->requested_s_scale); - qemu_put_be32(f, tp->ts_recent); - qemu_put_be32(f, tp->ts_recent_age); - qemu_put_be32(f, tp->last_ack_sent); + 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() + } +}; + static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf) { uint32_t off; @@ -1222,7 +1231,7 @@ static void slirp_socket_save(QEMUFile *f, struct socket *so) qemu_put_be32(f, so->so_state); slirp_sbuf_save(f, &so->so_rcv); slirp_sbuf_save(f, &so->so_snd); - slirp_tcp_save(f, so->so_tcpcb); + vmstate_save_state(f, &vmstate_slirp_tcp, so->so_tcpcb, 0); } static void slirp_bootp_save(QEMUFile *f, Slirp *slirp) @@ -1258,54 +1267,6 @@ static void slirp_state_save(QEMUFile *f, void *opaque) slirp_bootp_save(f, slirp); } -static void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp) -{ - int i; - - tp->t_state = qemu_get_sbe16(f); - for (i = 0; i < TCPT_NTIMERS; i++) - tp->t_timer[i] = qemu_get_sbe16(f); - tp->t_rxtshift = qemu_get_sbe16(f); - tp->t_rxtcur = qemu_get_sbe16(f); - tp->t_dupacks = qemu_get_sbe16(f); - tp->t_maxseg = qemu_get_be16(f); - tp->t_force = qemu_get_sbyte(f); - tp->t_flags = qemu_get_be16(f); - tp->snd_una = qemu_get_be32(f); - tp->snd_nxt = qemu_get_be32(f); - tp->snd_up = qemu_get_be32(f); - tp->snd_wl1 = qemu_get_be32(f); - tp->snd_wl2 = qemu_get_be32(f); - tp->iss = qemu_get_be32(f); - tp->snd_wnd = qemu_get_be32(f); - tp->rcv_wnd = qemu_get_be32(f); - tp->rcv_nxt = qemu_get_be32(f); - tp->rcv_up = qemu_get_be32(f); - tp->irs = qemu_get_be32(f); - tp->rcv_adv = qemu_get_be32(f); - tp->snd_max = qemu_get_be32(f); - tp->snd_cwnd = qemu_get_be32(f); - tp->snd_ssthresh = qemu_get_be32(f); - tp->t_idle = qemu_get_sbe16(f); - tp->t_rtt = qemu_get_sbe16(f); - tp->t_rtseq = qemu_get_be32(f); - tp->t_srtt = qemu_get_sbe16(f); - tp->t_rttvar = qemu_get_sbe16(f); - tp->t_rttmin = qemu_get_be16(f); - tp->max_sndwnd = qemu_get_be32(f); - tp->t_oobflags = qemu_get_byte(f); - tp->t_iobc = qemu_get_byte(f); - tp->t_softerror = qemu_get_sbe16(f); - tp->snd_scale = qemu_get_byte(f); - tp->rcv_scale = qemu_get_byte(f); - tp->request_r_scale = qemu_get_byte(f); - tp->requested_s_scale = qemu_get_byte(f); - tp->ts_recent = qemu_get_be32(f); - tp->ts_recent_age = qemu_get_be32(f); - tp->last_ack_sent = qemu_get_be32(f); - tcp_template(tp); -} - static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf) { uint32_t off, sb_cc, sb_datalen; @@ -1371,9 +1332,7 @@ static int slirp_socket_load(QEMUFile *f, struct socket *so, int version_id) return -ENOMEM; if (slirp_sbuf_load(f, &so->so_snd) < 0) return -ENOMEM; - slirp_tcp_load(f, so->so_tcpcb); - - return 0; + return vmstate_load_state(f, &vmstate_slirp_tcp, so->so_tcpcb, 0); } static void slirp_bootp_load(QEMUFile *f, Slirp *slirp) diff --git a/slirp/tcp_var.h b/slirp/tcp_var.h index 0f8f187c5c..895ef6df1e 100644 --- a/slirp/tcp_var.h +++ b/slirp/tcp_var.h @@ -48,7 +48,7 @@ struct tcpcb { short t_rxtcur; /* current retransmit value */ short t_dupacks; /* consecutive dup acks recd */ u_short t_maxseg; /* maximum segment size */ - char t_force; /* 1 if forcing out a byte */ + uint8_t t_force; /* 1 if forcing out a byte */ u_short t_flags; #define TF_ACKNOW 0x0001 /* ack peer immediately */ #define TF_DELACK 0x0002 /* ack, but try to delay it */ @@ -109,8 +109,8 @@ struct tcpcb { uint32_t max_sndwnd; /* largest window peer has offered */ /* out-of-band data */ - char t_oobflags; /* have some */ - char t_iobc; /* input character */ + uint8_t t_oobflags; /* have some */ + uint8_t t_iobc; /* input character */ #define TCPOOB_HAVEDATA 0x01 #define TCPOOB_HADDATA 0x02 short t_softerror; /* possible error not yet reported */ From 2a7cab9e17bbe78f37c7515278eefc32876fa7a2 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 20 Feb 2017 18:50:17 +0000 Subject: [PATCH 6/9] slirp: VMStatify sbuf Convert the sbuf structure to a VMStateDescription. Note this uses the VMSTATE_WITH_TMP mechanism to calculate and reload the offsets based on the pointers. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: David Gibson Reviewed-by: Juan Quintela Signed-off-by: Samuel Thibault --- slirp/sbuf.h | 4 +- slirp/slirp.c | 116 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 78 insertions(+), 42 deletions(-) diff --git a/slirp/sbuf.h b/slirp/sbuf.h index efcec39a6b..a722ecb629 100644 --- a/slirp/sbuf.h +++ b/slirp/sbuf.h @@ -12,8 +12,8 @@ #define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc) struct sbuf { - u_int sb_cc; /* actual chars in buffer */ - u_int sb_datalen; /* Length of data */ + uint32_t sb_cc; /* actual chars in buffer */ + uint32_t sb_datalen; /* Length of data */ char *sb_wptr; /* write pointer. points to where the next * bytes should be written in the sbuf */ char *sb_rptr; /* read pointer. points to where the next diff --git a/slirp/slirp.c b/slirp/slirp.c index 2c2a589303..8fc4e8df73 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -1189,19 +1189,72 @@ static const VMStateDescription vmstate_slirp_tcp = { } }; -static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf) -{ - uint32_t off; +/* 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; +}; - qemu_put_be32(f, sbuf->sb_cc); - qemu_put_be32(f, sbuf->sb_datalen); - off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data); - qemu_put_sbe32(f, off); - off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data); - qemu_put_sbe32(f, off); - qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen); +static void 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; } +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) { + error_report("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 void slirp_socket_save(QEMUFile *f, struct socket *so) { qemu_put_be32(f, so->so_urgc); @@ -1229,8 +1282,9 @@ static void slirp_socket_save(QEMUFile *f, struct socket *so) qemu_put_byte(f, so->so_emu); qemu_put_byte(f, so->so_type); qemu_put_be32(f, so->so_state); - slirp_sbuf_save(f, &so->so_rcv); - slirp_sbuf_save(f, &so->so_snd); + /* TODO: Build vmstate at this level */ + vmstate_save_state(f, &vmstate_slirp_sbuf, &so->so_rcv, 0); + vmstate_save_state(f, &vmstate_slirp_sbuf, &so->so_snd, 0); vmstate_save_state(f, &vmstate_slirp_tcp, so->so_tcpcb, 0); } @@ -1267,31 +1321,9 @@ static void slirp_state_save(QEMUFile *f, void *opaque) slirp_bootp_save(f, slirp); } -static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf) -{ - uint32_t off, sb_cc, sb_datalen; - - sb_cc = qemu_get_be32(f); - sb_datalen = qemu_get_be32(f); - - sbreserve(sbuf, sb_datalen); - - if (sbuf->sb_datalen != sb_datalen) - return -ENOMEM; - - sbuf->sb_cc = sb_cc; - - off = qemu_get_sbe32(f); - sbuf->sb_wptr = sbuf->sb_data + off; - off = qemu_get_sbe32(f); - sbuf->sb_rptr = sbuf->sb_data + off; - qemu_get_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen); - - return 0; -} - static int slirp_socket_load(QEMUFile *f, struct socket *so, int version_id) { + int ret = 0; if (tcp_attach(so) < 0) return -ENOMEM; @@ -1328,11 +1360,15 @@ static int slirp_socket_load(QEMUFile *f, struct socket *so, int version_id) so->so_emu = qemu_get_byte(f); so->so_type = qemu_get_byte(f); so->so_state = qemu_get_be32(f); - if (slirp_sbuf_load(f, &so->so_rcv) < 0) - return -ENOMEM; - if (slirp_sbuf_load(f, &so->so_snd) < 0) - return -ENOMEM; - return vmstate_load_state(f, &vmstate_slirp_tcp, so->so_tcpcb, 0); + /* TODO: VMState at this level */ + ret = vmstate_load_state(f, &vmstate_slirp_sbuf, &so->so_rcv, 0); + if (!ret) { + ret = vmstate_load_state(f, &vmstate_slirp_sbuf, &so->so_snd, 0); + } + if (!ret) { + ret = vmstate_load_state(f, &vmstate_slirp_tcp, so->so_tcpcb, 0); + } + return ret; } static void slirp_bootp_load(QEMUFile *f, Slirp *slirp) From 7eddf37c63d20367989fc0ecb25460b64817f6df Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 20 Feb 2017 18:50:18 +0000 Subject: [PATCH 7/9] slirp: Common lhost/fhost union MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The socket structure has a pair of unions for lhost and fhost addresses; the unions are identical so split them out into a separate union declaration. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Juan Quintela Signed-off-by: Samuel Thibault --- slirp/socket.h | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/slirp/socket.h b/slirp/socket.h index 8feed2aea4..c1be77eaf3 100644 --- a/slirp/socket.h +++ b/slirp/socket.h @@ -15,6 +15,12 @@ * Our socket structure */ +union slirp_sockaddr { + struct sockaddr_storage ss; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; +}; + struct socket { struct socket *so_next,*so_prev; /* For a linked list of sockets */ @@ -31,22 +37,14 @@ struct socket { struct tcpiphdr *so_ti; /* Pointer to the original ti within * so_mconn, for non-blocking connections */ int so_urgc; - union { /* foreign host */ - struct sockaddr_storage ss; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - } fhost; + union slirp_sockaddr fhost; /* Foreign host */ #define so_faddr fhost.sin.sin_addr #define so_fport fhost.sin.sin_port #define so_faddr6 fhost.sin6.sin6_addr #define so_fport6 fhost.sin6.sin6_port #define so_ffamily fhost.ss.ss_family - union { /* local host */ - struct sockaddr_storage ss; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - } lhost; + union slirp_sockaddr lhost; /* Local host */ #define so_laddr lhost.sin.sin_addr #define so_lport lhost.sin.sin_port #define so_laddr6 lhost.sin6.sin6_addr From 14650df4020c60be6c498f05622ac07338cebb09 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 3 Apr 2017 18:18:42 +0100 Subject: [PATCH 8/9] slirp: VMStatify socket level Working up the stack, this replaces the slirp_socket_load/save with VMState definitions. A place holder for IPv6 support is added as a comment; it needs testing once the rest of the IPv6 code is there. Signed-off-by: Dr. David Alan Gilbert Signed-off-by: Samuel Thibault --- slirp/slirp.c | 229 +++++++++++++++++++++++++++++++------------------ slirp/socket.h | 6 +- 2 files changed, 150 insertions(+), 85 deletions(-) diff --git a/slirp/slirp.c b/slirp/slirp.c index 8fc4e8df73..c3426648e5 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -1254,40 +1254,154 @@ static const VMStateDescription vmstate_slirp_sbuf = { } }; - -static void slirp_socket_save(QEMUFile *f, struct socket *so) +static bool slirp_older_than_v4(void *opaque, int version_id) { - qemu_put_be32(f, so->so_urgc); - qemu_put_be16(f, so->so_ffamily); - switch (so->so_ffamily) { - case AF_INET: - qemu_put_be32(f, so->so_faddr.s_addr); - qemu_put_be16(f, so->so_fport); - break; - default: - error_report("so_ffamily unknown, unable to save so_faddr and" - " so_fport"); - } - qemu_put_be16(f, so->so_lfamily); - switch (so->so_lfamily) { - case AF_INET: - qemu_put_be32(f, so->so_laddr.s_addr); - qemu_put_be16(f, so->so_lport); - break; - default: - error_report("so_ffamily unknown, unable to save so_laddr and" - " so_lport"); - } - qemu_put_byte(f, so->so_iptos); - qemu_put_byte(f, so->so_emu); - qemu_put_byte(f, so->so_type); - qemu_put_be32(f, so->so_state); - /* TODO: Build vmstate at this level */ - vmstate_save_state(f, &vmstate_slirp_sbuf, &so->so_rcv, 0); - vmstate_save_state(f, &vmstate_slirp_sbuf, &so->so_snd, 0); - vmstate_save_state(f, &vmstate_slirp_tcp, so->so_tcpcb, 0); + 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 void 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; + } +} + +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: + error_report("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 void slirp_bootp_save(QEMUFile *f, Slirp *slirp) { int i; @@ -1312,7 +1426,7 @@ static void slirp_state_save(QEMUFile *f, void *opaque) continue; qemu_put_byte(f, 42); - slirp_socket_save(f, so); + vmstate_save_state(f, &vmstate_slirp_socket, so, NULL); } qemu_put_byte(f, 0); @@ -1321,55 +1435,6 @@ static void slirp_state_save(QEMUFile *f, void *opaque) slirp_bootp_save(f, slirp); } -static int slirp_socket_load(QEMUFile *f, struct socket *so, int version_id) -{ - int ret = 0; - if (tcp_attach(so) < 0) - return -ENOMEM; - - so->so_urgc = qemu_get_be32(f); - if (version_id <= 3) { - so->so_ffamily = AF_INET; - so->so_faddr.s_addr = qemu_get_be32(f); - so->so_laddr.s_addr = qemu_get_be32(f); - so->so_fport = qemu_get_be16(f); - so->so_lport = qemu_get_be16(f); - } else { - so->so_ffamily = qemu_get_be16(f); - switch (so->so_ffamily) { - case AF_INET: - so->so_faddr.s_addr = qemu_get_be32(f); - so->so_fport = qemu_get_be16(f); - break; - default: - error_report( - "so_ffamily unknown, unable to restore so_faddr and so_lport"); - } - so->so_lfamily = qemu_get_be16(f); - switch (so->so_lfamily) { - case AF_INET: - so->so_laddr.s_addr = qemu_get_be32(f); - so->so_lport = qemu_get_be16(f); - break; - default: - error_report( - "so_ffamily unknown, unable to restore so_laddr and so_lport"); - } - } - so->so_iptos = qemu_get_byte(f); - so->so_emu = qemu_get_byte(f); - so->so_type = qemu_get_byte(f); - so->so_state = qemu_get_be32(f); - /* TODO: VMState at this level */ - ret = vmstate_load_state(f, &vmstate_slirp_sbuf, &so->so_rcv, 0); - if (!ret) { - ret = vmstate_load_state(f, &vmstate_slirp_sbuf, &so->so_snd, 0); - } - if (!ret) { - ret = vmstate_load_state(f, &vmstate_slirp_tcp, so->so_tcpcb, 0); - } - return ret; -} static void slirp_bootp_load(QEMUFile *f, Slirp *slirp) { @@ -1393,7 +1458,7 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id) if (!so) return -ENOMEM; - ret = slirp_socket_load(f, so, version_id); + ret = vmstate_load_state(f, &vmstate_slirp_socket, so, version_id); if (ret < 0) return ret; diff --git a/slirp/socket.h b/slirp/socket.h index c1be77eaf3..2f224bc34f 100644 --- a/slirp/socket.h +++ b/slirp/socket.h @@ -36,7 +36,7 @@ struct socket { * PING reply's */ struct tcpiphdr *so_ti; /* Pointer to the original ti within * so_mconn, for non-blocking connections */ - int so_urgc; + uint32_t so_urgc; union slirp_sockaddr fhost; /* Foreign host */ #define so_faddr fhost.sin.sin_addr #define so_fport fhost.sin.sin_port @@ -54,8 +54,8 @@ struct socket { uint8_t so_iptos; /* Type of service */ uint8_t so_emu; /* Is the socket emulated? */ - u_char so_type; /* Type of socket, UDP or TCP */ - int so_state; /* internal state flags SS_*, below */ + uint8_t so_type; /* Type of socket, UDP or TCP */ + 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 */ From eb5d4f5329df83ea15244b47f7fbca21adaae41b Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Mon, 3 Apr 2017 18:18:43 +0100 Subject: [PATCH 9/9] slirp: VMStatify remaining except for loop This converts the remaining components, except for the top level loop, to VMState. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Juan Quintela Signed-off-by: Samuel Thibault --- slirp/slirp.c | 50 ++++++++++++++++++++------------------------------ 1 file changed, 20 insertions(+), 30 deletions(-) diff --git a/slirp/slirp.c b/slirp/slirp.c index c3426648e5..2f2ec2c1b3 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -1402,15 +1402,25 @@ static const VMStateDescription vmstate_slirp_socket = { } }; -static void slirp_bootp_save(QEMUFile *f, Slirp *slirp) -{ - int i; - - for (i = 0; i < NB_BOOTP_CLIENTS; i++) { - qemu_put_be16(f, slirp->bootp_clients[i].allocated); - qemu_put_buffer(f, slirp->bootp_clients[i].macaddr, 6); +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) { @@ -1430,22 +1440,10 @@ static void slirp_state_save(QEMUFile *f, void *opaque) } qemu_put_byte(f, 0); - qemu_put_be16(f, slirp->ip_id); - - slirp_bootp_save(f, slirp); + vmstate_save_state(f, &vmstate_slirp, slirp, NULL); } -static void slirp_bootp_load(QEMUFile *f, Slirp *slirp) -{ - int i; - - for (i = 0; i < NB_BOOTP_CLIENTS; i++) { - slirp->bootp_clients[i].allocated = qemu_get_be16(f); - qemu_get_buffer(f, slirp->bootp_clients[i].macaddr, 6); - } -} - static int slirp_state_load(QEMUFile *f, void *opaque, int version_id) { Slirp *slirp = opaque; @@ -1480,13 +1478,5 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id) so->extra = (void *)ex_ptr->ex_exec; } - if (version_id >= 2) { - slirp->ip_id = qemu_get_be16(f); - } - - if (version_id >= 3) { - slirp_bootp_load(f, slirp); - } - - return 0; + return vmstate_load_state(f, &vmstate_slirp, slirp, version_id); }