slirp updates

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEErr90SPq5RTpFUjkOsKUb9YyRecUFAlkEwyQACgkQsKUb9YyR
 ecUMQA/8D2F0OXuphid1kyfpFv5aX1SxWJiQ1hdY9Zjt/OOL+5pC9xseoVMf5GOK
 5y8JmoTMu/xzPHLWAZxAIU8cVulx3Ck4/KKgJk1zyxozZul2pAsDwZgG7AUzu8E/
 bLzMtdvW8zaNYVnxWuqBtZ39AgqBAo9SRYY4dGUAInEVIWXpfzeIxk3tMUUlcp4g
 Xwig4rKIsxqkBFgMDwwsRuVU6aS3rRjwrTa5/uHe4Z0Aob5nxS7uFhSXUC8wd1vN
 KPjHppUhrG4bfXF8A5vMrSJ68frPLnxw43P7V3PMLnNG7ys5+NI3o8FkJKHL20dx
 Y3dL06YdIsOybE0S+8unzl6XjVKvtEOG0UEKRK53DcYUEBUSEA27UsChOaVwsO5S
 qaRIMFWhyDaB+0zpQMnHhEzC+8RDKoseBtkEwr0rWWlmEVtlDRoCtsniExK9BFUJ
 c4d2z5eDuYire1MSN3lx5tU/F5dJj5AwH83Wkk6+RKUfs2kpvcHklzIPtcN//ZG7
 OyIxQfCfAOpNoifdumsh0xuq1Q2MhCmB1vEhfHcR4L2y+ifRUgQ80l88fvwhUMTG
 np/Yg/SNvBjTRjanor7YIhFYLcnev2NK9z/kLv2hJhOaIdFa9fh/KgW2VUFFnLG6
 /HVN6/Zk5+4+DczXeh3EbMknHTBgz8N/UUnjCwHUSeJZnUr9PSo=
 =0pFA
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Stefan Hajnoczi 2017-05-02 15:16:20 +01:00
commit e619b14746
7 changed files with 316 additions and 263 deletions

View File

@ -80,7 +80,7 @@ typedef struct SlirpState {
Slirp *slirp; Slirp *slirp;
Notifier exit_notifier; Notifier exit_notifier;
#ifndef _WIN32 #ifndef _WIN32
char smb_dir[128]; gchar *smb_dir;
#endif #endif
} SlirpState; } SlirpState;
@ -487,7 +487,7 @@ static int slirp_hostfwd(SlirpState *s, const char *redir_str,
goto fail_syntax; goto fail_syntax;
} }
host_port = strtol(buf, &end, 0); 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; goto fail_syntax;
} }
@ -558,11 +558,10 @@ int net_slirp_redir(const char *redir_str)
/* automatic user mode samba server configuration */ /* automatic user mode samba server configuration */
static void slirp_smb_cleanup(SlirpState *s) static void slirp_smb_cleanup(SlirpState *s)
{ {
char cmd[128];
int ret; int ret;
if (s->smb_dir[0] != '\0') { if (s->smb_dir) {
snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir); gchar *cmd = g_strdup_printf("rm -rf %s", s->smb_dir);
ret = system(cmd); ret = system(cmd);
if (ret == -1 || !WIFEXITED(ret)) { if (ret == -1 || !WIFEXITED(ret)) {
error_report("'%s' failed.", cmd); error_report("'%s' failed.", cmd);
@ -570,15 +569,17 @@ static void slirp_smb_cleanup(SlirpState *s)
error_report("'%s' failed. Error code: %d", error_report("'%s' failed. Error code: %d",
cmd, WEXITSTATUS(ret)); 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, static int slirp_smb(SlirpState* s, const char *exported_dir,
struct in_addr vserver_addr) struct in_addr vserver_addr)
{ {
char smb_conf[128]; char *smb_conf;
char smb_cmdline[128]; char *smb_cmdline;
struct passwd *passwd; struct passwd *passwd;
FILE *f; FILE *f;
@ -600,19 +601,19 @@ static int slirp_smb(SlirpState* s, const char *exported_dir,
return -1; return -1;
} }
snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.XXXXXX"); s->smb_dir = g_dir_make_tmp("qemu-smb.XXXXXX", NULL);
if (!mkdtemp(s->smb_dir)) { if (!s->smb_dir) {
error_report("could not create samba server dir '%s'", s->smb_dir); error_report("could not create samba server dir");
s->smb_dir[0] = 0;
return -1; 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"); f = fopen(smb_conf, "w");
if (!f) { if (!f) {
slirp_smb_cleanup(s); slirp_smb_cleanup(s);
error_report("could not create samba server configuration file '%s'", error_report("could not create samba server configuration file '%s'",
smb_conf); smb_conf);
g_free(smb_conf);
return -1; return -1;
} }
fprintf(f, fprintf(f,
@ -651,15 +652,18 @@ static int slirp_smb(SlirpState* s, const char *exported_dir,
); );
fclose(f); 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); 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 || 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_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 445) < 0) {
slirp_smb_cleanup(s); slirp_smb_cleanup(s);
g_free(smb_cmdline);
error_report("conflicting/invalid smbserver address"); error_report("conflicting/invalid smbserver address");
return -1; return -1;
} }
g_free(smb_cmdline);
return 0; return 0;
} }

View File

@ -152,8 +152,9 @@ icmp_input(struct mbuf *m, int hlen)
switch (icp->icmp_type) { switch (icp->icmp_type) {
case ICMP_ECHO: case ICMP_ECHO:
ip->ip_len += hlen; /* since ip_input subtracts this */ ip->ip_len += hlen; /* since ip_input subtracts this */
if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) { if (ip->ip_dst.s_addr == slirp->vhost_addr.s_addr ||
icmp_reflect(m); ip->ip_dst.s_addr == slirp->vnameserver_addr.s_addr) {
icmp_reflect(m);
} else if (slirp->restricted) { } else if (slirp->restricted) {
goto freeit; goto freeit;
} else { } else {

View File

@ -12,8 +12,8 @@
#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc) #define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc)
struct sbuf { struct sbuf {
u_int sb_cc; /* actual chars in buffer */ uint32_t sb_cc; /* actual chars in buffer */
u_int sb_datalen; /* Length of data */ uint32_t sb_datalen; /* Length of data */
char *sb_wptr; /* write pointer. points to where the next char *sb_wptr; /* write pointer. points to where the next
* bytes should be written in the sbuf */ * bytes should be written in the sbuf */
char *sb_rptr; /* read pointer. points to where the next char *sb_rptr; /* read pointer. points to where the next

View File

@ -1133,107 +1133,294 @@ void slirp_socket_recv(Slirp *slirp, struct in_addr guest_addr, int guest_port,
tcp_output(sototcpcb(so)); 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); return 0;
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);
} }
static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf) static const VMStateDescription vmstate_slirp_tcp = {
{ .name = "slirp-tcp",
uint32_t off; .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()
}
};
qemu_put_be32(f, sbuf->sb_cc); /* The sbuf has a pair of pointers that are migrated as offsets;
qemu_put_be32(f, sbuf->sb_datalen); * we calculate the offsets and restore the pointers using
off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data); * pre_save/post_load on a tmp structure.
qemu_put_sbe32(f, off); */
off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data); struct sbuf_tmp {
qemu_put_sbe32(f, off); struct sbuf *parent;
qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen); uint32_t roff, woff;
};
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 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); struct sbuf_tmp *tmp = opaque;
qemu_put_be16(f, so->so_ffamily); uint32_t requested_len = tmp->parent->sb_datalen;
switch (so->so_ffamily) {
case AF_INET: /* Allocate the buffer space used by the field after the tmp */
qemu_put_be32(f, so->so_faddr.s_addr); sbreserve(tmp->parent, tmp->parent->sb_datalen);
qemu_put_be16(f, so->so_fport);
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 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 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; break;
default: default:
error_report("so_ffamily unknown, unable to save so_faddr and" error_report("invalid ss_family type %x", tss->portable_family);
" so_fport"); return -EINVAL;
} }
qemu_put_be16(f, so->so_lfamily);
switch (so->so_lfamily) { return 0;
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);
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) static const VMStateDescription vmstate_slirp_ss_family = {
{ .name = "slirp-socket-addr/ss_family",
int i; .pre_save = ss_family_pre_save,
.post_load = ss_family_post_load,
for (i = 0; i < NB_BOOTP_CLIENTS; i++) { .fields = (VMStateField[]) {
qemu_put_be16(f, slirp->bootp_clients[i].allocated); VMSTATE_UINT16(portable_family, SS_FamilyTmpStruct),
qemu_put_buffer(f, slirp->bootp_clients[i].macaddr, 6); 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) static void slirp_state_save(QEMUFile *f, void *opaque)
{ {
@ -1249,142 +1436,13 @@ static void slirp_state_save(QEMUFile *f, void *opaque)
continue; continue;
qemu_put_byte(f, 42); qemu_put_byte(f, 42);
slirp_socket_save(f, so); vmstate_save_state(f, &vmstate_slirp_socket, so, NULL);
} }
qemu_put_byte(f, 0); qemu_put_byte(f, 0);
qemu_put_be16(f, slirp->ip_id); vmstate_save_state(f, &vmstate_slirp, slirp, NULL);
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;
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)
{
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);
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;
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) static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
{ {
@ -1398,7 +1456,7 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
if (!so) if (!so)
return -ENOMEM; return -ENOMEM;
ret = slirp_socket_load(f, so, version_id); ret = vmstate_load_state(f, &vmstate_slirp_socket, so, version_id);
if (ret < 0) if (ret < 0)
return ret; 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; so->extra = (void *)ex_ptr->ex_exec;
} }
if (version_id >= 2) { return vmstate_load_state(f, &vmstate_slirp, slirp, version_id);
slirp->ip_id = qemu_get_be16(f);
}
if (version_id >= 3) {
slirp_bootp_load(f, slirp);
}
return 0;
} }

View File

@ -15,6 +15,12 @@
* Our socket structure * Our socket structure
*/ */
union slirp_sockaddr {
struct sockaddr_storage ss;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
};
struct socket { struct socket {
struct socket *so_next,*so_prev; /* For a linked list of sockets */ struct socket *so_next,*so_prev; /* For a linked list of sockets */
@ -30,23 +36,15 @@ struct socket {
* PING reply's */ * PING reply's */
struct tcpiphdr *so_ti; /* Pointer to the original ti within struct tcpiphdr *so_ti; /* Pointer to the original ti within
* so_mconn, for non-blocking connections */ * so_mconn, for non-blocking connections */
int so_urgc; uint32_t so_urgc;
union { /* foreign host */ union slirp_sockaddr fhost; /* Foreign host */
struct sockaddr_storage ss;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} fhost;
#define so_faddr fhost.sin.sin_addr #define so_faddr fhost.sin.sin_addr
#define so_fport fhost.sin.sin_port #define so_fport fhost.sin.sin_port
#define so_faddr6 fhost.sin6.sin6_addr #define so_faddr6 fhost.sin6.sin6_addr
#define so_fport6 fhost.sin6.sin6_port #define so_fport6 fhost.sin6.sin6_port
#define so_ffamily fhost.ss.ss_family #define so_ffamily fhost.ss.ss_family
union { /* local host */ union slirp_sockaddr lhost; /* Local host */
struct sockaddr_storage ss;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} lhost;
#define so_laddr lhost.sin.sin_addr #define so_laddr lhost.sin.sin_addr
#define so_lport lhost.sin.sin_port #define so_lport lhost.sin.sin_port
#define so_laddr6 lhost.sin6.sin6_addr #define so_laddr6 lhost.sin6.sin6_addr
@ -56,8 +54,8 @@ struct socket {
uint8_t so_iptos; /* Type of service */ uint8_t so_iptos; /* Type of service */
uint8_t so_emu; /* Is the socket emulated? */ uint8_t so_emu; /* Is the socket emulated? */
u_char so_type; /* Type of socket, UDP or TCP */ uint8_t so_type; /* Type of socket, UDP or TCP */
int so_state; /* internal state flags SS_*, below */ int32_t so_state; /* internal state flags SS_*, below */
struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */ struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */
u_int so_expire; /* When the socket will expire */ u_int so_expire; /* When the socket will expire */

View File

@ -48,7 +48,7 @@ struct tcpcb {
short t_rxtcur; /* current retransmit value */ short t_rxtcur; /* current retransmit value */
short t_dupacks; /* consecutive dup acks recd */ short t_dupacks; /* consecutive dup acks recd */
u_short t_maxseg; /* maximum segment size */ 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; u_short t_flags;
#define TF_ACKNOW 0x0001 /* ack peer immediately */ #define TF_ACKNOW 0x0001 /* ack peer immediately */
#define TF_DELACK 0x0002 /* ack, but try to delay it */ #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 */ uint32_t max_sndwnd; /* largest window peer has offered */
/* out-of-band data */ /* out-of-band data */
char t_oobflags; /* have some */ uint8_t t_oobflags; /* have some */
char t_iobc; /* input character */ uint8_t t_iobc; /* input character */
#define TCPOOB_HAVEDATA 0x01 #define TCPOOB_HAVEDATA 0x01
#define TCPOOB_HADDATA 0x02 #define TCPOOB_HADDATA 0x02
short t_softerror; /* possible error not yet reported */ short t_softerror; /* possible error not yet reported */

View File

@ -70,7 +70,7 @@ static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas,
found: found:
memset(spt, 0, sizeof(*spt)); memset(spt, 0, sizeof(*spt));
spt->client_addr = *srcsas; memcpy(&spt->client_addr, srcsas, sockaddr_size(srcsas));
spt->fd = -1; spt->fd = -1;
spt->block_size = 512; spt->block_size = 512;
spt->client_port = tp->udp.uh_sport; spt->client_port = tp->udp.uh_sport;