diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2017-05-02 15:16:20 +0100 |
---|---|---|
committer | Stefan Hajnoczi <stefanha@redhat.com> | 2017-05-02 15:16:29 +0100 |
commit | e619b14746e5d8c0e53061661fd0e1da01fd4d60 (patch) | |
tree | 7ef36747afcc049baa1e5993f2c7d7f19bdc9c44 | |
parent | 38bb54f323bf7c83496b6a044cfd28896e997a00 (diff) | |
parent | eb5d4f5329df83ea15244b47f7fbca21adaae41b (diff) |
Merge remote-tracking branch 'sthibault/tags/samuel-thibault' into staging
slirp updates
# gpg: Signature made Sat 29 Apr 2017 05:45:24 PM BST
# gpg: using RSA key 0xB0A51BF58C9179C5
# gpg: Good signature from "Samuel Thibault <samuel.thibault@aquilenet.fr>"
# gpg: aka "Samuel Thibault <sthibault@debian.org>"
# gpg: aka "Samuel Thibault <samuel.thibault@gnu.org>"
# gpg: aka "Samuel Thibault <samuel.thibault@inria.fr>"
# gpg: aka "Samuel Thibault <samuel.thibault@labri.fr>"
# gpg: aka "Samuel Thibault <samuel.thibault@ens-lyon.org>"
# gpg: aka "Samuel Thibault <samuel.thibault@u-bordeaux.fr>"
# Primary key fingerprint: 900C B024 B679 31D4 0F82 304B D017 8C76 7D06 9EE6
# Subkey fingerprint: AEBF 7448 FAB9 453A 4552 390E B0A5 1BF5 8C91 79C5
* sthibault/tags/samuel-thibault:
slirp: VMStatify remaining except for loop
slirp: VMStatify socket level
slirp: Common lhost/fhost union
slirp: VMStatify sbuf
slirp: VMState conversion; tcpcb
slirp: fix pinging the virtual ipv4 DNS server
slirp: tftp, copy sockaddr_size
slirp/smb: Replace constant strings by glib string
slirp: allow host port 0 for hostfwd
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
-rw-r--r-- | net/slirp.c | 32 | ||||
-rw-r--r-- | slirp/ip_icmp.c | 5 | ||||
-rw-r--r-- | slirp/sbuf.h | 4 | ||||
-rw-r--r-- | slirp/slirp.c | 494 | ||||
-rw-r--r-- | slirp/socket.h | 24 | ||||
-rw-r--r-- | slirp/tcp_var.h | 6 | ||||
-rw-r--r-- | slirp/tftp.c | 2 |
7 files changed, 310 insertions, 257 deletions
diff --git a/net/slirp.c b/net/slirp.c index f97ec23345..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; @@ -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; } @@ -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; } 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 { 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 9a50918346..2f2ec2c1b3 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -1133,259 +1133,317 @@ 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; - - 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); + tcp_template((struct tcpcb *)opaque); + + return 0; } -static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf) +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 void sbuf_tmp_pre_save(void *opaque) { - uint32_t off; - - 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); + 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 void slirp_socket_save(QEMUFile *f, struct socket *so) +static int sbuf_tmp_post_load(void *opaque, int version) { - 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"); + 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; } - 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"); + 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; } - 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); - slirp_sbuf_save(f, &so->so_rcv); - slirp_sbuf_save(f, &so->so_snd); - slirp_tcp_save(f, so->so_tcpcb); -} -static void slirp_bootp_save(QEMUFile *f, Slirp *slirp) -{ - int i; + tmp->parent->sb_wptr = tmp->parent->sb_data + tmp->woff; + tmp->parent->sb_rptr = tmp->parent->sb_data + tmp->roff; - 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); - } + return 0; } -static void slirp_state_save(QEMUFile *f, void *opaque) -{ - Slirp *slirp = opaque; - struct ex_list *ex_ptr; - - for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) - if (ex_ptr->ex_pty == 3) { - 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); - slirp_socket_save(f, so); - } - qemu_put_byte(f, 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() + } +}; - qemu_put_be16(f, slirp->ip_id); +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() + } +}; - slirp_bootp_save(f, slirp); +static bool slirp_older_than_v4(void *opaque, int version_id) +{ + return version_id < 4; } -static void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp) +static bool slirp_family_inet(void *opaque, int version_id) { - 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); + union slirp_sockaddr *ssa = (union slirp_sockaddr *)opaque; + return ssa->ss.ss_family == AF_INET; } -static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf) +static int slirp_socket_pre_load(void *opaque) { - uint32_t off, sb_cc, sb_datalen; + 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; +} - sb_cc = qemu_get_be32(f); - sb_datalen = qemu_get_be32(f); +#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 - sbreserve(sbuf, sb_datalen); +/* 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; - if (sbuf->sb_datalen != sb_datalen) - return -ENOMEM; +#define SS_FAMILY_MIG_IPV4 2 /* Linux, BSD, Win... */ +#define SS_FAMILY_MIG_IPV6 10 /* Linux */ +#define SS_FAMILY_MIG_OTHER 0xffff - sbuf->sb_cc = sb_cc; +static void ss_family_pre_save(void *opaque) +{ + SS_FamilyTmpStruct *tss = opaque; - 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); + tss->portable_family = SS_FAMILY_MIG_OTHER; - return 0; + 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 slirp_socket_load(QEMUFile *f, struct socket *so, int version_id) +static int ss_family_post_load(void *opaque, int version_id) { - if (tcp_attach(so) < 0) - return -ENOMEM; + SS_FamilyTmpStruct *tss = opaque; - 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"); - } + 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; } - 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); - if (slirp_sbuf_load(f, &so->so_rcv) < 0) - return -ENOMEM; - if (slirp_sbuf_load(f, &so->so_snd) < 0) - return -ENOMEM; - slirp_tcp_load(f, so->so_tcpcb); return 0; } -static void slirp_bootp_load(QEMUFile *f, Slirp *slirp) -{ - int i; +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() + } +}; - 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 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 ex_list *ex_ptr; + + for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) + if (ex_ptr->ex_pty == 3) { + 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; @@ -1398,7 +1456,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; @@ -1420,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); } diff --git a/slirp/socket.h b/slirp/socket.h index 8feed2aea4..2f224bc34f 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 */ @@ -30,23 +36,15 @@ struct socket { * PING reply's */ 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; + uint32_t so_urgc; + 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 @@ -56,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 */ 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 */ 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; |