From 99787f69cdd8147d0be67d71ec3058cce21e2444 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sun, 20 Mar 2016 12:14:18 +0100 Subject: [PATCH 1/5] slirp: Fix memory leak on small incoming ipv4 packet Signed-off-by: Samuel Thibault Reviewed-by: Thomas Huth --- slirp/ip_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slirp/ip_input.c b/slirp/ip_input.c index 12f173de6c..b464f6baf0 100644 --- a/slirp/ip_input.c +++ b/slirp/ip_input.c @@ -85,7 +85,7 @@ ip_input(struct mbuf *m) DEBUG_ARG("m_len = %d", m->m_len); if (m->m_len < sizeof (struct ip)) { - return; + goto bad; } ip = mtod(m, struct ip *); From c17c07231e88549169689ffba811e53921e10025 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sun, 20 Mar 2016 14:52:32 +0100 Subject: [PATCH 2/5] slirp: send icmp6 errors when UDP send failed Signed-off-by: Samuel Thibault Reviewed-by: Thomas Huth --- slirp/udp6.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/slirp/udp6.c b/slirp/udp6.c index 60a91c9532..a23026f2e4 100644 --- a/slirp/udp6.c +++ b/slirp/udp6.c @@ -113,8 +113,7 @@ void udp6_input(struct mbuf *m) m->m_data -= iphlen; *ip = save_ip; DEBUG_MISC((dfd, "udp tx errno = %d-%s\n", errno, strerror(errno))); - /* TODO: ICMPv6 error */ - /*icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));*/ + icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE); goto bad; } From 67e3eee45460129cbc5a90fb9f74eb52594281cd Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Mon, 22 Feb 2016 22:29:21 +0100 Subject: [PATCH 3/5] Avoid embedding struct mbuf in other structures struct mbuf uses a C99 open char array to allow inlining data. Inlining this in another structure is however a GNU extension. The inlines used so far in struct Slirp were actually only needed as head of struct mbuf lists. This replaces these inline with mere struct quehead, and use casts as appropriate. Signed-off-by: Samuel Thibault Reviewed-by: Peter Maydell --- slirp/if.c | 27 ++++++++++++++------------- slirp/mbuf.c | 19 ++++++++++--------- slirp/misc.c | 5 ----- slirp/misc.h | 5 +++++ slirp/slirp.h | 8 +++++--- 5 files changed, 34 insertions(+), 30 deletions(-) diff --git a/slirp/if.c b/slirp/if.c index 2e21f438e8..9b02180db0 100644 --- a/slirp/if.c +++ b/slirp/if.c @@ -28,9 +28,9 @@ ifs_remque(struct mbuf *ifm) void if_init(Slirp *slirp) { - slirp->if_fastq.ifq_next = slirp->if_fastq.ifq_prev = &slirp->if_fastq; - slirp->if_batchq.ifq_next = slirp->if_batchq.ifq_prev = &slirp->if_batchq; - slirp->next_m = &slirp->if_batchq; + slirp->if_fastq.qh_link = slirp->if_fastq.qh_rlink = &slirp->if_fastq; + slirp->if_batchq.qh_link = slirp->if_batchq.qh_rlink = &slirp->if_batchq; + slirp->next_m = (struct mbuf *) &slirp->if_batchq; } /* @@ -74,7 +74,8 @@ if_output(struct socket *so, struct mbuf *ifm) * We mustn't put this packet back on the fastq (or we'll send it out of order) * XXX add cache here? */ - for (ifq = slirp->if_batchq.ifq_prev; ifq != &slirp->if_batchq; + for (ifq = (struct mbuf *) slirp->if_batchq.qh_rlink; + (struct quehead *) ifq != &slirp->if_batchq; ifq = ifq->ifq_prev) { if (so == ifq->ifq_so) { /* A match! */ @@ -86,7 +87,7 @@ if_output(struct socket *so, struct mbuf *ifm) /* No match, check which queue to put it on */ if (so && (so->so_iptos & IPTOS_LOWDELAY)) { - ifq = slirp->if_fastq.ifq_prev; + ifq = (struct mbuf *) slirp->if_fastq.qh_rlink; on_fastq = 1; /* * Check if this packet is a part of the last @@ -98,9 +99,9 @@ if_output(struct socket *so, struct mbuf *ifm) goto diddit; } } else { - ifq = slirp->if_batchq.ifq_prev; + ifq = (struct mbuf *) slirp->if_batchq.qh_rlink; /* Set next_m if the queue was empty so far */ - if (slirp->next_m == &slirp->if_batchq) { + if ((struct quehead *) slirp->next_m == &slirp->if_batchq) { slirp->next_m = ifm; } } @@ -166,10 +167,10 @@ void if_start(Slirp *slirp) } slirp->if_start_busy = true; - if (slirp->if_fastq.ifq_next != &slirp->if_fastq) { - ifm_next = slirp->if_fastq.ifq_next; + if (slirp->if_fastq.qh_link != &slirp->if_fastq) { + ifm_next = (struct mbuf *) slirp->if_fastq.qh_link; next_from_batchq = false; - } else if (slirp->next_m != &slirp->if_batchq) { + } else if ((struct quehead *) slirp->next_m != &slirp->if_batchq) { /* Nothing on fastq, pick up from batchq via next_m */ ifm_next = slirp->next_m; next_from_batchq = true; @@ -182,12 +183,12 @@ void if_start(Slirp *slirp) from_batchq = next_from_batchq; ifm_next = ifm->ifq_next; - if (ifm_next == &slirp->if_fastq) { + if ((struct quehead *) ifm_next == &slirp->if_fastq) { /* No more packets in fastq, switch to batchq */ ifm_next = slirp->next_m; next_from_batchq = true; } - if (ifm_next == &slirp->if_batchq) { + if ((struct quehead *) ifm_next == &slirp->if_batchq) { /* end of batchq */ ifm_next = NULL; } @@ -218,7 +219,7 @@ void if_start(Slirp *slirp) /* Next packet in fastq is from the same session */ ifm_next = next; next_from_batchq = false; - } else if (slirp->next_m == &slirp->if_batchq) { + } else if ((struct quehead *) slirp->next_m == &slirp->if_batchq) { /* Set next_m and ifm_next if the session packet is now the * only one on batchq */ slirp->next_m = ifm_next = next; diff --git a/slirp/mbuf.c b/slirp/mbuf.c index d688dd43f7..d136988397 100644 --- a/slirp/mbuf.c +++ b/slirp/mbuf.c @@ -29,16 +29,16 @@ void m_init(Slirp *slirp) { - slirp->m_freelist.m_next = slirp->m_freelist.m_prev = &slirp->m_freelist; - slirp->m_usedlist.m_next = slirp->m_usedlist.m_prev = &slirp->m_usedlist; + slirp->m_freelist.qh_link = slirp->m_freelist.qh_rlink = &slirp->m_freelist; + slirp->m_usedlist.qh_link = slirp->m_usedlist.qh_rlink = &slirp->m_usedlist; } void m_cleanup(Slirp *slirp) { struct mbuf *m, *next; - m = slirp->m_usedlist.m_next; - while (m != &slirp->m_usedlist) { + m = (struct mbuf *) slirp->m_usedlist.qh_link; + while ((struct quehead *) m != &slirp->m_usedlist) { next = m->m_next; if (m->m_flags & M_EXT) { free(m->m_ext); @@ -46,8 +46,8 @@ void m_cleanup(Slirp *slirp) free(m); m = next; } - m = slirp->m_freelist.m_next; - while (m != &slirp->m_freelist) { + m = (struct mbuf *) slirp->m_freelist.qh_link; + while ((struct quehead *) m != &slirp->m_freelist) { next = m->m_next; free(m); m = next; @@ -70,7 +70,7 @@ m_get(Slirp *slirp) DEBUG_CALL("m_get"); - if (slirp->m_freelist.m_next == &slirp->m_freelist) { + if (slirp->m_freelist.qh_link == &slirp->m_freelist) { m = (struct mbuf *)malloc(SLIRP_MSIZE); if (m == NULL) goto end_error; slirp->mbuf_alloced++; @@ -78,7 +78,7 @@ m_get(Slirp *slirp) flags = M_DOFREE; m->slirp = slirp; } else { - m = slirp->m_freelist.m_next; + m = (struct mbuf *) slirp->m_freelist.qh_link; remque(m); } @@ -225,7 +225,8 @@ dtom(Slirp *slirp, void *dat) DEBUG_ARG("dat = %p", dat); /* bug corrected for M_EXT buffers */ - for (m = slirp->m_usedlist.m_next; m != &slirp->m_usedlist; + for (m = (struct mbuf *) slirp->m_usedlist.qh_link; + (struct quehead *) m != &slirp->m_usedlist; m = m->m_next) { if (m->m_flags & M_EXT) { if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) ) diff --git a/slirp/misc.c b/slirp/misc.c index e2eea2e4b3..2fbd04856a 100644 --- a/slirp/misc.c +++ b/slirp/misc.c @@ -17,11 +17,6 @@ int slirp_debug = DBG_CALL|DBG_MISC|DBG_ERROR; #endif -struct quehead { - struct quehead *qh_link; - struct quehead *qh_rlink; -}; - inline void insque(void *a, void *b) { diff --git a/slirp/misc.h b/slirp/misc.h index 41a32583da..0d0c059e6b 100644 --- a/slirp/misc.h +++ b/slirp/misc.h @@ -45,6 +45,11 @@ struct emu_t { struct emu_t *next; }; +struct slirp_quehead { + struct slirp_quehead *qh_link; + struct slirp_quehead *qh_rlink; +}; + void slirp_insque(void *, void *); void slirp_remque(void *); int add_exec(struct ex_list **, int, char *, struct in_addr, int); diff --git a/slirp/slirp.h b/slirp/slirp.h index 9ad88e7df7..1abbcc6c32 100644 --- a/slirp/slirp.h +++ b/slirp/slirp.h @@ -82,6 +82,7 @@ void free(void *ptr); have different prototypes. */ #define insque slirp_insque #define remque slirp_remque +#define quehead slirp_quehead #ifdef HAVE_SYS_STROPTS_H #include @@ -197,12 +198,13 @@ struct Slirp { struct ex_list *exec_list; /* mbuf states */ - struct mbuf m_freelist, m_usedlist; + struct quehead m_freelist; + struct quehead m_usedlist; int mbuf_alloced; /* if states */ - struct mbuf if_fastq; /* fast queue (for interactive data) */ - struct mbuf if_batchq; /* queue for non-interactive data */ + struct quehead if_fastq; /* fast queue (for interactive data) */ + struct quehead if_batchq; /* queue for non-interactive data */ struct mbuf *next_m; /* pointer to next mbuf to output */ bool if_start_busy; /* avoid if_start recursion */ From 1c3c8e954704cc70a8da2af3d14159b0d2f5c02b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 23 Mar 2016 01:03:09 +0100 Subject: [PATCH 4/5] Use C99 flexible array instead of 1-byte trailing array Signed-off-by: Peter Maydell Signed-off-by: Samuel Thibault --- slirp/mbuf.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/slirp/mbuf.h b/slirp/mbuf.h index 38fedf46de..36fb814097 100644 --- a/slirp/mbuf.h +++ b/slirp/mbuf.h @@ -81,11 +81,9 @@ struct mbuf { Slirp *slirp; bool resolution_requested; uint64_t expiration_date; + char *m_ext; /* start of dynamic buffer area, must be last element */ - union { - char m_dat[1]; /* ANSI don't like 0 sized arrays */ - char *m_ext; - }; + char m_dat[]; }; #define ifq_prev m_prev From d8eb38649587c58d767c3bc6a1075bfeabda9e8a Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Fri, 25 Mar 2016 00:02:58 +0100 Subject: [PATCH 5/5] Rework ipv6 options Rename the recently-added ip6-foo options into ipv6-foo options, to make them coherent with other ipv6 options. Also rework the documentation. Signed-off-by: Samuel Thibault Reviewed-by: Eric Blake --- net/slirp.c | 6 +++--- qapi-schema.json | 25 ++++++++++++++++--------- qemu-options.hx | 18 ++++++++++-------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/net/slirp.c b/net/slirp.c index 95239bceb0..0013c27fe6 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -828,10 +828,10 @@ int net_init_slirp(const NetClientOptions *opts, const char *name, net_init_slirp_configs(user->guestfwd, 0); ret = net_slirp_init(peer, "user", name, user->q_restrict, vnet, - user->host, user->ip6_prefix, user->ip6_prefixlen, - user->ip6_host, user->hostname, user->tftp, + user->host, user->ipv6_prefix, user->ipv6_prefixlen, + user->ipv6_host, user->hostname, user->tftp, user->bootfile, user->dhcpstart, - user->dns, user->ip6_dns, user->smb, + user->dns, user->ipv6_dns, user->smb, user->smbserver, dnssearch); while (slirp_configs) { diff --git a/qapi-schema.json b/qapi-schema.json index 88f9b81c12..e1dd7e19b4 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2427,7 +2427,10 @@ # # @ip: #optional legacy parameter, use net= instead # -# @net: #optional IP address and optional netmask +# @net: #optional IP network address that the guest will see, in the +# form addr[/netmask] The netmask is optional, and can be +# either in the form a.b.c.d or as a number of valid top-most +# bits. Default is 10.0.2.0/24. # # @host: #optional guest-visible address of the host # @@ -2443,13 +2446,17 @@ # @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option # to the guest # -# @ip6-prefix: #optional IPv6 network prefix (default is fec0::) (since 2.6) +# @ipv6-prefix: #optional IPv6 network prefix (default is fec0::) (since +# 2.6). The network prefix is given in the usual +# hexadecimal IPv6 address notation. # -# @ip6-prefixlen: #optional IPv6 network prefix length (default is 64) (since 2.6) +# @ipv6-prefixlen: #optional IPv6 network prefix length (default is 64) +# (since 2.6) # -# @ip6-host: #optional guest-visible IPv6 address of the host (since 2.6) +# @ipv6-host: #optional guest-visible IPv6 address of the host (since 2.6) # -# @ip6-dns: #optional guest-visible IPv6 address of the virtual nameserver (since 2.6) +# @ipv6-dns: #optional guest-visible IPv6 address of the virtual +# nameserver (since 2.6) # # @smb: #optional root directory of the built-in SMB server # @@ -2474,10 +2481,10 @@ '*dhcpstart': 'str', '*dns': 'str', '*dnssearch': ['String'], - '*ip6-prefix': 'str', - '*ip6-prefixlen': 'int', - '*ip6-host': 'str', - '*ip6-dns': 'str', + '*ipv6-prefix': 'str', + '*ipv6-prefixlen': 'int', + '*ipv6-host': 'str', + '*ipv6-dns': 'str', '*smb': 'str', '*smbserver': 'str', '*hostfwd': ['String'], diff --git a/qemu-options.hx b/qemu-options.hx index 732ed8cbc5..5654ce35bb 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1560,9 +1560,9 @@ DEF("smb", HAS_ARG, QEMU_OPTION_smb, "", QEMU_ARCH_ALL) DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, #ifdef CONFIG_SLIRP - "-netdev user,id=str[,net=addr[/mask]][,host=addr][,ip6-net=addr[/int]]\n" - " [,ip6-host=addr][,restrict=on|off][,hostname=host][,dhcpstart=addr]\n" - " [,dns=addr][,ip6-dns=addr][,dnssearch=domain][,tftp=dir]\n" + "-netdev user,id=str[,net=addr[/mask]][,host=addr][,ipv6-net=addr[/int]]\n" + " [,ipv6-host=addr][,restrict=on|off][,hostname=host][,dhcpstart=addr]\n" + " [,dns=addr][,ipv6-dns=addr][,dnssearch=domain][,tftp=dir]\n" " [,bootfile=f][,hostfwd=rule][,guestfwd=rule]" #ifndef _WIN32 "[,smb=dir[,smbserver=addr]]\n" @@ -1719,11 +1719,13 @@ either in the form a.b.c.d or as number of valid top-most bits. Default is Specify the guest-visible address of the host. Default is the 2nd IP in the guest network, i.e. x.x.x.2. -@item ip6-net=@var{addr}[/@var{int}] -Set IPv6 network address the guest will see. Optionally specify the prefix -size, as number of valid top-most bits. Default is fec0::/64. +@item ipv6-net=@var{addr}[/@var{int}] +Set IPv6 network address the guest will see (default is fec0::/64). The +network prefix is given in the usual hexadecimal IPv6 address +notation. The prefix size is optional, and is given as the number of +valid top-most bits (default is 64). -@item ip6-host=@var{addr} +@item ipv6-host=@var{addr} Specify the guest-visible IPv6 address of the host. Default is the 2nd IPv6 in the guest network, i.e. xxxx::2. @@ -1744,7 +1746,7 @@ Specify the guest-visible address of the virtual nameserver. The address must be different from the host address. Default is the 3rd IP in the guest network, i.e. x.x.x.3. -@item ip6-dns=@var{addr} +@item ipv6-dns=@var{addr} Specify the guest-visible address of the IPv6 virtual nameserver. The address must be different from the host address. Default is the 3rd IP in the guest network, i.e. xxxx::3.