diff options
Diffstat (limited to 'slirp/slirp.c')
-rw-r--r-- | slirp/slirp.c | 179 |
1 files changed, 87 insertions, 92 deletions
diff --git a/slirp/slirp.c b/slirp/slirp.c index 322edf51eb..a9674ab090 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -35,6 +35,11 @@ #include <net/if.h> #endif +int slirp_debug; + +/* Define to 1 if you want KEEPALIVE timers */ +bool slirp_do_keepalive; + /* host loopback address */ struct in_addr loopback_addr; /* host loopback network mask */ @@ -47,7 +52,7 @@ static const uint8_t special_ethaddr[ETH_ALEN] = { 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; @@ -161,9 +166,7 @@ static int get_dns_addr_resolv_conf(int af, void *pdns_addr, void *cached_addr, if (!f) return -1; -#ifdef DEBUG - fprintf(stderr, "IP address of your DNS(s): "); -#endif + DEBUG_MISC("IP address of your DNS(s):"); while (fgets(buff, 512, f) != NULL) { if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) { char *c = strchr(buff2, '%'); @@ -186,26 +189,18 @@ static int get_dns_addr_resolv_conf(int af, void *pdns_addr, void *cached_addr, } *cached_time = curtime; } -#ifdef DEBUG - else - fprintf(stderr, ", "); -#endif + if (++found > 3) { -#ifdef DEBUG - fprintf(stderr, "(more)"); -#endif + DEBUG_MISC(" (more)"); break; - } -#ifdef DEBUG - else { + } else if (slirp_debug & DBG_MISC) { char s[INET6_ADDRSTRLEN]; const char *res = inet_ntop(af, tmp_addr, s, sizeof(s)); if (!res) { - res = "(string conversion error)"; + res = " (string conversion error)"; } - fprintf(stderr, "%s", res); + DEBUG_MISC(" %s", res); } -#endif } } fclose(f); @@ -252,6 +247,7 @@ int get_dns6_addr(struct in6_addr *pdns6_addr, uint32_t *scope_id) static void slirp_init_once(void) { static int initialized; + const char *debug; #ifdef _WIN32 WSADATA Data; #endif @@ -268,6 +264,18 @@ static void slirp_init_once(void) loopback_addr.s_addr = htonl(INADDR_LOOPBACK); loopback_mask = htonl(IN_CLASSA_NET); + + debug = g_getenv("SLIRP_DEBUG"); + if (debug) { + const GDebugKey keys[] = { + { "call", DBG_CALL }, + { "misc", DBG_MISC }, + { "error", DBG_ERROR }, + }; + slirp_debug = g_parse_debug_string(debug, keys, G_N_ELEMENTS(keys)); + } + + } static void slirp_state_save(QEMUFile *f, void *opaque); @@ -287,12 +295,15 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork, 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, void *opaque) + 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; @@ -339,6 +350,14 @@ Slirp *slirp_init(int restricted, bool in_enabled, struct in_addr vnetwork, void slirp_cleanup(Slirp *slirp) { + struct gfwd_list *e, *next; + + for (e = slirp->guestfwd_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); @@ -560,15 +579,15 @@ void slirp_pollfds_fill(GArray *pollfds, uint32_t *timeout) void slirp_pollfds_poll(GArray *pollfds, int select_error) { - Slirp *slirp; + Slirp *slirp = QTAILQ_FIRST(&slirp_instances); struct socket *so, *so_next; int ret; - if (QTAILQ_EMPTY(&slirp_instances)) { + if (!slirp) { return; } - curtime = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + curtime = slirp->cb->clock_get_ns() / SCALE_MS; QTAILQ_FOREACH(slirp, &slirp_instances, entry) { /* @@ -688,47 +707,6 @@ void slirp_pollfds_poll(GArray *pollfds, int select_error) } } } - - /* - * 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; - } - - } - tcp_input((struct mbuf *)NULL, sizeof(struct ip), so, - so->so_ffamily); - } /* SS_ISFCONNECTING */ -#endif } /* @@ -787,7 +765,7 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) struct ethhdr *reh = (struct ethhdr *)arp_reply; struct slirp_arphdr *rah = (struct slirp_arphdr *)(arp_reply + ETH_HLEN); int ar_op; - struct ex_list *ex_ptr; + struct gfwd_list *ex_ptr; if (!slirp->in_enabled) { return; @@ -807,7 +785,7 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) if (ah->ar_tip == slirp->vnameserver_addr.s_addr || ah->ar_tip == slirp->vhost_addr.s_addr) goto arp_ok; - for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { + for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { if (ex_ptr->ex_addr.s_addr == ah->ar_tip) goto arp_ok; } @@ -832,7 +810,7 @@ static void arp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len) rah->ar_sip = ah->ar_tip; memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN); rah->ar_tip = ah->ar_sip; - slirp_output(slirp->opaque, arp_reply, sizeof(arp_reply)); + slirp->cb->output(slirp->opaque, arp_reply, sizeof(arp_reply)); } break; case ARPOP_REPLY: @@ -932,11 +910,11 @@ static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh, /* target IP */ rah->ar_tip = iph->ip_dst.s_addr; slirp->client_ipaddr = iph->ip_dst; - slirp_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 */ - ifm->expiration_date = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL; + ifm->expiration_date = slirp->cb->clock_get_ns() + 1000000000ULL; } return 0; } else { @@ -962,8 +940,7 @@ static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh, if (!ifm->resolution_requested) { ndp_send_ns(slirp, ip6h->ip_dst); ifm->resolution_requested = true; - ifm->expiration_date = - qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL; + ifm->expiration_date = slirp->cb->clock_get_ns() + 1000000000ULL; } return 0; } else { @@ -1011,14 +988,14 @@ int if_encap(Slirp *slirp, struct mbuf *ifm) } memcpy(eh->h_dest, ethaddr, ETH_ALEN); - DEBUG_ARGS((dfd, " src = %02x:%02x:%02x:%02x:%02x:%02x\n", - eh->h_source[0], eh->h_source[1], eh->h_source[2], - eh->h_source[3], eh->h_source[4], eh->h_source[5])); - DEBUG_ARGS((dfd, " dst = %02x:%02x:%02x:%02x:%02x:%02x\n", - eh->h_dest[0], eh->h_dest[1], eh->h_dest[2], - eh->h_dest[3], eh->h_dest[4], eh->h_dest[5])); + DEBUG_ARG("src = %02x:%02x:%02x:%02x:%02x:%02x", + eh->h_source[0], eh->h_source[1], eh->h_source[2], + eh->h_source[3], eh->h_source[4], eh->h_source[5]); + DEBUG_ARG("dst = %02x:%02x:%02x:%02x:%02x:%02x", + 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; } @@ -1065,9 +1042,11 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, return 0; } -int slirp_add_exec(Slirp *slirp, int do_pty, const void *args, - struct in_addr *guest_addr, int guest_port) +static bool +check_guestfwd(Slirp *slirp, struct in_addr *guest_addr, int guest_port) { + struct gfwd_list *tmp_ptr; + if (!guest_addr->s_addr) { guest_addr->s_addr = slirp->vnetwork_addr.s_addr | (htonl(0x0204) & ~slirp->vnetwork_mask.s_addr); @@ -1076,18 +1055,36 @@ int slirp_add_exec(Slirp *slirp, int do_pty, const void *args, slirp->vnetwork_addr.s_addr || guest_addr->s_addr == slirp->vhost_addr.s_addr || guest_addr->s_addr == slirp->vnameserver_addr.s_addr) { + return false; + } + + /* check if the port is "bound" */ + for (tmp_ptr = slirp->guestfwd_list; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) { + if (guest_port == tmp_ptr->ex_fport && + guest_addr->s_addr == tmp_ptr->ex_addr.s_addr) + return false; + } + + return true; +} + +int slirp_add_exec(Slirp *slirp, void *chardev, const char *cmdline, + struct in_addr *guest_addr, int guest_port) +{ + if (!check_guestfwd(slirp, guest_addr, guest_port)) { return -1; } - return add_exec(&slirp->exec_list, do_pty, (char *)args, *guest_addr, + + return add_exec(&slirp->guestfwd_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; } @@ -1240,8 +1237,8 @@ static int sbuf_tmp_post_load(void *opaque, int version) } 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); + g_critical("invalid sbuf offsets r/w=%u/%u len=%u", + tmp->roff, tmp->woff, requested_len); return -EINVAL; } @@ -1349,7 +1346,7 @@ static int ss_family_post_load(void *opaque, int version_id) tss->parent->ss.ss_family = AF_INET6; break; default: - error_report("invalid ss_family type %x", tss->portable_family); + g_critical("invalid ss_family type %x", tss->portable_family); return -EINVAL; } @@ -1449,10 +1446,10 @@ static const VMStateDescription vmstate_slirp = { static void slirp_state_save(QEMUFile *f, void *opaque) { Slirp *slirp = opaque; - struct ex_list *ex_ptr; + struct gfwd_list *ex_ptr; - for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) - if (ex_ptr->ex_pty == 3) { + for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) + if (ex_ptr->ex_chardev) { struct socket *so; so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr, ntohs(ex_ptr->ex_fport)); @@ -1471,7 +1468,7 @@ static void slirp_state_save(QEMUFile *f, void *opaque) static int slirp_state_load(QEMUFile *f, void *opaque, int version_id) { Slirp *slirp = opaque; - struct ex_list *ex_ptr; + struct gfwd_list *ex_ptr; while (qemu_get_byte(f)) { int ret; @@ -1486,8 +1483,8 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id) slirp->vnetwork_addr.s_addr) { return -EINVAL; } - for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { - if (ex_ptr->ex_pty == 3 && + for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { + if (ex_ptr->ex_chardev && so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr && so->so_fport == ex_ptr->ex_fport) { break; @@ -1495,8 +1492,6 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id) } if (!ex_ptr) return -EINVAL; - - so->extra = (void *)ex_ptr->ex_exec; } return vmstate_load_state(f, &vmstate_slirp, slirp, version_id); |