#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"
#include <net/if.h>
#endif
+/* Define to 1 if you want KEEPALIVE timers */
+bool slirp_do_keepalive;
+
/* host loopback address */
struct in_addr loopback_addr;
/* host loopback network mask */
u_int curtime;
-static QTAILQ_HEAD(slirp_instances, Slirp) slirp_instances =
+static QTAILQ_HEAD(, Slirp) slirp_instances =
QTAILQ_HEAD_INITIALIZER(slirp_instances);
static struct in_addr dns_addr;
bool in6_enabled,
struct in6_addr vprefix_addr6, uint8_t vprefix_len,
struct in6_addr vhost6, const char *vhostname,
+ const char *tftp_server_name,
const char *tftp_path, const char *bootfile,
struct in_addr vdhcp_start, struct in_addr vnameserver,
struct in6_addr vnameserver6, const char **vdnssearch,
+ const char *vdomainname,
+ const SlirpCb *callbacks,
void *opaque)
{
Slirp *slirp = g_malloc0(sizeof(Slirp));
slirp_init_once();
+ slirp->cb = callbacks;
slirp->grand = g_rand_new();
slirp->restricted = restricted;
}
slirp->tftp_prefix = g_strdup(tftp_path);
slirp->bootp_filename = g_strdup(bootfile);
+ slirp->vdomainname = g_strdup(vdomainname);
slirp->vdhcp_startaddr = vdhcp_start;
slirp->vnameserver_addr = vnameserver;
slirp->vnameserver_addr6 = vnameserver6;
+ slirp->tftp_server_name = g_strdup(tftp_server_name);
if (vdnssearch) {
translate_dnssearch(slirp, vdnssearch);
void slirp_cleanup(Slirp *slirp)
{
+ struct ex_list *e, *next;
+
+ for (e = slirp->exec_list; e; e = next) {
+ next = e->ex_next;
+ g_free(e->ex_exec);
+ g_free(e);
+ }
+
QTAILQ_REMOVE(&slirp_instances, slirp, entry);
unregister_savevm(NULL, "slirp", slirp);
g_free(slirp->vdnssearch);
g_free(slirp->tftp_prefix);
g_free(slirp->bootp_filename);
+ g_free(slirp->vdomainname);
g_free(slirp);
}
/* continue; */
} else {
ret = sowrite(so);
- }
- /*
- * XXXXX If we wrote something (a lot), there
- * could be a need for a window update.
- * In the worst case, the remote will send
- * a window probe to get things going again
- */
- }
-
- /*
- * Probe a still-connecting, non-blocking socket
- * to check if it's still alive
- */
-#ifdef PROBE_CONN
- if (so->so_state & SS_ISFCONNECTING) {
- ret = qemu_recv(so->s, &ret, 0, 0);
-
- if (ret < 0) {
- /* XXX */
- if (errno == EAGAIN || errno == EWOULDBLOCK ||
- errno == EINPROGRESS || errno == ENOTCONN) {
- continue; /* Still connecting, continue */
- }
-
- /* else failed */
- so->so_state &= SS_PERSISTENT_MASK;
- so->so_state |= SS_NOFDREF;
-
- /* tcp_input will take care of it */
- } else {
- ret = send(so->s, &ret, 0, 0);
- if (ret < 0) {
- /* XXX */
- 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;
+ 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);
- } /* SS_ISFCONNECTING */
-#endif
+ }
}
/*
rah->ar_sip = ah->ar_tip;
memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
rah->ar_tip = ah->ar_sip;
- slirp_output(slirp->opaque, arp_reply, sizeof(arp_reply));
+ slirp->cb->output(slirp->opaque, arp_reply, sizeof(arp_reply));
}
break;
case ARPOP_REPLY:
/* target IP */
rah->ar_tip = iph->ip_dst.s_addr;
slirp->client_ipaddr = iph->ip_dst;
- slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
+ slirp->cb->output(slirp->opaque, arp_req, sizeof(arp_req));
ifm->resolution_requested = true;
/* Expire request and drop outgoing packet after 1 second */
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_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
+ slirp->cb->output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
return 1;
}
return 0;
}
-int slirp_add_exec(Slirp *slirp, int do_pty, const void *args,
+int slirp_add_exec(Slirp *slirp, void *chardev, const char *cmdline,
struct in_addr *guest_addr, int guest_port)
{
if (!guest_addr->s_addr) {
guest_addr->s_addr == slirp->vnameserver_addr.s_addr) {
return -1;
}
- return add_exec(&slirp->exec_list, do_pty, (char *)args, *guest_addr,
+
+ return add_exec(&slirp->exec_list, chardev, cmdline, *guest_addr,
htons(guest_port));
}
ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
{
- if (so->s == -1 && so->extra) {
+ if (so->s == -1 && so->chardev) {
/* XXX this blocks entire thread. Rewrite to use
* qemu_chr_fe_write and background I/O callbacks */
- qemu_chr_fe_write_all(so->extra, buf, len);
+ qemu_chr_fe_write_all(so->chardev, buf, len);
return len;
}
+ if (so->s == -1) {
+ /*
+ * This should in theory not happen but it is hard to be
+ * sure because some code paths will end up with so->s == -1
+ * on a failure but don't dispose of the struct socket.
+ * Check specifically, so we don't pass -1 to send().
+ */
+ errno = EBADF;
+ return -1;
+ }
+
return send(so->s, buf, len, flags);
}
uint32_t roff, woff;
};
-static void sbuf_tmp_pre_save(void *opaque)
+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)
#define SS_FAMILY_MIG_IPV6 10 /* Linux */
#define SS_FAMILY_MIG_OTHER 0xffff
-static void ss_family_pre_save(void *opaque)
+static int ss_family_pre_save(void *opaque)
{
SS_FamilyTmpStruct *tss = opaque;
} 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)
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) {
+ if (ex_ptr->ex_chardev) {
struct socket *so;
so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
ntohs(ex_ptr->ex_fport));
int ret;
struct socket *so = socreate(slirp);
- if (!so)
- return -ENOMEM;
-
ret = vmstate_load_state(f, &vmstate_slirp_socket, so, version_id);
if (ret < 0)
return -EINVAL;
}
for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
- if (ex_ptr->ex_pty == 3 &&
+ 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;
-
- so->extra = (void *)ex_ptr->ex_exec;
}
return vmstate_load_state(f, &vmstate_slirp, slirp, version_id);