qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCHv8 0/9] slirp: Adding IPv6 support to Qemu -net user mode
@ 2016-02-14 17:47 Samuel Thibault
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
                   ` (9 more replies)
  0 siblings, 10 replies; 38+ messages in thread
From: Samuel Thibault @ 2016-02-14 17:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei,
	Jan Kiszka, Samuel Thibault, Guillaume Subiron

Hello,

This is another respin of IPv6 in Qemu -net user mode.


These patches add ICMPv6, NDP, and make UDP and TCP compatible with
IPv6.


Difference with version 7 is:
- Fix overflow detection in strtol call
- Fix formatting and typos
- Use SLIRP_ prefix for header protection
- Use grand instead of srand/rand
- Use standard macros instead of defining intermediate in6_multicast and in6_unspecified
- Pass pointers to in6_equal* instead of structs
- Use qemu_log_mask(LOG_GUEST_ERROR) for guest errors instead of error_report()
- Use bool type
- Avoid floating point operation
- Include qemu/osdep.h in new files.
- Move code to send NA to separate function
- Fix memory leak
- Fix missing save_ip in UDPv6
- Fix zero UDP checksum
- Use unreachable assertion instead of simple breaks when the socket type is not v4 or v6.
- Avoid duplicate ipv4/ipv6 header save.

Here is a summary of the patches:

Guillaume Subiron (7):
  slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  slirp: Adding IPv6 UDP support
  slirp: Factorizing tcpiphdr structure with an union
  slirp: Generalizing and neutralizing various TCP functions before
    adding IPv6 stuff
  slirp: Reindent after refactoring
  slirp: Handle IPv6 in TCP functions
  slirp: Adding IPv6 address for DNS relay

Yann Bordenave (2):
  slirp: Adding ICMPv6 error sending
  qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6
    addresses

 net/net.c           |  31 ++++
 net/slirp.c         |  50 ++++++-
 qapi-schema.json    |  40 +++--
 qemu-options.hx     |  18 ++-
 slirp/Makefile.objs |   6 +-
 slirp/cksum.c       |  25 ++++
 slirp/if.c          |   2 +-
 slirp/if.h          |   4 +-
 slirp/ip6.h         | 138 ++++++++++++++++++
 slirp/ip6_icmp.c    | 411 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 slirp/ip6_icmp.h    | 213 +++++++++++++++++++++++++++
 slirp/ip6_input.c   |  73 ++++++++++
 slirp/ip6_output.c  |  38 +++++
 slirp/ip_icmp.c     |  12 +-
 slirp/ip_icmp.h     |   4 +-
 slirp/ip_input.c    |  10 +-
 slirp/libslirp.h    |   8 +-
 slirp/mbuf.c        |   3 +-
 slirp/ndp_table.c   |  84 +++++++++++
 slirp/slirp.c       |  79 ++++++++--
 slirp/slirp.h       |  43 +++++-
 slirp/socket.c      |  54 ++++++-
 slirp/socket.h      |  13 ++
 slirp/tcp.h         |   2 +
 slirp/tcp_input.c   | 181 ++++++++++++++++-------
 slirp/tcp_output.c  |  51 +++++--
 slirp/tcp_subr.c    | 114 +++++++++++----
 slirp/tcp_timer.c   |   3 +-
 slirp/tcpip.h       |  40 ++++-
 slirp/udp.c         |   3 +-
 slirp/udp.h         |   5 +
 slirp/udp6.c        | 156 ++++++++++++++++++++
 32 files changed, 1754 insertions(+), 160 deletions(-)
 create mode 100644 slirp/ip6.h
 create mode 100644 slirp/ip6_icmp.c
 create mode 100644 slirp/ip6_icmp.h
 create mode 100644 slirp/ip6_input.c
 create mode 100644 slirp/ip6_output.c
 create mode 100644 slirp/ndp_table.c
 create mode 100644 slirp/udp6.c

-- 
2.7.0

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  2016-02-14 17:47 [Qemu-devel] [PATCHv8 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
@ 2016-02-14 17:47 ` Samuel Thibault
  2016-02-16 11:36   ` Thomas Huth
  2016-02-19 13:57   ` Thomas Huth
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 2/9] slirp: Adding ICMPv6 error sending Samuel Thibault
                   ` (8 subsequent siblings)
  9 siblings, 2 replies; 38+ messages in thread
From: Samuel Thibault @ 2016-02-14 17:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei,
	Jan Kiszka, Samuel Thibault, Guillaume Subiron

From: Guillaume Subiron <maethor@subiron.org>

This patch adds the functions needed to handle IPv6 packets. ICMPv6 and
NDP headers are implemented.

Slirp is now able to send NDP Router or Neighbor Advertisement when it
receives Router or Neighbor Solicitation. Using a 64bit-sized IPv6
prefix, the guest is now able to perform stateless autoconfiguration
(SLAAC) and to compute its IPv6 address.

This patch adds an ndp_table, mainly inspired by arp_table, to keep an
NDP cache and manage network address resolution.
Slirp regularly sends NDP Neighbor Advertisement, as recommended by the
RFC, to make the guest refresh its route.

This also adds ip6_cksum() to compute ICMPv6 checksums using IPv6
pseudo-header.

Some #define ETH_* are moved upper in slirp.h to make them accessible to
other slirp/*.h

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
 slirp/Makefile.objs |   6 +-
 slirp/cksum.c       |  25 ++++
 slirp/if.c          |   2 +-
 slirp/ip6.h         | 135 ++++++++++++++++++++
 slirp/ip6_icmp.c    | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 slirp/ip6_icmp.h    | 203 ++++++++++++++++++++++++++++++
 slirp/ip6_input.c   |  69 +++++++++++
 slirp/ip6_output.c  |  38 ++++++
 slirp/ndp_table.c   |  84 +++++++++++++
 slirp/slirp.c       |  49 +++++++-
 slirp/slirp.h       |  37 ++++++
 slirp/socket.h      |   7 ++
 12 files changed, 996 insertions(+), 6 deletions(-)
 create mode 100644 slirp/ip6.h
 create mode 100644 slirp/ip6_icmp.c
 create mode 100644 slirp/ip6_icmp.h
 create mode 100644 slirp/ip6_input.c
 create mode 100644 slirp/ip6_output.c
 create mode 100644 slirp/ndp_table.c

diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs
index 2daa9dc..4e3a289 100644
--- a/slirp/Makefile.objs
+++ b/slirp/Makefile.objs
@@ -1,3 +1,5 @@
-common-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o dnssearch.o
+common-obj-y = cksum.o if.o ip_icmp.o ip6_icmp.o ip6_input.o ip6_output.o \
+               ip_input.o ip_output.o dnssearch.o
 common-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
-common-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o
+common-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o \
+                ndp_table.o
diff --git a/slirp/cksum.c b/slirp/cksum.c
index bc0d017..2ad0e65 100644
--- a/slirp/cksum.c
+++ b/slirp/cksum.c
@@ -138,3 +138,28 @@ cont:
 	REDUCE;
 	return (~sum & 0xffff);
 }
+
+int ip6_cksum(struct mbuf *m)
+{
+    /* TODO: Optimize this by being able to pass the ip6_pseudohdr to cksum
+     * separately from the mbuf */
+    struct ip6 save_ip, *ip = mtod(m, struct ip6 *);
+    struct ip6_pseudohdr *ih = mtod(m, struct ip6_pseudohdr *);
+    int sum;
+
+    save_ip = *ip;
+
+    ih->ih_src = save_ip.ip_src;
+    ih->ih_dst = save_ip.ip_dst;
+    ih->ih_pl = htonl((uint32_t)ntohs(save_ip.ip_pl));
+    ih->ih_zero_hi = 0;
+    ih->ih_zero_lo = 0;
+    ih->ih_nh = save_ip.ip_nh;
+
+    sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr))
+                    + ntohl(ih->ih_pl));
+
+    *ip = save_ip;
+
+    return sum;
+}
diff --git a/slirp/if.c b/slirp/if.c
index 93d7cc0..2e21f43 100644
--- a/slirp/if.c
+++ b/slirp/if.c
@@ -194,7 +194,7 @@ void if_start(Slirp *slirp)
 
         /* Try to send packet unless it already expired */
         if (ifm->expiration_date >= now && !if_encap(slirp, ifm)) {
-            /* Packet is delayed due to pending ARP resolution */
+            /* Packet is delayed due to pending ARP or NDP resolution */
             continue;
         }
 
diff --git a/slirp/ip6.h b/slirp/ip6.h
new file mode 100644
index 0000000..9f7623f
--- /dev/null
+++ b/slirp/ip6.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ */
+
+#ifndef SLIRP_IP6_H_
+#define SLIRP_IP6_H_
+
+#define ALLNODES_MULTICAST  { .s6_addr = \
+                            { 0xff, 0x02, 0x00, 0x00,\
+                            0x00, 0x00, 0x00, 0x00,\
+                            0x00, 0x00, 0x00, 0x00,\
+                            0x00, 0x00, 0x00, 0x01 } }
+
+#define SOLICITED_NODE_PREFIX { .s6_addr = \
+                            { 0xff, 0x02, 0x00, 0x00,\
+                            0x00, 0x00, 0x00, 0x00,\
+                            0x00, 0x00, 0x00, 0x01,\
+                            0xff, 0x00, 0x00, 0x00 } }
+
+#define LINKLOCAL_ADDR  { .s6_addr = \
+                        { 0xfe, 0x80, 0x00, 0x00,\
+                        0x00, 0x00, 0x00, 0x00,\
+                        0x00, 0x00, 0x00, 0x00,\
+                        0x00, 0x00, 0x00, 0x02 } }
+
+static inline bool in6_equal(const struct in6_addr *a, const struct in6_addr *b)
+{
+    return memcmp(a, b, sizeof(*a)) == 0;
+}
+
+static inline bool in6_equal_net(const struct in6_addr *a,
+                                 const struct in6_addr *b,
+                                 int prefix_len)
+{
+    if (memcmp(a, b, prefix_len / 8) != 0) {
+        return 0;
+    }
+
+    if (prefix_len % 8 == 0) {
+        return 1;
+    }
+
+    return a->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8))
+        == b->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8));
+}
+
+static inline bool in6_equal_mach(const struct in6_addr *a,
+                                  const struct in6_addr *b,
+                                  int prefix_len)
+{
+    if (memcmp(&(a->s6_addr[(prefix_len + 7) / 8]),
+               &(b->s6_addr[(prefix_len + 7) / 8]),
+               16 - (prefix_len + 7) / 8) != 0) {
+        return 0;
+    }
+
+    if (prefix_len % 8 == 0) {
+        return 1;
+    }
+
+    return (a->s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 1))
+        == (b->s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 1));
+}
+
+
+#define in6_equal_router(a)\
+    ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len)\
+      && in6_equal_mach(a, &slirp->vhost_addr6, slirp->vprefix_len))\
+  || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)\
+      && in6_equal_mach(a, &slirp->vhost_addr6, 64)))
+
+#define in6_equal_dns(a) 0
+
+#define in6_equal_host(a)\
+    (in6_equal_router(a) || in6_equal_dns(a))
+
+#define in6_solicitednode_multicast(a)\
+    (in6_equal_net(a, &(struct in6_addr)SOLICITED_NODE_PREFIX, 104))
+
+/* Compute emulated host MAC address from its ipv6 address */
+static inline void in6_compute_ethaddr(struct in6_addr ip,
+                                       uint8_t eth[ETH_ALEN])
+{
+    eth[0] = 0x52;
+    eth[1] = 0x56;
+    memcpy(&eth[2], &ip.s6_addr[16 - (ETH_ALEN - 2)], ETH_ALEN - 2);
+}
+
+/*
+ * Definitions for internet protocol version 6.
+ * Per RFC 2460, December 1998.
+ */
+#define IP6VERSION      6
+#define IP6_HOP_LIMIT 255
+
+/*
+ * Structure of an internet header, naked of options.
+ */
+struct ip6 {
+#ifdef HOST_WORDS_BIGENDIAN
+    uint32_t
+        ip_v:4,         /* version */
+        ip_tc_hi:4,     /* traffic class */
+        ip_tc_lo:4,
+        ip_fl_hi:4,     /* flow label */
+        ip_fl_lo:16;
+#else
+    uint32_t
+        ip_tc_hi:4,
+        ip_v:4,
+        ip_fl_hi:4,
+        ip_tc_lo:4,
+        ip_fl_lo:16;
+#endif
+    uint16_t    ip_pl;               /* payload length */
+    uint8_t     ip_nh;               /* next header */
+    uint8_t     ip_hl;               /* hop limit */
+    struct in6_addr ip_src, ip_dst;  /* source and dest address */
+} QEMU_PACKED;
+
+/*
+ * IPv6 pseudo-header used by upper-layer protocols
+ */
+struct ip6_pseudohdr {
+    struct      in6_addr ih_src;  /* source internet address */
+    struct      in6_addr ih_dst;  /* destination internet address */
+    uint32_t    ih_pl;            /* upper-layer packet length */
+    uint16_t    ih_zero_hi;       /* zero */
+    uint8_t     ih_zero_lo;       /* zero */
+    uint8_t     ih_nh;            /* next header */
+} QEMU_PACKED;
+
+
+#endif
diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c
new file mode 100644
index 0000000..029d297
--- /dev/null
+++ b/slirp/ip6_icmp.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ */
+
+#include "qemu/osdep.h"
+#include "slirp.h"
+#include "ip6_icmp.h"
+#include "qemu/timer.h"
+#include "qemu/error-report.h"
+#include "qemu/log.h"
+#include <time.h>
+
+#define NDP_Interval g_rand_int_range(slirp->grand, NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval)
+
+static void ra_timer_handler(void *opaque)
+{
+    Slirp *slirp = opaque;
+    timer_mod(slirp->ra_timer,
+              qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
+    ndp_send_ra(slirp);
+}
+
+void icmp6_init(Slirp *slirp)
+{
+    slirp->ra_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, ra_timer_handler, slirp);
+    timer_mod(slirp->ra_timer,
+              qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
+}
+
+void icmp6_cleanup(Slirp *slirp)
+{
+    timer_del(slirp->ra_timer);
+    timer_free(slirp->ra_timer);
+}
+
+static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
+        struct icmp6 *icmp)
+{
+    struct mbuf *t = m_get(slirp);
+    t->m_len = sizeof(struct ip6) + ntohs(ip->ip_pl);
+    memcpy(t->m_data, m->m_data, t->m_len);
+
+    /* IPv6 Packet */
+    struct ip6 *rip = mtod(t, struct ip6 *);
+    rip->ip_dst = ip->ip_src;
+    rip->ip_src = ip->ip_dst;
+
+    /* ICMPv6 packet */
+    t->m_data += sizeof(struct ip6);
+    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+    ricmp->icmp6_type = ICMP6_ECHO_REPLY;
+    ricmp->icmp6_cksum = 0;
+
+    /* Checksum */
+    t->m_data -= sizeof(struct ip6);
+    ricmp->icmp6_cksum = ip6_cksum(t);
+
+    ip6_output(NULL, t, 0);
+}
+
+/*
+ * Send NDP Router Advertisement
+ */
+void ndp_send_ra(Slirp *slirp)
+{
+    DEBUG_CALL("ndp_send_ra");
+
+    /* Build IPv6 packet */
+    struct mbuf *t = m_get(slirp);
+    struct ip6 *rip = mtod(t, struct ip6 *);
+    rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
+    rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
+    rip->ip_nh = IPPROTO_ICMPV6;
+    rip->ip_pl = htons(ICMP6_NDP_RA_MINLEN
+                        + NDPOPT_LINKLAYER_LEN
+                        + NDPOPT_PREFIXINFO_LEN);
+    t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
+
+    /* Build ICMPv6 packet */
+    t->m_data += sizeof(struct ip6);
+    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+    ricmp->icmp6_type = ICMP6_NDP_RA;
+    ricmp->icmp6_code = 0;
+    ricmp->icmp6_cksum = 0;
+
+    /* NDP */
+    ricmp->icmp6_nra.chl = NDP_AdvCurHopLimit;
+    ricmp->icmp6_nra.M = NDP_AdvManagedFlag;
+    ricmp->icmp6_nra.O = NDP_AdvOtherConfigFlag;
+    ricmp->icmp6_nra.reserved = 0;
+    ricmp->icmp6_nra.lifetime = htons(NDP_AdvDefaultLifetime);
+    ricmp->icmp6_nra.reach_time = htonl(NDP_AdvReachableTime);
+    ricmp->icmp6_nra.retrans_time = htonl(NDP_AdvRetransTime);
+
+    /* Source link-layer address (NDP option) */
+    t->m_data += ICMP6_NDP_RA_MINLEN;
+    struct ndpopt *opt = mtod(t, struct ndpopt *);
+    opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
+    opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
+    in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer);
+
+    /* Prefix information (NDP option) */
+    t->m_data += NDPOPT_LINKLAYER_LEN;
+    struct ndpopt *opt2 = mtod(t, struct ndpopt *);
+    opt2->ndpopt_type = NDPOPT_PREFIX_INFO;
+    opt2->ndpopt_len = NDPOPT_PREFIXINFO_LEN / 8;
+    opt2->ndpopt_prefixinfo.prefix_length = slirp->vprefix_len;
+    opt2->ndpopt_prefixinfo.L = 1;
+    opt2->ndpopt_prefixinfo.A = 1;
+    opt2->ndpopt_prefixinfo.reserved1 = 0;
+    opt2->ndpopt_prefixinfo.valid_lt = htonl(NDP_AdvValidLifetime);
+    opt2->ndpopt_prefixinfo.pref_lt = htonl(NDP_AdvPrefLifetime);
+    opt2->ndpopt_prefixinfo.reserved2 = 0;
+    opt2->ndpopt_prefixinfo.prefix = slirp->vprefix_addr6;
+
+    /* ICMPv6 Checksum */
+    t->m_data -= NDPOPT_LINKLAYER_LEN;
+    t->m_data -= ICMP6_NDP_RA_MINLEN;
+    t->m_data -= sizeof(struct ip6);
+    ricmp->icmp6_cksum = ip6_cksum(t);
+
+    ip6_output(NULL, t, 0);
+}
+
+/*
+ * Send NDP Neighbor Solitication
+ */
+void ndp_send_ns(Slirp *slirp, struct in6_addr addr)
+{
+    char addrstr[INET6_ADDRSTRLEN];
+    inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN);
+    DEBUG_CALL("ndp_send_ns");
+    DEBUG_ARG("target = %s", addrstr);
+
+    /* Build IPv6 packet */
+    struct mbuf *t = m_get(slirp);
+    struct ip6 *rip = mtod(t, struct ip6 *);
+    rip->ip_src = slirp->vhost_addr6;
+    rip->ip_dst = (struct in6_addr)SOLICITED_NODE_PREFIX;
+    memcpy(&rip->ip_dst.s6_addr[13], &addr.s6_addr[13], 3);
+    rip->ip_nh = IPPROTO_ICMPV6;
+    rip->ip_pl = htons(ICMP6_NDP_NS_MINLEN + NDPOPT_LINKLAYER_LEN);
+    t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
+
+    /* Build ICMPv6 packet */
+    t->m_data += sizeof(struct ip6);
+    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+    ricmp->icmp6_type = ICMP6_NDP_NS;
+    ricmp->icmp6_code = 0;
+    ricmp->icmp6_cksum = 0;
+
+    /* NDP */
+    ricmp->icmp6_nns.reserved = 0;
+    ricmp->icmp6_nns.target = addr;
+
+    /* Build NDP option */
+    t->m_data += ICMP6_NDP_NS_MINLEN;
+    struct ndpopt *opt = mtod(t, struct ndpopt *);
+    opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
+    opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
+    in6_compute_ethaddr(slirp->vhost_addr6, opt->ndpopt_linklayer);
+
+    /* ICMPv6 Checksum */
+    t->m_data -= ICMP6_NDP_NA_MINLEN;
+    t->m_data -= sizeof(struct ip6);
+    ricmp->icmp6_cksum = ip6_cksum(t);
+
+    ip6_output(NULL, t, 1);
+}
+
+/*
+ * Send NDP Neighbor Advertisement
+ */
+static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp)
+{
+    /* Build IPv6 packet */
+    struct mbuf *t = m_get(slirp);
+    struct ip6 *rip = mtod(t, struct ip6 *);
+    rip->ip_src = icmp->icmp6_nns.target;
+    if (IN6_IS_ADDR_UNSPECIFIED(&ip->ip_src)) {
+        rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
+    } else {
+        rip->ip_dst = ip->ip_src;
+    }
+    rip->ip_nh = IPPROTO_ICMPV6;
+    rip->ip_pl = htons(ICMP6_NDP_NA_MINLEN
+                        + NDPOPT_LINKLAYER_LEN);
+    t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
+
+    /* Build ICMPv6 packet */
+    t->m_data += sizeof(struct ip6);
+    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+    ricmp->icmp6_type = ICMP6_NDP_NA;
+    ricmp->icmp6_code = 0;
+    ricmp->icmp6_cksum = 0;
+
+    /* NDP */
+    ricmp->icmp6_nna.R = NDP_IsRouter;
+    ricmp->icmp6_nna.S = !IN6_IS_ADDR_MULTICAST(&rip->ip_dst);
+    ricmp->icmp6_nna.O = 1;
+    ricmp->icmp6_nna.reserved_hi = 0;
+    ricmp->icmp6_nna.reserved_lo = 0;
+    ricmp->icmp6_nna.target = icmp->icmp6_nns.target;
+
+    /* Build NDP option */
+    t->m_data += ICMP6_NDP_NA_MINLEN;
+    struct ndpopt *opt = mtod(t, struct ndpopt *);
+    opt->ndpopt_type = NDPOPT_LINKLAYER_TARGET;
+    opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
+    in6_compute_ethaddr(ricmp->icmp6_nna.target,
+                    opt->ndpopt_linklayer);
+
+    /* ICMPv6 Checksum */
+    t->m_data -= ICMP6_NDP_NA_MINLEN;
+    t->m_data -= sizeof(struct ip6);
+    ricmp->icmp6_cksum = ip6_cksum(t);
+
+    ip6_output(NULL, t, 0);
+}
+
+/*
+ * Process a NDP message
+ */
+static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
+        struct icmp6 *icmp)
+{
+    m->m_len += ETH_HLEN;
+    m->m_data -= ETH_HLEN;
+    struct ethhdr *eth = mtod(m, struct ethhdr *);
+    m->m_len -= ETH_HLEN;
+    m->m_data += ETH_HLEN;
+
+    switch (icmp->icmp6_type) {
+    case ICMP6_NDP_RS:
+        DEBUG_CALL(" type = Router Solicitation");
+        if (ip->ip_hl == 255
+                && icmp->icmp6_code == 0
+                && ntohs(ip->ip_pl) >= ICMP6_NDP_RS_MINLEN) {
+            /* Gratuitous NDP */
+            ndp_table_add(slirp, ip->ip_src, eth->h_source);
+
+            ndp_send_ra(slirp);
+        }
+        break;
+
+    case ICMP6_NDP_RA:
+        DEBUG_CALL(" type = Router Advertisement");
+        qemu_log_mask(LOG_GUEST_ERROR,
+                "Warning: guest sent NDP RA, but shouldn't");
+        break;
+
+    case ICMP6_NDP_NS:
+        DEBUG_CALL(" type = Neighbor Solicitation");
+        if (ip->ip_hl == 255
+                && icmp->icmp6_code == 0
+                && !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nns.target)
+                && ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN
+                && (!IN6_IS_ADDR_UNSPECIFIED(&ip->ip_src)
+                    || in6_solicitednode_multicast(&ip->ip_dst))) {
+            if (in6_equal_host(&icmp->icmp6_nns.target)) {
+                /* Gratuitous NDP */
+                ndp_table_add(slirp, ip->ip_src, eth->h_source);
+                ndp_send_na(slirp, ip, icmp);
+            }
+        }
+        break;
+
+    case ICMP6_NDP_NA:
+        DEBUG_CALL(" type = Neighbor Advertisement");
+        if (ip->ip_hl == 255
+                && icmp->icmp6_code == 0
+                && ntohs(ip->ip_pl) >= ICMP6_NDP_NA_MINLEN
+                && !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nna.target)
+                && (!IN6_IS_ADDR_MULTICAST(&ip->ip_dst)
+                    || icmp->icmp6_nna.S == 0)) {
+            ndp_table_add(slirp, ip->ip_src, eth->h_source);
+        }
+        break;
+
+    case ICMP6_NDP_REDIRECT:
+        DEBUG_CALL(" type = Redirect");
+        qemu_log_mask(LOG_GUEST_ERROR,
+                "Warning: guest sent NDP REDIRECT, but shouldn't");
+        break;
+    }
+}
+
+/*
+ * Process a received ICMPv6 message.
+ */
+void icmp6_input(struct mbuf *m)
+{
+    struct icmp6 *icmp;
+    struct ip6 *ip = mtod(m, struct ip6 *);
+    Slirp *slirp = m->slirp;
+    int hlen = sizeof(struct ip6);
+
+    DEBUG_CALL("icmp6_input");
+    DEBUG_ARG("m = %lx", (long) m);
+    DEBUG_ARG("m_len = %d", m->m_len);
+
+    if (ntohs(ip->ip_pl) < ICMP6_MINLEN) {
+        goto end;
+    }
+
+    if (ip6_cksum(m)) {
+        goto end;
+    }
+
+    m->m_len -= hlen;
+    m->m_data += hlen;
+    icmp = mtod(m, struct icmp6 *);
+    m->m_len += hlen;
+    m->m_data -= hlen;
+
+    DEBUG_ARG("icmp6_type = %d", icmp->icmp6_type);
+    switch (icmp->icmp6_type) {
+    case ICMP6_ECHO_REQUEST:
+        if (in6_equal_host(&ip->ip_dst)) {
+            icmp6_send_echoreply(m, slirp, ip, icmp);
+        } else {
+            /* TODO */
+            error_report("external icmpv6 not supported yet");
+        }
+        break;
+
+    case ICMP6_NDP_RS:
+    case ICMP6_NDP_RA:
+    case ICMP6_NDP_NS:
+    case ICMP6_NDP_NA:
+    case ICMP6_NDP_REDIRECT:
+        ndp_input(m, slirp, ip, icmp);
+        break;
+
+    case ICMP6_UNREACH:
+    case ICMP6_TOOBIG:
+    case ICMP6_TIMXCEED:
+    case ICMP6_PARAMPROB:
+        /* XXX? report error? close socket? */
+    default:
+        break;
+    }
+
+end:
+    m_free(m);
+}
diff --git a/slirp/ip6_icmp.h b/slirp/ip6_icmp.h
new file mode 100644
index 0000000..b2c40d6
--- /dev/null
+++ b/slirp/ip6_icmp.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ */
+
+#ifndef SLIRP_NETINET_ICMP6_H_
+#define SLIRP_NETINET_ICMP6_H_
+
+/*
+ * Interface Control Message Protocol version 6 Definitions.
+ * Per RFC 4443, March 2006.
+ *
+ * Network Discover Protocol Definitions.
+ * Per RFC 4861, September 2007.
+ */
+
+struct icmp6_echo { /* Echo Messages */
+    uint16_t id;
+    uint16_t seq_num;
+};
+
+/*
+ * NDP Messages
+ */
+struct ndp_rs {     /* Router Solicitation Message */
+    uint32_t reserved;
+};
+
+struct ndp_ra {     /* Router Advertisement Message */
+    uint8_t chl;    /* Cur Hop Limit */
+#ifdef HOST_WORDS_BIGENDIAN
+    uint8_t
+        M:1,
+        O:1,
+        reserved:6;
+#else
+    uint8_t
+        reserved:6,
+        O:1,
+        M:1;
+#endif
+    uint16_t lifetime;      /* Router Lifetime */
+    uint32_t reach_time;    /* Reachable Time */
+    uint32_t retrans_time;  /* Retrans Timer */
+} QEMU_PACKED;
+
+struct ndp_ns {     /* Neighbor Solicitation Message */
+    uint32_t reserved;
+    struct in6_addr target; /* Target Address */
+} QEMU_PACKED;
+
+struct ndp_na {     /* Neighbor Advertisement Message */
+#ifdef HOST_WORDS_BIGENDIAN
+    uint32_t
+        R:1,                /* Router Flag */
+        S:1,                /* Solicited Flag */
+        O:1,                /* Override Flag */
+        reserved_hi:5,
+        reserved_lo:24;
+#else
+    uint32_t
+        reserved_hi:5,
+        O:1,
+        S:1,
+        R:1,
+        reserved_lo:24;
+#endif
+    struct in6_addr target; /* Target Address */
+} QEMU_PACKED;
+
+struct ndp_redirect {
+    uint32_t reserved;
+    struct in6_addr target; /* Target Address */
+    struct in6_addr dest;   /* Destination Address */
+} QEMU_PACKED;
+
+/*
+ * Structure of an icmpv6 header.
+ */
+struct icmp6 {
+    uint8_t     icmp6_type;         /* type of message, see below */
+    uint8_t     icmp6_code;         /* type sub code */
+    uint16_t    icmp6_cksum;        /* ones complement cksum of struct */
+    union {
+        struct icmp6_echo echo;
+        struct ndp_rs ndp_rs;
+        struct ndp_ra ndp_ra;
+        struct ndp_ns ndp_ns;
+        struct ndp_na ndp_na;
+        struct ndp_redirect ndp_redirect;
+    } icmp6_body;
+#define icmp6_echo icmp6_body.echo
+#define icmp6_nrs icmp6_body.ndp_rs
+#define icmp6_nra icmp6_body.ndp_ra
+#define icmp6_nns icmp6_body.ndp_ns
+#define icmp6_nna icmp6_body.ndp_na
+#define icmp6_redirect icmp6_body.ndp_redirect
+} QEMU_PACKED;
+
+#define ICMP6_MINLEN    4
+#define ICMP6_ECHO_MINLEN   8
+#define ICMP6_NDP_RS_MINLEN 8
+#define ICMP6_NDP_RA_MINLEN 16
+#define ICMP6_NDP_NS_MINLEN 24
+#define ICMP6_NDP_NA_MINLEN 24
+#define ICMP6_NDP_REDIRECT_MINLEN 40
+
+/*
+ * NDP Options
+ */
+struct ndpopt {
+    uint8_t     ndpopt_type;                    /* Option type */
+    uint8_t     ndpopt_len;                     /* /!\ In units of 8 octets */
+    union {
+        unsigned char   linklayer_addr[6];      /* Source/Target Link-layer */
+        struct prefixinfo {                     /* Prefix Information */
+            uint8_t     prefix_length;
+#ifdef HOST_WORDS_BIGENDIAN
+            uint8_t     L:1, A:1, reserved1:6;
+#else
+            uint8_t     reserved1:6, A:1, L:1;
+#endif
+            uint32_t    valid_lt;               /* Valid Lifetime */
+            uint32_t    pref_lt;                /* Preferred Lifetime */
+            uint32_t    reserved2;
+            struct in6_addr prefix;
+        } QEMU_PACKED prefixinfo;
+    } ndpopt_body;
+#define ndpopt_linklayer ndpopt_body.linklayer_addr
+#define ndpopt_prefixinfo ndpopt_body.prefixinfo
+} QEMU_PACKED;
+
+/* NDP options type */
+#define NDPOPT_LINKLAYER_SOURCE     1   /* Source Link-Layer Address */
+#define NDPOPT_LINKLAYER_TARGET     2   /* Target Link-Layer Address */
+#define NDPOPT_PREFIX_INFO          3   /* Prefix Information */
+
+/* NDP options size, in octets. */
+#define NDPOPT_LINKLAYER_LEN    8
+#define NDPOPT_PREFIXINFO_LEN   32
+
+/*
+ * Definition of type and code field values.
+ * Per https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml
+ * Last Updated 2012-11-12
+ */
+
+/* Errors */
+#define ICMP6_UNREACH   1   /* Destination Unreachable */
+#define     ICMP6_UNREACH_NO_ROUTE      0   /* no route to dest */
+#define     ICMP6_UNREACH_DEST_PROHIB   1   /* com with dest prohibited */
+#define     ICMP6_UNREACH_SCOPE         2   /* beyond scope of src addr */
+#define     ICMP6_UNREACH_ADDRESS       3   /* address unreachable */
+#define     ICMP6_UNREACH_PORT          4   /* port unreachable */
+#define     ICMP6_UNREACH_SRC_FAIL      5   /* src addr failed */
+#define     ICMP6_UNREACH_REJECT_ROUTE  6   /* reject route to dest */
+#define     ICMP6_UNREACH_SRC_HDR_ERROR 7   /* error in src routing header */
+#define ICMP6_TOOBIG    2   /* Packet Too Big */
+#define ICMP6_TIMXCEED  3   /* Time Exceeded */
+#define     ICMP6_TIMXCEED_INTRANS      0   /* hop limit exceeded in transit */
+#define     ICMP6_TIMXCEED_REASS        1   /* ttl=0 in reass */
+#define ICMP6_PARAMPROB 4   /* Parameter Problem */
+#define     ICMP6_PARAMPROB_HDR_FIELD   0   /* err header field */
+#define     ICMP6_PARAMPROB_NXTHDR_TYPE 1   /* unrecognized Next Header type */
+#define     ICMP6_PARAMPROB_IPV6_OPT    2   /* unrecognized IPv6 option */
+
+/* Informational Messages */
+#define ICMP6_ECHO_REQUEST      128 /* Echo Request */
+#define ICMP6_ECHO_REPLY        129 /* Echo Reply */
+#define ICMP6_NDP_RS            133 /* Router Solicitation (NDP) */
+#define ICMP6_NDP_RA            134 /* Router Advertisement (NDP) */
+#define ICMP6_NDP_NS            135 /* Neighbor Solicitation (NDP) */
+#define ICMP6_NDP_NA            136 /* Neighbor Advertisement (NDP) */
+#define ICMP6_NDP_REDIRECT      137 /* Redirect Message (NDP) */
+
+/*
+ * Router Configuration Variables (rfc4861#section-6)
+ */
+#define NDP_IsRouter                1
+#define NDP_AdvSendAdvertisements   1
+#define NDP_MaxRtrAdvInterval       600000
+#define NDP_MinRtrAdvInterval       ((NDP_MaxRtrAdvInterval >= 9) ? \
+                                        NDP_MaxRtrAdvInterval / 3 : \
+                                        NDP_MaxRtrAdvInterval)
+#define NDP_AdvManagedFlag          0
+#define NDP_AdvOtherConfigFlag      0
+#define NDP_AdvLinkMTU              0
+#define NDP_AdvReachableTime        0
+#define NDP_AdvRetransTime          0
+#define NDP_AdvCurHopLimit          64
+#define NDP_AdvDefaultLifetime      ((3 * NDP_MaxRtrAdvInterval) / 1000)
+#define NDP_AdvValidLifetime        86400
+#define NDP_AdvOnLinkFlag           1
+#define NDP_AdvPrefLifetime         14400
+#define NDP_AdvAutonomousFlag       1
+
+void icmp6_init(Slirp *slirp);
+void icmp6_cleanup(Slirp *slirp);
+void icmp6_input(struct mbuf *);
+void ndp_send_ra(Slirp *slirp);
+void ndp_send_ns(Slirp *slirp, struct in6_addr addr);
+
+#endif
diff --git a/slirp/ip6_input.c b/slirp/ip6_input.c
new file mode 100644
index 0000000..df249f1
--- /dev/null
+++ b/slirp/ip6_input.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ */
+
+#include "qemu/osdep.h"
+#include "slirp.h"
+#include "ip6_icmp.h"
+
+/*
+ * IP initialization: fill in IP protocol switch table.
+ * All protocols not implemented in kernel go to raw IP protocol handler.
+ */
+void ip6_init(Slirp *slirp)
+{
+    icmp6_init(slirp);
+}
+
+void ip6_cleanup(Slirp *slirp)
+{
+    icmp6_cleanup(slirp);
+}
+
+void ip6_input(struct mbuf *m)
+{
+    struct ip6 *ip6;
+
+    DEBUG_CALL("ip6_input");
+    DEBUG_ARG("m = %lx", (long)m);
+    DEBUG_ARG("m_len = %d", m->m_len);
+
+    if (m->m_len < sizeof(struct ip6)) {
+        goto bad;
+    }
+
+    ip6 = mtod(m, struct ip6 *);
+
+    if (ip6->ip_v != IP6VERSION) {
+        goto bad;
+    }
+
+    /* check ip_ttl for a correct ICMP reply */
+    if (ip6->ip_hl == 0) {
+        /*icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");*/
+        goto bad;
+    }
+
+    /*
+     * Switch out to protocol's input routine.
+     */
+    switch (ip6->ip_nh) {
+#if 0
+    case IPPROTO_TCP:
+        tcp_input(m, hlen, (struct socket *)NULL);
+        break;
+    case IPPROTO_UDP:
+        udp_input(m, hlen);
+        break;
+#endif
+    case IPPROTO_ICMPV6:
+        icmp6_input(m);
+        break;
+    default:
+        m_free(m);
+    }
+    return;
+bad:
+    m_free(m);
+}
diff --git a/slirp/ip6_output.c b/slirp/ip6_output.c
new file mode 100644
index 0000000..2dd80f4
--- /dev/null
+++ b/slirp/ip6_output.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ */
+
+#include "slirp.h"
+
+/* Number of packets queued before we start sending
+ * (to prevent allocing too many mbufs) */
+#define IF6_THRESH 10
+
+/*
+ * IPv6 output. The packet in mbuf chain m contains a IP header
+ */
+int ip6_output(struct socket *so, struct mbuf *m, int fast)
+{
+    struct ip6 *ip = mtod(m, struct ip6 *);
+
+    DEBUG_CALL("ip6_output");
+    DEBUG_ARG("so = %lx", (long)so);
+    DEBUG_ARG("m = %lx", (long)m);
+
+    /* Fill IPv6 header */
+    ip->ip_v = IP6VERSION;
+    ip->ip_hl = IP6_HOP_LIMIT;
+    ip->ip_tc_hi = 0;
+    ip->ip_tc_lo = 0;
+    ip->ip_fl_hi = 0;
+    ip->ip_fl_lo = 0;
+
+    if (fast) {
+        if_encap(m->slirp, m);
+    } else {
+        if_output(so, m);
+    }
+
+    return 0;
+}
diff --git a/slirp/ndp_table.c b/slirp/ndp_table.c
new file mode 100644
index 0000000..a715ddd
--- /dev/null
+++ b/slirp/ndp_table.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ */
+
+#include "slirp.h"
+
+void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
+                    uint8_t ethaddr[ETH_ALEN])
+{
+    NdpTable *ndp_table = &slirp->ndp_table;
+    int i;
+    char addrstr[INET6_ADDRSTRLEN];
+
+    DEBUG_CALL("ndp_table_add");
+    inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
+    DEBUG_ARG("ip = %s", addrstr);
+    DEBUG_ARGS((dfd, " hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                ethaddr[0], ethaddr[1], ethaddr[2],
+                ethaddr[3], ethaddr[4], ethaddr[5]));
+
+    if (IN6_IS_ADDR_MULTICAST(&ip_addr) || IN6_IS_ADDR_UNSPECIFIED(&ip_addr)) {
+        /* Do not register multicast or unspecified addresses */
+        DEBUG_CALL(" abort: do not register multicast or unspecified address");
+        return;
+    }
+
+    /* Search for an entry */
+    for (i = 0; i < NDP_TABLE_SIZE; i++) {
+        if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) {
+            DEBUG_CALL(" already in table: update the entry");
+            /* Update the entry */
+            memcpy(ndp_table->table[i].eth_addr, ethaddr, ETH_ALEN);
+            return;
+        }
+    }
+
+    /* No entry found, create a new one */
+    DEBUG_CALL(" create new entry");
+    ndp_table->table[ndp_table->next_victim].ip_addr = ip_addr;
+    memcpy(ndp_table->table[ndp_table->next_victim].eth_addr,
+            ethaddr, ETH_ALEN);
+    ndp_table->next_victim = (ndp_table->next_victim + 1) % NDP_TABLE_SIZE;
+}
+
+bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
+                      uint8_t out_ethaddr[ETH_ALEN])
+{
+    NdpTable *ndp_table = &slirp->ndp_table;
+    int i;
+    char addrstr[INET6_ADDRSTRLEN];
+
+    DEBUG_CALL("ndp_table_search");
+    inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
+    DEBUG_ARG("ip = %s", addrstr);
+
+    assert(!IN6_IS_ADDR_UNSPECIFIED(&ip_addr));
+
+    /* Multicast address: fec0::abcd:efgh/8 -> 33:33:ab:cd:ef:gh */
+    if (IN6_IS_ADDR_MULTICAST(&ip_addr)) {
+        out_ethaddr[0] = 0x33; out_ethaddr[1] = 0x33;
+        out_ethaddr[2] = ip_addr.s6_addr[12];
+        out_ethaddr[3] = ip_addr.s6_addr[13];
+        out_ethaddr[4] = ip_addr.s6_addr[14];
+        out_ethaddr[5] = ip_addr.s6_addr[15];
+        DEBUG_ARGS((dfd, " multicast addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                    out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+                    out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]));
+        return 1;
+    }
+
+    for (i = 0; i < NDP_TABLE_SIZE; i++) {
+        if (in6_equal(&ndp_table->table[i].ip_addr, &ip_addr)) {
+            memcpy(out_ethaddr, ndp_table->table[i].eth_addr,  ETH_ALEN);
+            DEBUG_ARGS((dfd, " found hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                        out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+                        out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]));
+            return 1;
+        }
+    }
+
+    DEBUG_CALL(" ip not found in table");
+    return 0;
+}
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 0466d33..5f42ada 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -210,10 +210,12 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
 
     slirp_init_once();
 
+    slirp->grand = g_rand_new();
     slirp->restricted = restricted;
 
     if_init(slirp);
     ip_init(slirp);
+    ip6_init(slirp);
 
     /* Initialise mbufs *after* setting the MTU */
     m_init(slirp);
@@ -221,6 +223,9 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
     slirp->vnetwork_addr = vnetwork;
     slirp->vnetwork_mask = vnetmask;
     slirp->vhost_addr = vhost;
+    inet_pton(AF_INET6, "fec0::0", &slirp->vprefix_addr6);
+    slirp->vprefix_len = 64;
+    inet_pton(AF_INET6, "fec0::2", &slirp->vhost_addr6);
     if (vhostname) {
         pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
                 vhostname);
@@ -251,6 +256,7 @@ void slirp_cleanup(Slirp *slirp)
     unregister_savevm(NULL, "slirp", slirp);
 
     ip_cleanup(slirp);
+    ip6_cleanup(slirp);
     m_cleanup(slirp);
 
     g_free(slirp->vdnssearch);
@@ -744,6 +750,7 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
         arp_input(slirp, pkt, pkt_len);
         break;
     case ETH_P_IP:
+    case ETH_P_IPV6:
         m = m_get(slirp);
         if (!m)
             return;
@@ -757,8 +764,13 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
         m->m_data += 2 + ETH_HLEN;
         m->m_len -= 2 + ETH_HLEN;
 
-        ip_input(m);
+        if (proto == ETH_P_IP) {
+            ip_input(m);
+        } else if (proto == ETH_P_IPV6) {
+            ip6_input(m);
+        }
         break;
+
     default:
         break;
     }
@@ -826,6 +838,31 @@ static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
     }
 }
 
+/* Prepare the IPv6 packet to be sent to the ethernet device. Returns 1 if no
+ * packet should be sent, 0 if the packet must be re-queued, 2 if the packet
+ * is ready to go.
+ */
+static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
+        uint8_t ethaddr[ETH_ALEN])
+{
+    const struct ip6 *ip6h = mtod(ifm, const struct ip6 *);
+    if (!ndp_table_search(slirp, ip6h->ip_dst, ethaddr)) {
+        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;
+        }
+        return 0;
+    } else {
+        eh->h_proto = htons(ETH_P_IPV6);
+        in6_compute_ethaddr(ip6h->ip_src, eh->h_source);
+
+        /* Send this */
+        return 2;
+    }
+}
+
 /* Output the IP packet to the ethernet device. Returns 0 if the packet must be
  * re-queued.
  */
@@ -849,9 +886,15 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
         }
         break;
 
+    case IP6VERSION:
+        ret = if_encap6(slirp, ifm, eh, ethaddr);
+        if (ret < 2) {
+            return ret;
+        }
+        break;
+
     default:
-        /* Do not assert while we don't manage IP6VERSION */
-        /* assert(0); */
+        g_assert_not_reached();
         break;
     }
 
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 239fe29..15775bc 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -131,6 +131,8 @@ void free(void *ptr);
 #include <sys/stropts.h>
 #endif
 
+#include <glib.h>
+
 #include "debug.h"
 
 #include "qemu/queue.h"
@@ -139,12 +141,14 @@ void free(void *ptr);
 
 #include "libslirp.h"
 #include "ip.h"
+#include "ip6.h"
 #include "tcp.h"
 #include "tcp_timer.h"
 #include "tcp_var.h"
 #include "tcpip.h"
 #include "udp.h"
 #include "ip_icmp.h"
+#include "ip6_icmp.h"
 #include "mbuf.h"
 #include "sbuf.h"
 #include "socket.h"
@@ -196,6 +200,23 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN]);
 bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
                       uint8_t out_ethaddr[ETH_ALEN]);
 
+struct ndpentry {
+    unsigned char   eth_addr[ETH_ALEN];     /* sender hardware address */
+    struct in6_addr ip_addr;                /* sender IP address       */
+} QEMU_PACKED;
+
+#define NDP_TABLE_SIZE 16
+
+typedef struct NdpTable {
+    struct ndpentry table[NDP_TABLE_SIZE];
+    int next_victim;
+} NdpTable;
+
+void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
+                   uint8_t ethaddr[ETH_ALEN]);
+bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
+                      uint8_t out_ethaddr[ETH_ALEN]);
+
 struct Slirp {
     QTAILQ_ENTRY(Slirp) entry;
     u_int time_fasttimo;
@@ -206,6 +227,9 @@ struct Slirp {
     struct in_addr vnetwork_addr;
     struct in_addr vnetwork_mask;
     struct in_addr vhost_addr;
+    struct in6_addr vprefix_addr6;
+    uint8_t vprefix_len;
+    struct in6_addr vhost_addr6;
     struct in_addr vdhcp_startaddr;
     struct in_addr vnameserver_addr;
 
@@ -254,6 +278,10 @@ struct Slirp {
     struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
 
     ArpTable arp_table;
+    NdpTable ndp_table;
+
+    GRand *grand;
+    QEMUTimer *ra_timer;
 
     void *opaque;
 };
@@ -296,6 +324,7 @@ int translate_dnssearch(Slirp *s, const char ** names);
 
 /* cksum.c */
 int cksum(struct mbuf *m, int len);
+int ip6_cksum(struct mbuf *m);
 
 /* if.c */
 void if_init(Slirp *);
@@ -311,6 +340,14 @@ void ip_stripoptions(register struct mbuf *, struct mbuf *);
 /* ip_output.c */
 int ip_output(struct socket *, struct mbuf *);
 
+/* ip6_input.c */
+void ip6_init(Slirp *);
+void ip6_cleanup(Slirp *);
+void ip6_input(struct mbuf *);
+
+/* ip6_output */
+int ip6_output(struct socket *, struct mbuf *, int fast);
+
 /* tcp_input.c */
 void tcp_input(register struct mbuf *, int, struct socket *);
 int tcp_mss(register struct tcpcb *, u_int);
diff --git a/slirp/socket.h b/slirp/socket.h
index c4afc94..bcebce1 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -102,6 +102,13 @@ static inline int sockaddr_equal(struct sockaddr_storage *a,
         return a4->sin_addr.s_addr == b4->sin_addr.s_addr
                && a4->sin_port == b4->sin_port;
     }
+    case AF_INET6:
+    {
+        struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) a;
+        struct sockaddr_in6 *b6 = (struct sockaddr_in6 *) b;
+        return (in6_equal(&a6->sin6_addr, &b6->sin6_addr)
+                && a6->sin6_port == b6->sin6_port);
+    }
     default:
         g_assert_not_reached();
     }
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [PATCHv7 2/9] slirp: Adding ICMPv6 error sending
  2016-02-14 17:47 [Qemu-devel] [PATCHv8 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
@ 2016-02-14 17:47 ` Samuel Thibault
  2016-02-16 12:21   ` Thomas Huth
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support Samuel Thibault
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 38+ messages in thread
From: Samuel Thibault @ 2016-02-14 17:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, Dave Gilbert, Vasiliy Tolstov, Huangpeng,
	Yann Bordenave, Gonglei, Jan Kiszka, Samuel Thibault,
	Guillaume Subiron

From: Yann Bordenave <meow@meowstars.org>

Disambiguation : icmp_error is renamed into icmp_send_error, since it
doesn't manage errors, but only sends ICMP Error messages.

Adding icmp6_send_error to send ICMPv6 Error messages. This function is
simpler than the v4 version.
Adding some calls in various functions to send ICMP errors, when a
received packet is too big, or when its hop limit is 0.

Signed-off-by: Yann Bordenave <meow@meowstars.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
 slirp/ip6_icmp.c  | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 slirp/ip6_icmp.h  | 10 +++++++++
 slirp/ip6_input.c | 13 ++++++-----
 slirp/ip_icmp.c   | 12 +++++------
 slirp/ip_icmp.h   |  4 ++--
 slirp/ip_input.c  |  8 +++----
 slirp/socket.c    |  4 ++--
 slirp/tcp_input.c |  2 +-
 slirp/udp.c       |  3 ++-
 9 files changed, 99 insertions(+), 21 deletions(-)

diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c
index 029d297..1cc65db 100644
--- a/slirp/ip6_icmp.c
+++ b/slirp/ip6_icmp.c
@@ -59,6 +59,70 @@ static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
     ip6_output(NULL, t, 0);
 }
 
+void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
+{
+    Slirp *slirp = m->slirp;
+    struct mbuf *t;
+    struct ip6 *ip = mtod(m, struct ip6 *);
+
+    char addrstr[INET6_ADDRSTRLEN];
+    DEBUG_CALL("icmp_send_error");
+    DEBUG_ARGS((dfd, " type = %d, code = %d\n", type, code));
+
+    if (IN6_IS_ADDR_MULTICAST(&ip->ip_src) ||
+            IN6_IS_ADDR_UNSPECIFIED(&ip->ip_src)) {
+        /* TODO icmp error? */
+        return;
+    }
+
+    t = m_get(slirp);
+
+    /* IPv6 packet */
+    struct ip6 *rip = mtod(t, struct ip6 *);
+    rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
+    rip->ip_dst = ip->ip_src;
+    inet_ntop(AF_INET6, &rip->ip_dst, addrstr, INET6_ADDRSTRLEN);
+    DEBUG_ARG("target = %s", addrstr);
+
+    rip->ip_nh = IPPROTO_ICMPV6;
+    const int error_data_len = min(m->m_len,
+            IF_MTU - (sizeof(struct ip6) + ICMP6_ERROR_MINLEN));
+    rip->ip_pl = htons(ICMP6_ERROR_MINLEN + error_data_len);
+    t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
+
+    /* ICMPv6 packet */
+    t->m_data += sizeof(struct ip6);
+    struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+    ricmp->icmp6_type = type;
+    ricmp->icmp6_code = code;
+    ricmp->icmp6_cksum = 0;
+
+    switch (type) {
+    case ICMP6_UNREACH:
+    case ICMP6_TIMXCEED:
+        ricmp->icmp6_err.unused = 0;
+        break;
+    case ICMP6_TOOBIG:
+        ricmp->icmp6_err.mtu = htonl(IF_MTU);
+        break;
+    case ICMP6_PARAMPROB:
+        /* TODO: Handle this case */
+        break;
+    default:
+        g_assert_not_reached();
+        break;
+    }
+    t->m_data += ICMP6_ERROR_MINLEN;
+    memcpy(t->m_data, m->m_data, error_data_len);
+
+    /* Checksum */
+    t->m_data -= ICMP6_ERROR_MINLEN;
+    t->m_data -= sizeof(struct ip6);
+    ricmp->icmp6_cksum = ip6_cksum(t);
+
+    ip6_output(NULL, t, 0);
+}
+
 /*
  * Send NDP Router Advertisement
  */
diff --git a/slirp/ip6_icmp.h b/slirp/ip6_icmp.h
index b2c40d6..9460bf8 100644
--- a/slirp/ip6_icmp.h
+++ b/slirp/ip6_icmp.h
@@ -19,6 +19,12 @@ struct icmp6_echo { /* Echo Messages */
     uint16_t seq_num;
 };
 
+union icmp6_error_body {
+    uint32_t unused;
+    uint32_t pointer;
+    uint32_t mtu;
+};
+
 /*
  * NDP Messages
  */
@@ -82,6 +88,7 @@ struct icmp6 {
     uint8_t     icmp6_code;         /* type sub code */
     uint16_t    icmp6_cksum;        /* ones complement cksum of struct */
     union {
+        union icmp6_error_body error_body;
         struct icmp6_echo echo;
         struct ndp_rs ndp_rs;
         struct ndp_ra ndp_ra;
@@ -89,6 +96,7 @@ struct icmp6 {
         struct ndp_na ndp_na;
         struct ndp_redirect ndp_redirect;
     } icmp6_body;
+#define icmp6_err icmp6_body.error_body
 #define icmp6_echo icmp6_body.echo
 #define icmp6_nrs icmp6_body.ndp_rs
 #define icmp6_nra icmp6_body.ndp_ra
@@ -98,6 +106,7 @@ struct icmp6 {
 } QEMU_PACKED;
 
 #define ICMP6_MINLEN    4
+#define ICMP6_ERROR_MINLEN  8
 #define ICMP6_ECHO_MINLEN   8
 #define ICMP6_NDP_RS_MINLEN 8
 #define ICMP6_NDP_RA_MINLEN 16
@@ -197,6 +206,7 @@ struct ndpopt {
 void icmp6_init(Slirp *slirp);
 void icmp6_cleanup(Slirp *slirp);
 void icmp6_input(struct mbuf *);
+void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code);
 void ndp_send_ra(Slirp *slirp);
 void ndp_send_ns(Slirp *slirp, struct in6_addr addr);
 
diff --git a/slirp/ip6_input.c b/slirp/ip6_input.c
index df249f1..b6a438d 100644
--- a/slirp/ip6_input.c
+++ b/slirp/ip6_input.c
@@ -39,9 +39,14 @@ void ip6_input(struct mbuf *m)
         goto bad;
     }
 
+    if (ntohs(ip6->ip_pl) > IF_MTU) {
+        icmp6_send_error(m, ICMP6_TOOBIG, 0);
+        goto bad;
+    }
+
     /* check ip_ttl for a correct ICMP reply */
     if (ip6->ip_hl == 0) {
-        /*icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");*/
+        icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS);
         goto bad;
     }
 
@@ -49,14 +54,12 @@ void ip6_input(struct mbuf *m)
      * Switch out to protocol's input routine.
      */
     switch (ip6->ip_nh) {
-#if 0
     case IPPROTO_TCP:
-        tcp_input(m, hlen, (struct socket *)NULL);
+        icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
         break;
     case IPPROTO_UDP:
-        udp_input(m, hlen);
+        icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
         break;
-#endif
     case IPPROTO_ICMPV6:
         icmp6_input(m);
         break;
diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
index ace3982..590dada 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -38,7 +38,7 @@
 /* Be nice and tell them it's just a pseudo-ping packet */
 static const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n";
 
-/* list of actions for icmp_error() on RX of an icmp message */
+/* list of actions for icmp_send_error() on RX of an icmp message */
 static const int icmp_flush[19] = {
 /*  ECHO REPLY (0)  */   0,
 		         1,
@@ -101,7 +101,7 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen)
                (struct sockaddr *)&addr, sizeof(addr)) == -1) {
         DEBUG_MISC((dfd, "icmp_input icmp sendto tx errno = %d-%s\n",
                     errno, strerror(errno)));
-        icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
+        icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
         icmp_detach(so);
     }
 
@@ -189,7 +189,7 @@ icmp_input(struct mbuf *m, int hlen)
 		(struct sockaddr *)&addr, sizeof(addr)) == -1) {
 	DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
 		    errno,strerror(errno)));
-	icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
+	icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno));
 	udp_detach(so);
       }
     } /* if ip->ip_dst.s_addr == alias_addr.s_addr */
@@ -235,7 +235,7 @@ end_error:
 
 #define ICMP_MAXDATALEN (IP_MSS-28)
 void
-icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
+icmp_send_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
            const char *message)
 {
   unsigned hlen, shlen, s_ip_len;
@@ -243,7 +243,7 @@ icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
   register struct icmp *icp;
   register struct mbuf *m;
 
-  DEBUG_CALL("icmp_error");
+  DEBUG_CALL("icmp_send_error");
   DEBUG_ARG("msrc = %p", msrc);
   DEBUG_ARG("msrc_len = %d", msrc->m_len);
 
@@ -433,7 +433,7 @@ void icmp_receive(struct socket *so)
         }
         DEBUG_MISC((dfd, " udp icmp rx errno = %d-%s\n", errno,
                     strerror(errno)));
-        icmp_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno));
+        icmp_send_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno));
     } else {
         icmp_reflect(so->so_m);
         so->so_m = NULL; /* Don't m_free() it again! */
diff --git a/slirp/ip_icmp.h b/slirp/ip_icmp.h
index be4426b..846761d 100644
--- a/slirp/ip_icmp.h
+++ b/slirp/ip_icmp.h
@@ -156,8 +156,8 @@ struct icmp {
 void icmp_init(Slirp *slirp);
 void icmp_cleanup(Slirp *slirp);
 void icmp_input(struct mbuf *, int);
-void icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
-                const char *message);
+void icmp_send_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
+                     const char *message);
 void icmp_reflect(struct mbuf *);
 void icmp_receive(struct socket *so);
 void icmp_detach(struct socket *so);
diff --git a/slirp/ip_input.c b/slirp/ip_input.c
index e4855ae..16fb2cb 100644
--- a/slirp/ip_input.c
+++ b/slirp/ip_input.c
@@ -132,9 +132,9 @@ ip_input(struct mbuf *m)
 	   m_adj(m, ip->ip_len - m->m_len);
 
 	/* check ip_ttl for a correct ICMP reply */
-	if(ip->ip_ttl==0) {
-	  icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");
-	  goto bad;
+	if (ip->ip_ttl == 0) {
+	    icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, "ttl");
+	    goto bad;
 	}
 
 	/*
@@ -637,7 +637,7 @@ typedef uint32_t n_time;
 	}
 	return (0);
 bad:
- 	icmp_error(m, type, code, 0, 0);
+	icmp_send_error(m, type, code, 0, 0);
 
 	return (1);
 }
diff --git a/slirp/socket.c b/slirp/socket.c
index 2b5453e..32b1ba3 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -463,7 +463,7 @@ sorecvfrom(struct socket *so)
 
 	    DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n",
 			errno,strerror(errno)));
-	    icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
+	    icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno));
 	  } else {
 	    icmp_reflect(so->so_m);
             so->so_m = NULL; /* Don't m_free() it again! */
@@ -511,7 +511,7 @@ sorecvfrom(struct socket *so)
 	    else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
 
 	    DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code));
-	    icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
+	    icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno));
 	    m_free(m);
 	  } else {
 	  /*
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index 2027a75..5f845da 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -608,7 +608,7 @@ findso:
 	      m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
 	      m->m_len  += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
 	      *ip=save_ip;
-	      icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno));
+	      icmp_send_error(m, ICMP_UNREACH, code, 0, strerror(errno));
 	    }
             tcp_close(tp);
 	    m_free(m);
diff --git a/slirp/udp.c b/slirp/udp.c
index 6b39cab..be012fb 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -209,7 +209,8 @@ udp_input(register struct mbuf *m, int iphlen)
 	  m->m_data -= iphlen;
 	  *ip=save_ip;
 	  DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
-	  icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
+	  icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0,
+	                  strerror(errno));
 	  goto bad;
 	}
 
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support
  2016-02-14 17:47 [Qemu-devel] [PATCHv8 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 2/9] slirp: Adding ICMPv6 error sending Samuel Thibault
@ 2016-02-14 17:47 ` Samuel Thibault
  2016-02-16 12:28   ` Thomas Huth
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union Samuel Thibault
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 38+ messages in thread
From: Samuel Thibault @ 2016-02-14 17:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei,
	Jan Kiszka, Samuel Thibault, Guillaume Subiron

From: Guillaume Subiron <maethor@subiron.org>

This adds the sin6 case in the fhost and lhost unions and related macros.
It adds udp6_input() and udp6_output().
It adds the IPv6 case in sorecvfrom().
Finally, udp_input() is called by ip6_input().

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
 slirp/Makefile.objs |   2 +-
 slirp/ip6_input.c   |   2 +-
 slirp/socket.c      |   5 ++
 slirp/socket.h      |   6 ++
 slirp/udp.h         |   5 ++
 slirp/udp6.c        | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 174 insertions(+), 2 deletions(-)
 create mode 100644 slirp/udp6.c

diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs
index 4e3a289..6748e4f 100644
--- a/slirp/Makefile.objs
+++ b/slirp/Makefile.objs
@@ -1,5 +1,5 @@
 common-obj-y = cksum.o if.o ip_icmp.o ip6_icmp.o ip6_input.o ip6_output.o \
                ip_input.o ip_output.o dnssearch.o
 common-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
-common-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o \
+common-obj-y += tcp_subr.o tcp_timer.o udp.o udp6.o bootp.o tftp.o arp_table.o \
                 ndp_table.o
diff --git a/slirp/ip6_input.c b/slirp/ip6_input.c
index b6a438d..9ca6d32 100644
--- a/slirp/ip6_input.c
+++ b/slirp/ip6_input.c
@@ -58,7 +58,7 @@ void ip6_input(struct mbuf *m)
         icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
         break;
     case IPPROTO_UDP:
-        icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
+        udp6_input(m);
         break;
     case IPPROTO_ICMPV6:
         icmp6_input(m);
diff --git a/slirp/socket.c b/slirp/socket.c
index 32b1ba3..b79ddec 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -541,7 +541,12 @@ sorecvfrom(struct socket *so)
 	                   (struct sockaddr_in *) &daddr,
 	                   so->so_iptos);
 	        break;
+	    case AF_INET6:
+	        udp6_output(so, m, (struct sockaddr_in6 *) &saddr,
+	                    (struct sockaddr_in6 *) &daddr);
+	        break;
 	    default:
+	        g_assert_not_reached();
 	        break;
 	    }
 	  } /* rx error */
diff --git a/slirp/socket.h b/slirp/socket.h
index bcebce1..e9c9b05 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -34,17 +34,23 @@ struct socket {
   union {   /* foreign host */
       struct sockaddr_storage ss;
       struct sockaddr_in sin;
+      struct sockaddr_in6 sin6;
   } fhost;
 #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;
 #define so_laddr lhost.sin.sin_addr
 #define so_lport lhost.sin.sin_port
+#define so_laddr6 lhost.sin6.sin6_addr
+#define so_lport6 lhost.sin6.sin6_port
 #define so_lfamily lhost.ss.ss_family
 
   uint8_t	so_iptos;	/* Type of service */
diff --git a/slirp/udp.h b/slirp/udp.h
index 2f9de38..10cc780 100644
--- a/slirp/udp.h
+++ b/slirp/udp.h
@@ -83,4 +83,9 @@ struct socket * udp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int,
 int udp_output(struct socket *so, struct mbuf *m,
                 struct sockaddr_in *saddr, struct sockaddr_in *daddr,
                 int iptos);
+
+void udp6_input(register struct mbuf *);
+int udp6_output(struct socket *so, struct mbuf *m,
+                struct sockaddr_in6 *saddr, struct sockaddr_in6 *daddr);
+
 #endif
diff --git a/slirp/udp6.c b/slirp/udp6.c
new file mode 100644
index 0000000..6c0d55f
--- /dev/null
+++ b/slirp/udp6.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron
+ */
+
+#include "slirp.h"
+#include "qemu/osdep.h"
+#include "udp.h"
+
+void udp6_input(struct mbuf *m)
+{
+    Slirp *slirp = m->slirp;
+    struct ip6 *ip, save_ip;
+    struct udphdr *uh;
+    int hlen = sizeof(struct ip6);
+    int len;
+    struct socket *so;
+    struct sockaddr_in6 lhost;
+
+    DEBUG_CALL("udp6_input");
+    DEBUG_ARG("m = %lx", (long)m);
+
+    if (slirp->restricted) {
+        goto bad;
+    }
+
+    ip = mtod(m, struct ip6 *);
+    m->m_len -= hlen;
+    m->m_data += hlen;
+    uh = mtod(m, struct udphdr *);
+    m->m_len += hlen;
+    m->m_data -= hlen;
+
+    if (ip6_cksum(m)) {
+        goto bad;
+    }
+
+    len = ntohs((uint16_t)uh->uh_ulen);
+
+    /*
+     * Make mbuf data length reflect UDP length.
+     * If not enough data to reflect UDP length, drop.
+     */
+    if (ntohs(ip->ip_pl) != len) {
+        if (len > ntohs(ip->ip_pl)) {
+            goto bad;
+        }
+        m_adj(m, len - ntohs(ip->ip_pl));
+        ip->ip_pl = htons(len);
+    }
+
+    /*
+     * Save a copy of the IP header in case we want restore it
+     * for sending an ICMP error message in response.
+     */
+    save_ip = *ip;
+
+    /* TODO handle DHCP/BOOTP */
+    /* TODO handle TFTP */
+
+    /* Locate pcb for datagram. */
+    lhost.sin6_family = AF_INET6;
+    lhost.sin6_addr = ip->ip_src;
+    lhost.sin6_port = uh->uh_sport;
+
+    so = solookup(&slirp->udp_last_so, &slirp->udb,
+                  (struct sockaddr_storage *) &lhost, NULL);
+
+    if (so == NULL) {
+        /* If there's no socket for this packet, create one. */
+        so = socreate(slirp);
+        if (!so) {
+            goto bad;
+        }
+        if (udp_attach(so, AF_INET6) == -1) {
+            DEBUG_MISC((dfd, " udp6_attach errno = %d-%s\n",
+                        errno, strerror(errno)));
+            sofree(so);
+            goto bad;
+        }
+
+        /* Setup fields */
+        so->so_lfamily = AF_INET6;
+        so->so_laddr6 = ip->ip_src;
+        so->so_lport6 = uh->uh_sport;
+    }
+
+    so->so_ffamily = AF_INET6;
+    so->so_faddr6 = ip->ip_dst; /* XXX */
+    so->so_fport6 = uh->uh_dport; /* XXX */
+
+    hlen += sizeof(struct udphdr);
+    m->m_len -= hlen;
+    m->m_data += hlen;
+
+    /*
+     * Now we sendto() the packet.
+     */
+    if (sosendto(so, m) == -1) {
+        m->m_len += hlen;
+        m->m_data -= hlen;
+        *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));*/
+        goto bad;
+    }
+
+    m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
+
+    /* restore the orig mbuf packet */
+    m->m_len += hlen;
+    m->m_data -= hlen;
+    *ip = save_ip;
+    so->so_m = m;
+
+    return;
+bad:
+    m_free(m);
+}
+
+int udp6_output(struct socket *so, struct mbuf *m,
+        struct sockaddr_in6 *saddr, struct sockaddr_in6 *daddr)
+{
+    struct ip6 *ip;
+    struct udphdr *uh;
+
+    DEBUG_CALL("udp6_output");
+    DEBUG_ARG("so = %lx", (long)so);
+    DEBUG_ARG("m = %lx", (long)m);
+
+    /* adjust for header */
+    m->m_data -= sizeof(struct udphdr);
+    m->m_len += sizeof(struct udphdr);
+    uh = mtod(m, struct udphdr *);
+    m->m_data -= sizeof(struct ip6);
+    m->m_len += sizeof(struct ip6);
+    ip = mtod(m, struct ip6 *);
+
+    /* Build IP header */
+    ip->ip_pl = htons(m->m_len - sizeof(struct ip6));
+    ip->ip_nh = IPPROTO_UDP;
+    ip->ip_src = saddr->sin6_addr;
+    ip->ip_dst = daddr->sin6_addr;
+
+    /* Build UDP header */
+    uh->uh_sport = saddr->sin6_port;
+    uh->uh_dport = daddr->sin6_port;
+    uh->uh_ulen = ip->ip_pl;
+    uh->uh_sum = 0;
+    uh->uh_sum = ip6_cksum(m);
+    if (uh->uh_sum == 0)
+        uh->uh_sum = 0xffff;
+
+    return ip6_output(so, m, 0);
+}
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union
  2016-02-14 17:47 [Qemu-devel] [PATCHv8 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (2 preceding siblings ...)
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support Samuel Thibault
@ 2016-02-14 17:47 ` Samuel Thibault
  2016-02-19  0:36   ` Samuel Thibault
  2016-02-19 13:44   ` Thomas Huth
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 5/9] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff Samuel Thibault
                   ` (5 subsequent siblings)
  9 siblings, 2 replies; 38+ messages in thread
From: Samuel Thibault @ 2016-02-14 17:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei,
	Jan Kiszka, Samuel Thibault, Guillaume Subiron

From: Guillaume Subiron <maethor@subiron.org>

This patch factorizes the tcpiphdr structure to put the IPv4 fields in
an union, for addition of version 6 in further patch.
Using some macros, retrocompatibility of the existing code is assured.

This patch also fixes the SLIRP_MSIZE and margin computation in various
functions, and makes them compatible with the new tcpiphdr structure,
whose size will be bigger than sizeof(struct tcphdr) + sizeof(struct ip)

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
 slirp/if.h         |  4 ++--
 slirp/mbuf.c       |  3 ++-
 slirp/slirp.c      | 15 ++++++++-------
 slirp/socket.c     | 13 ++++++++++++-
 slirp/tcp_input.c  | 31 ++++++++++++++++++++-----------
 slirp/tcp_output.c | 18 +++++++++++++-----
 slirp/tcp_subr.c   | 31 ++++++++++++++++++++++---------
 slirp/tcpip.h      | 31 +++++++++++++++++++++++--------
 8 files changed, 102 insertions(+), 44 deletions(-)

diff --git a/slirp/if.h b/slirp/if.h
index 3327023..c7a5c57 100644
--- a/slirp/if.h
+++ b/slirp/if.h
@@ -17,7 +17,7 @@
 #define IF_MRU 1500
 #define	IF_COMP IF_AUTOCOMP	/* Flags for compression */
 
-/* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
-#define IF_MAXLINKHDR (2 + 14 + 40)
+/* 2 for alignment, 14 for ethernet */
+#define IF_MAXLINKHDR (2 + ETH_HLEN)
 
 #endif
diff --git a/slirp/mbuf.c b/slirp/mbuf.c
index c959758..f081c69 100644
--- a/slirp/mbuf.c
+++ b/slirp/mbuf.c
@@ -24,7 +24,8 @@
  * Find a nice value for msize
  * XXX if_maxlinkhdr already in mtu
  */
-#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6)
+#define SLIRP_MSIZE\
+    (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)
 
 void
 m_init(Slirp *slirp)
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 5f42ada..c2c4597 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -754,15 +754,16 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
         m = m_get(slirp);
         if (!m)
             return;
-        /* Note: we add to align the IP header */
-        if (M_FREEROOM(m) < pkt_len + 2) {
-            m_inc(m, pkt_len + 2);
+        /* Note: we add 2 to align the IP header on 4 bytes,
+         * and add the margin for the tcpiphdr overhead  */
+        if (M_FREEROOM(m) < pkt_len + TCPIPHDR_DELTA + 2) {
+            m_inc(m, pkt_len + TCPIPHDR_DELTA + 2);
         }
-        m->m_len = pkt_len + 2;
-        memcpy(m->m_data + 2, pkt, pkt_len);
+        m->m_len = pkt_len + TCPIPHDR_DELTA + 2;
+        memcpy(m->m_data + TCPIPHDR_DELTA + 2, pkt, pkt_len);
 
-        m->m_data += 2 + ETH_HLEN;
-        m->m_len -= 2 + ETH_HLEN;
+        m->m_data += TCPIPHDR_DELTA + 2 + ETH_HLEN;
+        m->m_len -= TCPIPHDR_DELTA + 2 + ETH_HLEN;
 
         if (proto == ETH_P_IP) {
             ip_input(m);
diff --git a/slirp/socket.c b/slirp/socket.c
index b79ddec..d4b02c8 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -483,7 +483,18 @@ sorecvfrom(struct socket *so)
 	  if (!m) {
 	      return;
 	  }
-	  m->m_data += IF_MAXLINKHDR;
+	  switch (so->so_ffamily) {
+	  case AF_INET:
+	      m->m_data += IF_MAXLINKHDR + sizeof(struct udpiphdr);
+	      break;
+	  case AF_INET6:
+	      m->m_data += IF_MAXLINKHDR + sizeof(struct ip6)
+	                                 + sizeof(struct udphdr);
+	      break;
+	  default:
+	      g_assert_not_reached();
+	      break;
+	  }
 
 	  /*
 	   * XXX Shouldn't FIONREAD packets destined for port 53,
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index 5f845da..26b0c8b 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -256,11 +256,6 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
 	}
 	slirp = m->slirp;
 
-	/*
-	 * Get IP and TCP header together in first mbuf.
-	 * Note: IP leaves IP header in first mbuf.
-	 */
-	ti = mtod(m, struct tcpiphdr *);
 	if (iphlen > sizeof(struct ip )) {
 	  ip_stripoptions(m, (struct mbuf *)0);
 	  iphlen=sizeof(struct ip );
@@ -277,14 +272,28 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
 	save_ip.ip_len+= iphlen;
 
 	/*
+	 * Get IP and TCP header together in first mbuf.
+	 * Note: IP leaves IP header in first mbuf.
+	 */
+	m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip)
+	                                     + sizeof(struct tcphdr));
+	m->m_len += sizeof(struct tcpiphdr) - (sizeof(struct ip)
+	                                    + sizeof(struct tcphdr));
+	ti = mtod(m, struct tcpiphdr *);
+
+	/*
 	 * Checksum extended TCP header and data.
 	 */
-	tlen = ((struct ip *)ti)->ip_len;
-        tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
-        memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
-	ti->ti_x1 = 0;
+	tlen = ip->ip_len;
+	tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
+	memset(&ti->ih_mbuf, 0 , sizeof(struct mbuf_ptr));
+	memset(&ti->ti, 0, sizeof(ti->ti));
+	ti->ti_x0 = 0;
+	ti->ti_src = save_ip.ip_src;
+	ti->ti_dst = save_ip.ip_dst;
+	ti->ti_pr = save_ip.ip_p;
 	ti->ti_len = htons((uint16_t)tlen);
-	len = sizeof(struct ip ) + tlen;
+	len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
 	if(cksum(m, len)) {
 	  goto drop;
 	}
@@ -1475,7 +1484,7 @@ tcp_mss(struct tcpcb *tp, u_int offer)
 	DEBUG_ARG("tp = %p", tp);
 	DEBUG_ARG("offer = %d", offer);
 
-	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcpiphdr);
+	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr) + sizeof(struct ip);
 	if (offer)
 		mss = min(mss, offer);
 	mss = max(mss, 32);
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index 34e4d2e..7fc6a87 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -448,15 +448,23 @@ send:
 	 */
 	m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
 
-    {
+	struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
+	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                     - sizeof(struct ip);
+	m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                     - sizeof(struct ip);
+	struct ip *ip = mtod(m, struct ip *);
 
-	((struct ip *)ti)->ip_len = m->m_len;
+	ip->ip_len = m->m_len;
+	ip->ip_dst = tcpiph_save.ti_dst;
+	ip->ip_src = tcpiph_save.ti_src;
+	ip->ip_p = tcpiph_save.ti_pr;
 
-	((struct ip *)ti)->ip_ttl = IPDEFTTL;
-	((struct ip *)ti)->ip_tos = so->so_iptos;
+	ip->ip_ttl = IPDEFTTL;
+	ip->ip_tos = so->so_iptos;
 
 	error = ip_output(so, m);
-    }
+
 	if (error) {
 out:
 		return (error);
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index b1aa1f2..cd021df 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -76,9 +76,10 @@ tcp_template(struct tcpcb *tp)
 	register struct tcpiphdr *n = &tp->t_template;
 
 	n->ti_mbuf = NULL;
-	n->ti_x1 = 0;
+	memset(&n->ti, 0, sizeof(n->ti));
+	n->ti_x0 = 0;
 	n->ti_pr = IPPROTO_TCP;
-	n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
+	n->ti_len = htons(sizeof(struct tcphdr));
 	n->ti_src = so->so_faddr;
 	n->ti_dst = so->so_laddr;
 	n->ti_sport = so->so_fport;
@@ -131,6 +132,7 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 		m->m_data += IF_MAXLINKHDR;
 		*mtod(m, struct tcpiphdr *) = *ti;
 		ti = mtod(m, struct tcpiphdr *);
+		memset(&ti->ti, 0, sizeof(ti->ti));
 		flags = TH_ACK;
 	} else {
 		/*
@@ -150,8 +152,8 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 	tlen += sizeof (struct tcpiphdr);
 	m->m_len = tlen;
 
-        ti->ti_mbuf = NULL;
-	ti->ti_x1 = 0;
+	ti->ti_mbuf = NULL;
+	ti->ti_x0 = 0;
 	ti->ti_seq = htonl(seq);
 	ti->ti_ack = htonl(ack);
 	ti->ti_x2 = 0;
@@ -164,12 +166,23 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 	ti->ti_urp = 0;
 	ti->ti_sum = 0;
 	ti->ti_sum = cksum(m, tlen);
-	((struct ip *)ti)->ip_len = tlen;
 
-	if(flags & TH_RST)
-	  ((struct ip *)ti)->ip_ttl = MAXTTL;
-	else
-	  ((struct ip *)ti)->ip_ttl = IPDEFTTL;
+	struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
+	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                     - sizeof(struct ip);
+	m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                     - sizeof(struct ip);
+	struct ip *ip = mtod(m, struct ip *);
+	ip->ip_len = tlen;
+	ip->ip_dst = tcpiph_save.ti_dst;
+	ip->ip_src = tcpiph_save.ti_src;
+	ip->ip_p = tcpiph_save.ti_pr;
+
+	if (flags & TH_RST) {
+		ip->ip_ttl = MAXTTL;
+	} else {
+		ip->ip_ttl = IPDEFTTL;
+	}
 
 	(void) ip_output((struct socket *)0, m);
 }
diff --git a/slirp/tcpip.h b/slirp/tcpip.h
index 7974ce3..3c5d127 100644
--- a/slirp/tcpip.h
+++ b/slirp/tcpip.h
@@ -37,15 +37,23 @@
  * Tcp+ip header, after ip options removed.
  */
 struct tcpiphdr {
-	struct 	ipovly ti_i;		/* overlaid ip structure */
-	struct	tcphdr ti_t;		/* tcp header */
+    struct mbuf_ptr ih_mbuf;	/* backpointer to mbuf */
+    union {
+        struct {
+            struct  in_addr ih_src; /* source internet address */
+            struct  in_addr ih_dst; /* destination internet address */
+            uint8_t ih_x1;          /* (unused) */
+            uint8_t ih_pr;          /* protocol */
+        } ti_i4;
+    } ti;
+    uint16_t    ti_x0;
+    uint16_t    ti_len;             /* protocol length */
+    struct      tcphdr ti_t;        /* tcp header */
 };
-#define	ti_mbuf		ti_i.ih_mbuf.mptr
-#define	ti_x1		ti_i.ih_x1
-#define	ti_pr		ti_i.ih_pr
-#define	ti_len		ti_i.ih_len
-#define	ti_src		ti_i.ih_src
-#define	ti_dst		ti_i.ih_dst
+#define	ti_mbuf		ih_mbuf.mptr
+#define	ti_pr		ti.ti_i4.ih_pr
+#define	ti_src		ti.ti_i4.ih_src
+#define	ti_dst		ti.ti_i4.ih_dst
 #define	ti_sport	ti_t.th_sport
 #define	ti_dport	ti_t.th_dport
 #define	ti_seq		ti_t.th_seq
@@ -65,6 +73,13 @@ struct tcpiphdr {
 #define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink*)(T))
 #define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr*)(T))
 
+/* This is the difference between the size of a tcpiphdr structure, and the
+ * size of actual ip+tcp headers, rounded up since we need to align data.  */
+#define TCPIPHDR_DELTA\
+    (max(0,\
+         (sizeof(struct tcpiphdr)\
+          - sizeof(struct ip) - sizeof(struct tcphdr) + 3) & ~3))
+
 /*
  * Just a clean way to get to the first byte
  * of the packet
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [PATCHv7 5/9] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff
  2016-02-14 17:47 [Qemu-devel] [PATCHv8 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (3 preceding siblings ...)
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union Samuel Thibault
@ 2016-02-14 17:47 ` Samuel Thibault
  2016-02-17  8:25   ` Thomas Huth
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring Samuel Thibault
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 38+ messages in thread
From: Samuel Thibault @ 2016-02-14 17:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei,
	Jan Kiszka, Samuel Thibault, Guillaume Subiron

From: Guillaume Subiron <maethor@subiron.org>

Basically, this patch adds some switch in various TCP functions to
prepare them for the IPv6 case.

To have something to "switch" in tcp_input() and tcp_respond(), a new
argument is used to give them the sa_family of the addresses they are
working on.

This patch does not include the entailed reindentation, to make proofread
easier. Reindentation is adressed in the following no-op patch.

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
 slirp/ip_input.c   |  2 +-
 slirp/slirp.c      |  6 ++++--
 slirp/slirp.h      |  5 +++--
 slirp/tcp_input.c  | 62 ++++++++++++++++++++++++++++++++++++++++++------------
 slirp/tcp_output.c | 14 +++++++++---
 slirp/tcp_subr.c   | 37 +++++++++++++++++++++++++-------
 slirp/tcp_timer.c  |  3 ++-
 7 files changed, 99 insertions(+), 30 deletions(-)

diff --git a/slirp/ip_input.c b/slirp/ip_input.c
index 16fb2cb..12f173d 100644
--- a/slirp/ip_input.c
+++ b/slirp/ip_input.c
@@ -200,7 +200,7 @@ ip_input(struct mbuf *m)
 	 */
 	switch (ip->ip_p) {
 	 case IPPROTO_TCP:
-		tcp_input(m, hlen, (struct socket *)NULL);
+		tcp_input(m, hlen, (struct socket *)NULL, AF_INET);
 		break;
 	 case IPPROTO_UDP:
 		udp_input(m, hlen);
diff --git a/slirp/slirp.c b/slirp/slirp.c
index c2c4597..2321c41 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -574,7 +574,8 @@ void slirp_pollfds_poll(GArray *pollfds, int select_error)
                         /*
                          * Continue tcp_input
                          */
-                        tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
+                        tcp_input((struct mbuf *)NULL, sizeof(struct ip), so,
+                                so->so_ffamily);
                         /* continue; */
                     } else {
                         ret = sowrite(so);
@@ -623,7 +624,8 @@ void slirp_pollfds_poll(GArray *pollfds, int select_error)
                         }
 
                     }
-                    tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
+                    tcp_input((struct mbuf *)NULL, sizeof(struct ip), so,
+                            so->so_ffamily);
                 } /* SS_ISFCONNECTING */
 #endif
             }
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 15775bc..967d93e 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -349,7 +349,7 @@ void ip6_input(struct mbuf *);
 int ip6_output(struct socket *, struct mbuf *, int fast);
 
 /* tcp_input.c */
-void tcp_input(register struct mbuf *, int, struct socket *);
+void tcp_input(register struct mbuf *, int, struct socket *, unsigned short af);
 int tcp_mss(register struct tcpcb *, u_int);
 
 /* tcp_output.c */
@@ -360,7 +360,8 @@ void tcp_setpersist(register struct tcpcb *);
 void tcp_init(Slirp *);
 void tcp_cleanup(Slirp *);
 void tcp_template(struct tcpcb *);
-void tcp_respond(struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int);
+void tcp_respond(struct tcpcb *, register struct tcpiphdr *,
+        register struct mbuf *, tcp_seq, tcp_seq, int, unsigned short);
 struct tcpcb * tcp_newtcpcb(struct socket *);
 struct tcpcb * tcp_close(register struct tcpcb *);
 void tcp_sockclosed(struct tcpcb *);
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index 26b0c8b..ceac795 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -214,7 +214,7 @@ present:
  * protocol specification dated September, 1981 very closely.
  */
 void
-tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
+tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
 {
   	struct ip save_ip, *ip;
 	register struct tcpiphdr *ti;
@@ -256,6 +256,8 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
 	}
 	slirp = m->slirp;
 
+	switch (af) {
+	case AF_INET:
 	if (iphlen > sizeof(struct ip )) {
 	  ip_stripoptions(m, (struct mbuf *)0);
 	  iphlen=sizeof(struct ip );
@@ -297,6 +299,11 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
 	if(cksum(m, len)) {
 	  goto drop;
 	}
+	break;
+
+	default:
+	    g_assert_not_reached();
+	}
 
 	/*
 	 * Check that TCP offset makes sense,
@@ -332,14 +339,20 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
 	 * Locate pcb for segment.
 	 */
 findso:
-	lhost.ss_family = AF_INET;
+	lhost.ss_family = af;
+	fhost.ss_family = af;
+	switch (af) {
+	case AF_INET:
 	lhost4 = (struct sockaddr_in *) &lhost;
 	lhost4->sin_addr = ti->ti_src;
 	lhost4->sin_port = ti->ti_sport;
-	fhost.ss_family = AF_INET;
 	fhost4 = (struct sockaddr_in *) &fhost;
 	fhost4->sin_addr = ti->ti_dst;
 	fhost4->sin_port = ti->ti_dport;
+	    break;
+	default:
+	    g_assert_not_reached();
+	}
 
 	so = solookup(&slirp->tcp_last_so, &slirp->tcb, &lhost, &fhost);
 
@@ -389,8 +402,16 @@ findso:
 	  so->lhost.ss = lhost;
 	  so->fhost.ss = fhost;
 
-	  if ((so->so_iptos = tcp_tos(so)) == 0)
-	    so->so_iptos = ((struct ip *)ti)->ip_tos;
+	  so->so_iptos = tcp_tos(so);
+	  if (so->so_iptos == 0) {
+	      switch (af) {
+	      case AF_INET:
+	          so->so_iptos = ((struct ip *)ti)->ip_tos;
+	          break;
+	      default:
+	          g_assert_not_reached();
+	      }
+	  }
 
 	  tp = sototcpcb(so);
 	  tp->t_state = TCPS_LISTEN;
@@ -569,7 +590,8 @@ findso:
 	   * If this is destined for the control address, then flag to
 	   * tcp_ctl once connected, otherwise connect
 	   */
-	  if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+	  if (af == AF_INET &&
+	      (so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
 	      slirp->vnetwork_addr.s_addr) {
 	    if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr &&
 		so->so_faddr.s_addr != slirp->vnameserver_addr.s_addr) {
@@ -606,8 +628,8 @@ findso:
 			errno,strerror(errno)));
 	    if(errno == ECONNREFUSED) {
 	      /* ACK the SYN, send RST to refuse the connection */
-	      tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0,
-			  TH_RST|TH_ACK);
+	      tcp_respond(tp, ti, m, ti->ti_seq + 1, (tcp_seq) 0,
+			  TH_RST | TH_ACK, af);
 	    } else {
 	      if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
 	      HTONL(ti->ti_seq);             /* restore tcp header */
@@ -616,7 +638,13 @@ findso:
 	      HTONS(ti->ti_urp);
 	      m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
 	      m->m_len  += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
-	      *ip=save_ip;
+	      switch (af) {
+	      case AF_INET:
+	          *ip = save_ip;
+	          break;
+	      default:
+	          g_assert_not_reached();
+	      }
 	      icmp_send_error(m, ICMP_UNREACH, code, 0, strerror(errno));
 	    }
             tcp_close(tp);
@@ -1289,11 +1317,11 @@ dropafterack:
 dropwithreset:
 	/* reuses m if m!=NULL, m_free() unnecessary */
 	if (tiflags & TH_ACK)
-		tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);
+		tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST, af);
 	else {
 		if (tiflags & TH_SYN) ti->ti_len++;
-		tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0,
-		    TH_RST|TH_ACK);
+		tcp_respond(tp, ti, m, ti->ti_seq + ti->ti_len, (tcp_seq) 0,
+		    TH_RST | TH_ACK, af);
 	}
 
 	return;
@@ -1484,7 +1512,15 @@ tcp_mss(struct tcpcb *tp, u_int offer)
 	DEBUG_ARG("tp = %p", tp);
 	DEBUG_ARG("offer = %d", offer);
 
-	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr) + sizeof(struct ip);
+	switch (so->so_ffamily) {
+	case AF_INET:
+	    mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr)
+	                              + sizeof(struct ip);
+	    break;
+	default:
+	    g_assert_not_reached();
+	}
+
 	if (offer)
 		mss = min(mss, offer);
 	mss = max(mss, 32);
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index 7fc6a87..1e5da73 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -61,7 +61,8 @@ tcp_output(struct tcpcb *tp)
 	register long len, win;
 	int off, flags, error;
 	register struct mbuf *m;
-	register struct tcpiphdr *ti;
+	register struct tcpiphdr *ti, tcpiph_save;
+	struct ip *ip;
 	u_char opt[MAX_TCPOPTLEN];
 	unsigned optlen, hdrlen;
 	int idle, sendalot;
@@ -447,13 +448,15 @@ send:
 	 * the template, but need a way to checksum without them.
 	 */
 	m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
+	tcpiph_save = *(mtod(m, struct tcpiphdr *));
 
-	struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
+	switch (so->so_ffamily) {
+	case AF_INET:
 	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
 	                                     - sizeof(struct ip);
 	m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
 	                                     - sizeof(struct ip);
-	struct ip *ip = mtod(m, struct ip *);
+	ip = mtod(m, struct ip *);
 
 	ip->ip_len = m->m_len;
 	ip->ip_dst = tcpiph_save.ti_dst;
@@ -464,6 +467,11 @@ send:
 	ip->ip_tos = so->so_iptos;
 
 	error = ip_output(so, m);
+	    break;
+
+	default:
+	    g_assert_not_reached();
+	}
 
 	if (error) {
 out:
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index cd021df..ee101e2 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -78,12 +78,19 @@ tcp_template(struct tcpcb *tp)
 	n->ti_mbuf = NULL;
 	memset(&n->ti, 0, sizeof(n->ti));
 	n->ti_x0 = 0;
+	switch (so->so_ffamily) {
+	case AF_INET:
 	n->ti_pr = IPPROTO_TCP;
 	n->ti_len = htons(sizeof(struct tcphdr));
 	n->ti_src = so->so_faddr;
 	n->ti_dst = so->so_laddr;
 	n->ti_sport = so->so_fport;
 	n->ti_dport = so->so_lport;
+	    break;
+
+	default:
+	    g_assert_not_reached();
+	}
 
 	n->ti_seq = 0;
 	n->ti_ack = 0;
@@ -110,7 +117,7 @@ tcp_template(struct tcpcb *tp)
  */
 void
 tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
-            tcp_seq ack, tcp_seq seq, int flags)
+            tcp_seq ack, tcp_seq seq, int flags, unsigned short af)
 {
 	register int tlen;
 	int win = 0;
@@ -144,8 +151,14 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 		m->m_len = sizeof (struct tcpiphdr);
 		tlen = 0;
 #define xchg(a,b,type) { type t; t=a; a=b; b=t; }
+		switch (af) {
+		case AF_INET:
 		xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t);
 		xchg(ti->ti_dport, ti->ti_sport, uint16_t);
+		    break;
+		default:
+		    g_assert_not_reached();
+		}
 #undef xchg
 	}
 	ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
@@ -168,11 +181,15 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 	ti->ti_sum = cksum(m, tlen);
 
 	struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
+	struct ip *ip;
+
+	switch (af) {
+	case AF_INET:
 	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
 	                                     - sizeof(struct ip);
 	m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
 	                                     - sizeof(struct ip);
-	struct ip *ip = mtod(m, struct ip *);
+	ip = mtod(m, struct ip *);
 	ip->ip_len = tlen;
 	ip->ip_dst = tcpiph_save.ti_dst;
 	ip->ip_src = tcpiph_save.ti_src;
@@ -185,6 +202,11 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 	}
 
 	(void) ip_output((struct socket *)0, m);
+	    break;
+
+	default:
+	    g_assert_not_reached();
+	}
 }
 
 /*
@@ -388,8 +410,8 @@ void tcp_connect(struct socket *inso)
 {
     Slirp *slirp = inso->slirp;
     struct socket *so;
-    struct sockaddr_in addr;
-    socklen_t addrlen = sizeof(struct sockaddr_in);
+    struct sockaddr_storage addr;
+    socklen_t addrlen = sizeof(struct sockaddr_storage);
     struct tcpcb *tp;
     int s, opt;
 
@@ -414,9 +436,8 @@ void tcp_connect(struct socket *inso)
             free(so); /* NOT sofree */
             return;
         }
-        so->so_lfamily = AF_INET;
-        so->so_laddr = inso->so_laddr;
-        so->so_lport = inso->so_lport;
+        so->lhost = inso->lhost;
+        so->so_ffamily = inso->so_ffamily;
     }
 
     tcp_mss(sototcpcb(so), 0);
@@ -432,7 +453,7 @@ void tcp_connect(struct socket *inso)
     qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
     socket_set_nodelay(s);
 
-    so->fhost.sin = addr;
+    so->fhost.ss = addr;
     sotranslate_accept(so);
 
     /* Close the accept() socket, set right state */
diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c
index 1214c2e..8f5dd77 100644
--- a/slirp/tcp_timer.c
+++ b/slirp/tcp_timer.c
@@ -278,7 +278,8 @@ tcp_timers(register struct tcpcb *tp, int timer)
 			 * correspondent TCP to respond.
 			 */
 			tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
-			    tp->rcv_nxt, tp->snd_una - 1, 0);
+			    tp->rcv_nxt, tp->snd_una - 1, 0,
+			    tp->t_socket->so_ffamily);
 			tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
 		} else
 			tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring
  2016-02-14 17:47 [Qemu-devel] [PATCHv8 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (4 preceding siblings ...)
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 5/9] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff Samuel Thibault
@ 2016-02-14 17:47 ` Samuel Thibault
  2016-02-17  9:03   ` Thomas Huth
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 7/9] slirp: Handle IPv6 in TCP functions Samuel Thibault
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 38+ messages in thread
From: Samuel Thibault @ 2016-02-14 17:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei,
	Jan Kiszka, Samuel Thibault, Guillaume Subiron

From: Guillaume Subiron <maethor@subiron.org>

No code change.

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
 slirp/tcp_input.c  | 92 +++++++++++++++++++++++++++---------------------------
 slirp/tcp_output.c | 29 +++++++++--------
 slirp/tcp_subr.c   | 50 ++++++++++++++---------------
 3 files changed, 85 insertions(+), 86 deletions(-)

diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index ceac795..fac2a24 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -258,48 +258,48 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
 
 	switch (af) {
 	case AF_INET:
-	if (iphlen > sizeof(struct ip )) {
-	  ip_stripoptions(m, (struct mbuf *)0);
-	  iphlen=sizeof(struct ip );
-	}
-	/* XXX Check if too short */
+	    if (iphlen > sizeof(struct ip)) {
+	        ip_stripoptions(m, (struct mbuf *)0);
+	        iphlen = sizeof(struct ip);
+	    }
+	    /* XXX Check if too short */
 
 
-	/*
-	 * Save a copy of the IP header in case we want restore it
-	 * for sending an ICMP error message in response.
-	 */
-	ip=mtod(m, struct ip *);
-	save_ip = *ip;
-	save_ip.ip_len+= iphlen;
+	    /*
+	     * Save a copy of the IP header in case we want restore it
+	     * for sending an ICMP error message in response.
+	     */
+	    ip = mtod(m, struct ip *);
+	    save_ip = *ip;
+	    save_ip.ip_len += iphlen;
 
-	/*
-	 * Get IP and TCP header together in first mbuf.
-	 * Note: IP leaves IP header in first mbuf.
-	 */
-	m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip)
-	                                     + sizeof(struct tcphdr));
-	m->m_len += sizeof(struct tcpiphdr) - (sizeof(struct ip)
-	                                    + sizeof(struct tcphdr));
-	ti = mtod(m, struct tcpiphdr *);
+	    /*
+	     * Get IP and TCP header together in first mbuf.
+	     * Note: IP leaves IP header in first mbuf.
+	     */
+	    m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip)
+	                                         + sizeof(struct tcphdr));
+	    m->m_len  += sizeof(struct tcpiphdr) - (sizeof(struct ip)
+	                                         + sizeof(struct tcphdr));
+	    ti = mtod(m, struct tcpiphdr *);
 
-	/*
-	 * Checksum extended TCP header and data.
-	 */
-	tlen = ip->ip_len;
-	tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
-	memset(&ti->ih_mbuf, 0 , sizeof(struct mbuf_ptr));
-	memset(&ti->ti, 0, sizeof(ti->ti));
-	ti->ti_x0 = 0;
-	ti->ti_src = save_ip.ip_src;
-	ti->ti_dst = save_ip.ip_dst;
-	ti->ti_pr = save_ip.ip_p;
-	ti->ti_len = htons((uint16_t)tlen);
-	len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
-	if(cksum(m, len)) {
-	  goto drop;
-	}
-	break;
+	    /*
+	     * Checksum extended TCP header and data.
+	     */
+	    tlen = ip->ip_len;
+	    tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
+	    memset(&ti->ih_mbuf, 0 , sizeof(struct mbuf_ptr));
+	    memset(&ti->ti, 0, sizeof(ti->ti));
+	    ti->ti_x0 = 0;
+	    ti->ti_src = save_ip.ip_src;
+	    ti->ti_dst = save_ip.ip_dst;
+	    ti->ti_pr = save_ip.ip_p;
+	    ti->ti_len = htons((uint16_t)tlen);
+	    len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
+	    if (cksum(m, len)) {
+	        goto drop;
+	    }
+	    break;
 
 	default:
 	    g_assert_not_reached();
@@ -343,12 +343,12 @@ findso:
 	fhost.ss_family = af;
 	switch (af) {
 	case AF_INET:
-	lhost4 = (struct sockaddr_in *) &lhost;
-	lhost4->sin_addr = ti->ti_src;
-	lhost4->sin_port = ti->ti_sport;
-	fhost4 = (struct sockaddr_in *) &fhost;
-	fhost4->sin_addr = ti->ti_dst;
-	fhost4->sin_port = ti->ti_dport;
+	    lhost4 = (struct sockaddr_in *) &lhost;
+	    lhost4->sin_addr = ti->ti_src;
+	    lhost4->sin_port = ti->ti_sport;
+	    fhost4 = (struct sockaddr_in *) &fhost;
+	    fhost4->sin_addr = ti->ti_dst;
+	    fhost4->sin_port = ti->ti_dport;
 	    break;
 	default:
 	    g_assert_not_reached();
@@ -591,8 +591,8 @@ findso:
 	   * tcp_ctl once connected, otherwise connect
 	   */
 	  if (af == AF_INET &&
-	      (so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
-	      slirp->vnetwork_addr.s_addr) {
+	         (so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+	         slirp->vnetwork_addr.s_addr) {
 	    if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr &&
 		so->so_faddr.s_addr != slirp->vnameserver_addr.s_addr) {
 		/* May be an add exec */
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index 1e5da73..66363b2 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -452,21 +452,20 @@ send:
 
 	switch (so->so_ffamily) {
 	case AF_INET:
-	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
-	                                     - sizeof(struct ip);
-	m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
-	                                     - sizeof(struct ip);
-	ip = mtod(m, struct ip *);
-
-	ip->ip_len = m->m_len;
-	ip->ip_dst = tcpiph_save.ti_dst;
-	ip->ip_src = tcpiph_save.ti_src;
-	ip->ip_p = tcpiph_save.ti_pr;
-
-	ip->ip_ttl = IPDEFTTL;
-	ip->ip_tos = so->so_iptos;
-
-	error = ip_output(so, m);
+	    m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                         - sizeof(struct ip);
+	    m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                         - sizeof(struct ip);
+	    ip = mtod(m, struct ip *);
+
+	    ip->ip_len = m->m_len;
+	    ip->ip_dst = tcpiph_save.ti_dst;
+	    ip->ip_src = tcpiph_save.ti_src;
+	    ip->ip_p = tcpiph_save.ti_pr;
+
+	    ip->ip_ttl = IPDEFTTL;
+	    ip->ip_tos = so->so_iptos;
+	    error = ip_output(so, m);
 	    break;
 
 	default:
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index ee101e2..c16b29d 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -80,12 +80,12 @@ tcp_template(struct tcpcb *tp)
 	n->ti_x0 = 0;
 	switch (so->so_ffamily) {
 	case AF_INET:
-	n->ti_pr = IPPROTO_TCP;
-	n->ti_len = htons(sizeof(struct tcphdr));
-	n->ti_src = so->so_faddr;
-	n->ti_dst = so->so_laddr;
-	n->ti_sport = so->so_fport;
-	n->ti_dport = so->so_lport;
+	    n->ti_pr = IPPROTO_TCP;
+	    n->ti_len = htons(sizeof(struct tcphdr));
+	    n->ti_src = so->so_faddr;
+	    n->ti_dst = so->so_laddr;
+	    n->ti_sport = so->so_fport;
+	    n->ti_dport = so->so_lport;
 	    break;
 
 	default:
@@ -153,8 +153,8 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 #define xchg(a,b,type) { type t; t=a; a=b; b=t; }
 		switch (af) {
 		case AF_INET:
-		xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t);
-		xchg(ti->ti_dport, ti->ti_sport, uint16_t);
+		    xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t);
+		    xchg(ti->ti_dport, ti->ti_sport, uint16_t);
 		    break;
 		default:
 		    g_assert_not_reached();
@@ -185,23 +185,23 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 
 	switch (af) {
 	case AF_INET:
-	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
-	                                     - sizeof(struct ip);
-	m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
-	                                     - sizeof(struct ip);
-	ip = mtod(m, struct ip *);
-	ip->ip_len = tlen;
-	ip->ip_dst = tcpiph_save.ti_dst;
-	ip->ip_src = tcpiph_save.ti_src;
-	ip->ip_p = tcpiph_save.ti_pr;
-
-	if (flags & TH_RST) {
-		ip->ip_ttl = MAXTTL;
-	} else {
-		ip->ip_ttl = IPDEFTTL;
-	}
-
-	(void) ip_output((struct socket *)0, m);
+	    m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                         - sizeof(struct ip);
+	    m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                         - sizeof(struct ip);
+	    ip = mtod(m, struct ip *);
+	    ip->ip_len = tlen;
+	    ip->ip_dst = tcpiph_save.ti_dst;
+	    ip->ip_src = tcpiph_save.ti_src;
+	    ip->ip_p = tcpiph_save.ti_pr;
+
+	    if (flags & TH_RST) {
+	        ip->ip_ttl = MAXTTL;
+	    } else {
+	        ip->ip_ttl = IPDEFTTL;
+	    }
+
+	    (void) ip_output((struct socket *)0, m);
 	    break;
 
 	default:
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [PATCHv7 7/9] slirp: Handle IPv6 in TCP functions
  2016-02-14 17:47 [Qemu-devel] [PATCHv8 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (5 preceding siblings ...)
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring Samuel Thibault
@ 2016-02-14 17:47 ` Samuel Thibault
  2016-02-17  9:18   ` Thomas Huth
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 8/9] slirp: Adding IPv6 address for DNS relay Samuel Thibault
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 38+ messages in thread
From: Samuel Thibault @ 2016-02-14 17:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei,
	Jan Kiszka, Samuel Thibault, Guillaume Subiron

From: Guillaume Subiron <maethor@subiron.org>

This patch adds IPv6 case in TCP functions refactored by the last
patches.
This also adds IPv6 pseudo-header in tcpiphdr structure.
Finally, tcp_input() is called by ip6_input().

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
 slirp/ip6_input.c  |  3 ++-
 slirp/tcp.h        |  2 ++
 slirp/tcp_input.c  | 60 +++++++++++++++++++++++++++++++++++++++++++-----------
 slirp/tcp_output.c | 16 +++++++++++++++
 slirp/tcp_subr.c   | 30 ++++++++++++++++++++++++++-
 slirp/tcpip.h      |  9 ++++++++
 6 files changed, 106 insertions(+), 14 deletions(-)

diff --git a/slirp/ip6_input.c b/slirp/ip6_input.c
index 9ca6d32..c0b11e7 100644
--- a/slirp/ip6_input.c
+++ b/slirp/ip6_input.c
@@ -55,7 +55,8 @@ void ip6_input(struct mbuf *m)
      */
     switch (ip6->ip_nh) {
     case IPPROTO_TCP:
-        icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
+        NTOHS(ip6->ip_pl);
+        tcp_input(m, sizeof(struct ip6), (struct socket *)NULL, AF_INET6);
         break;
     case IPPROTO_UDP:
         udp6_input(m);
diff --git a/slirp/tcp.h b/slirp/tcp.h
index 2e2b403..61befcd 100644
--- a/slirp/tcp.h
+++ b/slirp/tcp.h
@@ -106,6 +106,8 @@ struct tcphdr {
  */
 #undef TCP_MSS
 #define	TCP_MSS	1460
+#undef TCP6_MSS
+#define TCP6_MSS 1440
 
 #undef TCP_MAXWIN
 #define	TCP_MAXWIN	65535	/* largest value for (unscaled) window */
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index fac2a24..7aad1bc 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -216,7 +216,8 @@ present:
 void
 tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
 {
-  	struct ip save_ip, *ip;
+	struct ip save_ip, *ip;
+	struct ip6 save_ip6, *ip6;
 	register struct tcpiphdr *ti;
 	caddr_t optp = NULL;
 	int optlen = 0;
@@ -230,6 +231,7 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
 	int ret;
 	struct sockaddr_storage lhost, fhost;
 	struct sockaddr_in *lhost4, *fhost4;
+	struct sockaddr_in6 *lhost6, *fhost6;
     struct ex_list *ex_ptr;
     Slirp *slirp;
 
@@ -256,21 +258,18 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
 	}
 	slirp = m->slirp;
 
+	ip = mtod(m, struct ip *);
+	ip6 = mtod(m, struct ip6 *);
+
 	switch (af) {
 	case AF_INET:
+	    save_ip = *ip;
 	    if (iphlen > sizeof(struct ip)) {
 	        ip_stripoptions(m, (struct mbuf *)0);
 	        iphlen = sizeof(struct ip);
 	    }
 	    /* XXX Check if too short */
 
-
-	    /*
-	     * Save a copy of the IP header in case we want restore it
-	     * for sending an ICMP error message in response.
-	     */
-	    ip = mtod(m, struct ip *);
-	    save_ip = *ip;
 	    save_ip.ip_len += iphlen;
 
 	    /*
@@ -295,16 +294,36 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
 	    ti->ti_dst = save_ip.ip_dst;
 	    ti->ti_pr = save_ip.ip_p;
 	    ti->ti_len = htons((uint16_t)tlen);
-	    len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
-	    if (cksum(m, len)) {
-	        goto drop;
-	    }
+	    break;
+
+	case AF_INET6:
+	    save_ip6 = *ip6;
+	    m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip6)
+	                                         + sizeof(struct tcphdr));
+	    m->m_len  += sizeof(struct tcpiphdr) - (sizeof(struct ip6)
+	                                         + sizeof(struct tcphdr));
+	    ti = mtod(m, struct tcpiphdr *);
+
+	    tlen = ip6->ip_pl;
+	    tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
+	    memset(&ti->ih_mbuf, 0 , sizeof(struct mbuf_ptr));
+	    memset(&ti->ti, 0, sizeof(ti->ti));
+	    ti->ti_x0 = 0;
+	    ti->ti_src6 = save_ip6.ip_src;
+	    ti->ti_dst6 = save_ip6.ip_dst;
+	    ti->ti_nh6 = save_ip6.ip_nh;
+	    ti->ti_len = htons((uint16_t)tlen);
 	    break;
 
 	default:
 	    g_assert_not_reached();
 	}
 
+	len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
+	if (cksum(m, len)) {
+	    goto drop;
+	}
+
 	/*
 	 * Check that TCP offset makes sense,
 	 * pull out TCP options and adjust length.		XXX
@@ -350,6 +369,14 @@ findso:
 	    fhost4->sin_addr = ti->ti_dst;
 	    fhost4->sin_port = ti->ti_dport;
 	    break;
+	case AF_INET6:
+	    lhost6 = (struct sockaddr_in6 *) &lhost;
+	    lhost6->sin6_addr = ti->ti_src6;
+	    lhost6->sin6_port = ti->ti_sport;
+	    fhost6 = (struct sockaddr_in6 *) &fhost;
+	    fhost6->sin6_addr = ti->ti_dst6;
+	    fhost6->sin6_port = ti->ti_dport;
+	    break;
 	default:
 	    g_assert_not_reached();
 	}
@@ -408,6 +435,8 @@ findso:
 	      case AF_INET:
 	          so->so_iptos = ((struct ip *)ti)->ip_tos;
 	          break;
+	      case AF_INET6:
+	          break;
 	      default:
 	          g_assert_not_reached();
 	      }
@@ -642,6 +671,9 @@ findso:
 	      case AF_INET:
 	          *ip = save_ip;
 	          break;
+	      case AF_INET6:
+	          *ip6 = save_ip6;
+	          break;
 	      default:
 	          g_assert_not_reached();
 	      }
@@ -1517,6 +1549,10 @@ tcp_mss(struct tcpcb *tp, u_int offer)
 	    mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr)
 	                              + sizeof(struct ip);
 	    break;
+	case AF_INET6:
+	    mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr)
+	                              + sizeof(struct ip6);
+	    break;
 	default:
 	    g_assert_not_reached();
 	}
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index 66363b2..61c3366 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -63,6 +63,7 @@ tcp_output(struct tcpcb *tp)
 	register struct mbuf *m;
 	register struct tcpiphdr *ti, tcpiph_save;
 	struct ip *ip;
+	struct ip6 *ip6;
 	u_char opt[MAX_TCPOPTLEN];
 	unsigned optlen, hdrlen;
 	int idle, sendalot;
@@ -468,6 +469,21 @@ send:
 	    error = ip_output(so, m);
 	    break;
 
+	case AF_INET6:
+	    m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                         - sizeof(struct ip6);
+	    m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                         - sizeof(struct ip6);
+	    ip6 = mtod(m, struct ip6 *);
+
+	    ip6->ip_pl = tcpiph_save.ti_len;
+	    ip6->ip_dst = tcpiph_save.ti_dst6;
+	    ip6->ip_src = tcpiph_save.ti_src6;
+	    ip6->ip_nh = tcpiph_save.ti_nh6;
+
+	    error = ip6_output(so, m, 0);
+	    break;
+
 	default:
 	    g_assert_not_reached();
 	}
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index c16b29d..6991b21 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -88,6 +88,15 @@ tcp_template(struct tcpcb *tp)
 	    n->ti_dport = so->so_lport;
 	    break;
 
+	case AF_INET6:
+	    n->ti_nh6 = IPPROTO_TCP;
+	    n->ti_len = htons(sizeof(struct tcphdr));
+	    n->ti_src6 = so->so_faddr6;
+	    n->ti_dst6 = so->so_laddr6;
+	    n->ti_sport = so->so_fport6;
+	    n->ti_dport = so->so_lport6;
+	    break;
+
 	default:
 	    g_assert_not_reached();
 	}
@@ -156,6 +165,10 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 		    xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t);
 		    xchg(ti->ti_dport, ti->ti_sport, uint16_t);
 		    break;
+		case AF_INET6:
+		    xchg(ti->ti_dst6, ti->ti_src6, struct in6_addr);
+		    xchg(ti->ti_dport, ti->ti_sport, uint16_t);
+		    break;
 		default:
 		    g_assert_not_reached();
 		}
@@ -182,6 +195,7 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 
 	struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
 	struct ip *ip;
+	struct ip6 *ip6;
 
 	switch (af) {
 	case AF_INET:
@@ -204,6 +218,20 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 	    (void) ip_output((struct socket *)0, m);
 	    break;
 
+	case AF_INET6:
+	    m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                         - sizeof(struct ip6);
+	    m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                         - sizeof(struct ip6);
+	    ip6 = mtod(m, struct ip6 *);
+	    ip6->ip_pl = tlen;
+	    ip6->ip_dst = tcpiph_save.ti_dst6;
+	    ip6->ip_src = tcpiph_save.ti_src6;
+	    ip6->ip_nh = tcpiph_save.ti_nh6;
+
+	    (void) ip6_output((struct socket *)0, m, 0);
+	    break;
+
 	default:
 	    g_assert_not_reached();
 	}
@@ -225,7 +253,7 @@ tcp_newtcpcb(struct socket *so)
 
 	memset((char *) tp, 0, sizeof(struct tcpcb));
 	tp->seg_next = tp->seg_prev = (struct tcpiphdr*)tp;
-	tp->t_maxseg = TCP_MSS;
+	tp->t_maxseg = (so->so_ffamily == AF_INET) ? TCP_MSS : TCP6_MSS;
 
 	tp->t_flags = TCP_DO_RFC1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
 	tp->t_socket = so;
diff --git a/slirp/tcpip.h b/slirp/tcpip.h
index 3c5d127..124b4a9 100644
--- a/slirp/tcpip.h
+++ b/slirp/tcpip.h
@@ -45,6 +45,12 @@ struct tcpiphdr {
             uint8_t ih_x1;          /* (unused) */
             uint8_t ih_pr;          /* protocol */
         } ti_i4;
+        struct {
+            struct  in6_addr ih_src;
+            struct  in6_addr ih_dst;
+            uint8_t ih_x1;
+            uint8_t ih_nh;
+        } ti_i6;
     } ti;
     uint16_t    ti_x0;
     uint16_t    ti_len;             /* protocol length */
@@ -54,6 +60,9 @@ struct tcpiphdr {
 #define	ti_pr		ti.ti_i4.ih_pr
 #define	ti_src		ti.ti_i4.ih_src
 #define	ti_dst		ti.ti_i4.ih_dst
+#define	ti_src6		ti.ti_i6.ih_src
+#define	ti_dst6		ti.ti_i6.ih_dst
+#define	ti_nh6		ti.ti_i6.ih_nh
 #define	ti_sport	ti_t.th_sport
 #define	ti_dport	ti_t.th_dport
 #define	ti_seq		ti_t.th_seq
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [PATCHv7 8/9] slirp: Adding IPv6 address for DNS relay
  2016-02-14 17:47 [Qemu-devel] [PATCHv8 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (6 preceding siblings ...)
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 7/9] slirp: Handle IPv6 in TCP functions Samuel Thibault
@ 2016-02-14 17:47 ` Samuel Thibault
  2016-02-17  9:28   ` Thomas Huth
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses Samuel Thibault
  2016-02-16  8:47 ` [Qemu-devel] [PATCH] slirp: Add IPv6 support to the TFTP code Thomas Huth
  9 siblings, 1 reply; 38+ messages in thread
From: Samuel Thibault @ 2016-02-14 17:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei,
	Jan Kiszka, Samuel Thibault, Guillaume Subiron

From: Guillaume Subiron <maethor@subiron.org>

This patch adds an IPv6 address to the DNS relay. in6_equal_dns() is
developed using this Slirp attribute.
sotranslate_in/out/accept() are also updated to manage the IPv6 case so the
guest can be able to join the host using one of the Slirp addresses.

For now this only points to localhost. Further development will be needed to
automatically fetch the IPv6 address from resolv.conf, and announce this via
RDNSS.

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
 slirp/ip6.h    |  5 ++++-
 slirp/slirp.c  |  1 +
 slirp/slirp.h  |  1 +
 slirp/socket.c | 32 ++++++++++++++++++++++++++++++++
 4 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/slirp/ip6.h b/slirp/ip6.h
index 9f7623f..ded6d78 100644
--- a/slirp/ip6.h
+++ b/slirp/ip6.h
@@ -70,7 +70,10 @@ static inline bool in6_equal_mach(const struct in6_addr *a,
   || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)\
       && in6_equal_mach(a, &slirp->vhost_addr6, 64)))
 
-#define in6_equal_dns(a) 0
+#define in6_equal_dns(a)\
+    ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len)\
+     || in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64))\
+     && in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len))
 
 #define in6_equal_host(a)\
     (in6_equal_router(a) || in6_equal_dns(a))
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 2321c41..9e7e3a6 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -234,6 +234,7 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
     slirp->bootp_filename = g_strdup(bootfile);
     slirp->vdhcp_startaddr = vdhcp_start;
     slirp->vnameserver_addr = vnameserver;
+    inet_pton(AF_INET6, "fec0::3", &slirp->vnameserver_addr6);
 
     if (vdnssearch) {
         translate_dnssearch(slirp, vdnssearch);
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 967d93e..a830353 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -232,6 +232,7 @@ struct Slirp {
     struct in6_addr vhost_addr6;
     struct in_addr vdhcp_startaddr;
     struct in_addr vnameserver_addr;
+    struct in6_addr vnameserver_addr6;
 
     struct in_addr client_ipaddr;
     char client_hostname[33];
diff --git a/slirp/socket.c b/slirp/socket.c
index d4b02c8..0661fa9 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -747,6 +747,7 @@ void sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
 {
     Slirp *slirp = so->slirp;
     struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
 
     switch (addr->ss_family) {
     case AF_INET:
@@ -767,6 +768,19 @@ void sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
             ntohs(sin->sin_port), inet_ntoa(sin->sin_addr)));
         break;
 
+    case AF_INET6:
+        if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
+                    slirp->vprefix_len)) {
+            if (in6_equal(&so->so_faddr6, &slirp->vnameserver_addr6)) {
+                /*if (get_dns_addr(&addr) < 0) {*/ /* TODO */
+                    sin6->sin6_addr = in6addr_loopback;
+                /*}*/
+            } else {
+                sin6->sin6_addr = in6addr_loopback;
+            }
+        }
+        break;
+
     default:
         break;
     }
@@ -776,6 +790,7 @@ void sotranslate_in(struct socket *so, struct sockaddr_storage *addr)
 {
     Slirp *slirp = so->slirp;
     struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+    struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
 
     switch (addr->ss_family) {
     case AF_INET:
@@ -792,6 +807,16 @@ void sotranslate_in(struct socket *so, struct sockaddr_storage *addr)
         }
         break;
 
+    case AF_INET6:
+        if (in6_equal_net(&so->so_faddr6, &slirp->vprefix_addr6,
+                    slirp->vprefix_len)) {
+            if (in6_equal(&sin6->sin6_addr, &in6addr_loopback)
+                    || !in6_equal(&so->so_faddr6, &slirp->vhost_addr6)) {
+                sin6->sin6_addr = so->so_faddr6;
+            }
+        }
+        break;
+
     default:
         break;
     }
@@ -813,6 +838,13 @@ void sotranslate_accept(struct socket *so)
         }
         break;
 
+   case AF_INET6:
+        if (in6_equal(&so->so_faddr6, &in6addr_any) ||
+                in6_equal(&so->so_faddr6, &in6addr_loopback)) {
+           so->so_faddr6 = slirp->vhost_addr6;
+        }
+        break;
+
     default:
         break;
     }
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses
  2016-02-14 17:47 [Qemu-devel] [PATCHv8 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (7 preceding siblings ...)
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 8/9] slirp: Adding IPv6 address for DNS relay Samuel Thibault
@ 2016-02-14 17:47 ` Samuel Thibault
  2016-02-17 11:59   ` Thomas Huth
  2016-02-16  8:47 ` [Qemu-devel] [PATCH] slirp: Add IPv6 support to the TFTP code Thomas Huth
  9 siblings, 1 reply; 38+ messages in thread
From: Samuel Thibault @ 2016-02-14 17:47 UTC (permalink / raw)
  To: qemu-devel
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, Dave Gilbert, Vasiliy Tolstov, Huangpeng,
	Yann Bordenave, Gonglei, Jan Kiszka, Samuel Thibault,
	Guillaume Subiron

From: Yann Bordenave <meow@meowstars.org>

This patch adds parameters to manage some new options in the qemu -net
command.
Slirp IPv6 address, network prefix, and DNS IPv6 address can be given in
argument to the qemu command.
Defaults parameters are respectively fec0::2, fec0::, /64 and fec0::3.

Signed-off-by: Yann Bordenave <meow@meowstars.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
 net/net.c        | 31 +++++++++++++++++++++++++++++++
 net/slirp.c      | 50 ++++++++++++++++++++++++++++++++++++++++++++------
 qapi-schema.json | 40 ++++++++++++++++++++++++++--------------
 qemu-options.hx  | 18 ++++++++++++++++--
 slirp/libslirp.h |  8 +++++---
 slirp/slirp.c    | 16 +++++++++-------
 6 files changed, 131 insertions(+), 32 deletions(-)

diff --git a/net/net.c b/net/net.c
index c5e414f..a097971 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1060,6 +1060,37 @@ int net_client_init(QemuOpts *opts, int is_netdev, Error **errp)
     int ret = -1;
 
     {
+        /* Parse convenience option format ip6-net=fec0::0[/64] */
+        const char *ip6_net = qemu_opt_get(opts, "ip6-net");
+
+        if (ip6_net) {
+            char buf[strlen(ip6_net) + 1];
+
+            if (get_str_sep(buf, sizeof(buf), &ip6_net, '/') < 0) {
+                /* Default 64bit prefix length.  */
+                qemu_opt_set(opts, "ip6-prefix", ip6_net, &error_abort);
+                qemu_opt_set_number(opts, "ip6-prefixlen", 64, &error_abort);
+            } else {
+                /* User-specified prefix length.  */
+                unsigned long len;
+                int err;
+
+                qemu_opt_set(opts, "ip6-prefix", buf, &error_abort);
+                err = qemu_strtoul(ip6_net, NULL, 10, &len);
+
+                if (err) {
+                    error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+                              "ip6-prefix", "a number");
+                } else {
+                    qemu_opt_set_number(opts, "ip6-prefixlen", len,
+                                        &error_abort);
+                }
+            }
+            qemu_opt_unset(opts, "ip6-net");
+        }
+    }
+
+    {
         OptsVisitor *ov = opts_visitor_new(opts);
 
         net_visit(opts_get_visitor(ov), is_netdev, &object, &err);
diff --git a/net/slirp.c b/net/slirp.c
index 6b51fbc..076dd27 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -135,17 +135,23 @@ static NetClientInfo net_slirp_info = {
 static int net_slirp_init(NetClientState *peer, const char *model,
                           const char *name, int restricted,
                           const char *vnetwork, const char *vhost,
+                          const char *vprefix6, int vprefix6_len,
+                          const char *vhost6,
                           const char *vhostname, const char *tftp_export,
                           const char *bootfile, const char *vdhcp_start,
-                          const char *vnameserver, const char *smb_export,
-                          const char *vsmbserver, const char **dnssearch)
+                          const char *vnameserver, const char *vnameserver6,
+                          const char *smb_export, const char *vsmbserver,
+                          const char **dnssearch)
 {
     /* default settings according to historic slirp */
     struct in_addr net  = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
     struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
     struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
+    struct in6_addr ip6_prefix;
+    struct in6_addr ip6_host;
     struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
     struct in_addr dns  = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
+    struct in6_addr ip6_dns;
 #ifndef _WIN32
     struct in_addr smbsrv = { .s_addr = 0 };
 #endif
@@ -213,6 +219,27 @@ static int net_slirp_init(NetClientState *peer, const char *model,
         return -1;
     }
 
+    if (!vprefix6) {
+        vprefix6 = "fec0::";
+    }
+    if (!inet_pton(AF_INET6, vprefix6, &ip6_prefix)) {
+        return -1;
+    }
+
+    if (!vprefix6_len) {
+        vprefix6_len = 64;
+    }
+    if (vprefix6_len < 0 || vprefix6_len > 128) {
+        return -1;
+    }
+
+    if (!vhost6) {
+        vhost6 = "fec0::2";
+    }
+    if (!inet_pton(AF_INET6, vhost6, &ip6_host)) {
+        return -1;
+    }
+
     if (vnameserver && !inet_aton(vnameserver, &dns)) {
         return -1;
     }
@@ -221,6 +248,13 @@ static int net_slirp_init(NetClientState *peer, const char *model,
         return -1;
     }
 
+    if (!vnameserver6) {
+        vnameserver6 = "fec0::3";
+    }
+    if (!inet_pton(AF_INET6, vnameserver6, &ip6_dns)) {
+        return -1;
+    }
+
     if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) {
         return -1;
     }
@@ -243,8 +277,10 @@ static int net_slirp_init(NetClientState *peer, const char *model,
 
     s = DO_UPCAST(SlirpState, nc, nc);
 
-    s->slirp = slirp_init(restricted, net, mask, host, vhostname,
-                          tftp_export, bootfile, dhcp, dns, dnssearch, s);
+    s->slirp = slirp_init(restricted, net, mask, host,
+                          ip6_prefix, vprefix6_len, ip6_host,
+                          vhostname, tftp_export, bootfile, dhcp,
+                          dns, ip6_dns, dnssearch, s);
     QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
 
     for (config = slirp_configs; config; config = config->next) {
@@ -761,8 +797,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->hostname, user->tftp,
-                         user->bootfile, user->dhcpstart, user->dns, user->smb,
+                         user->host, user->ip6_prefix, user->ip6_prefixlen,
+                         user->ip6_host, user->hostname, user->tftp,
+                         user->bootfile, user->dhcpstart,
+                         user->dns, user->ip6_dns, user->smb,
                          user->smbserver, dnssearch);
 
     while (slirp_configs) {
diff --git a/qapi-schema.json b/qapi-schema.json
index 8d04897..a62c2ec 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2399,6 +2399,14 @@
 # @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)
+#
+# @ip6-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)
+#
+# @ip6-dns: #optional guest-visible IPv6 address of the virtual nameserver (since 2.6)
+#
 # @smb: #optional root directory of the built-in SMB server
 #
 # @smbserver: #optional IP address of the built-in SMB server
@@ -2412,20 +2420,24 @@
 ##
 { 'struct': 'NetdevUserOptions',
   'data': {
-    '*hostname':  'str',
-    '*restrict':  'bool',
-    '*ip':        'str',
-    '*net':       'str',
-    '*host':      'str',
-    '*tftp':      'str',
-    '*bootfile':  'str',
-    '*dhcpstart': 'str',
-    '*dns':       'str',
-    '*dnssearch': ['String'],
-    '*smb':       'str',
-    '*smbserver': 'str',
-    '*hostfwd':   ['String'],
-    '*guestfwd':  ['String'] } }
+    '*hostname':        'str',
+    '*restrict':        'bool',
+    '*ip':              'str',
+    '*net':             'str',
+    '*host':            'str',
+    '*tftp':            'str',
+    '*bootfile':        'str',
+    '*dhcpstart':       'str',
+    '*dns':             'str',
+    '*dnssearch':       ['String'],
+    '*ip6-prefix':      'str',
+    '*ip6-prefixlen':   'int',
+    '*ip6-host':        'str',
+    '*ip6-dns':         'str',
+    '*smb':             'str',
+    '*smbserver':       'str',
+    '*hostfwd':         ['String'],
+    '*guestfwd':        ['String'] } }
 
 ##
 # @NetdevTapOptions
diff --git a/qemu-options.hx b/qemu-options.hx
index 733a194..de9e314 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1542,8 +1542,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][,restrict=on|off]\n"
-    "         [,hostname=host][,dhcpstart=addr][,dns=addr][,dnssearch=domain][,tftp=dir]\n"
+    "-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"
     "         [,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
 #ifndef _WIN32
                                              "[,smb=dir[,smbserver=addr]]\n"
@@ -1700,6 +1701,14 @@ 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 ip6-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.
+
 @item restrict=on|off
 If this option is enabled, the guest will be isolated, i.e. it will not be
 able to contact the host and no guest IP packets will be routed over the host
@@ -1717,6 +1726,11 @@ 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}
+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.
+
 @item dnssearch=@var{domain}
 Provides an entry for the domain-search list sent by the built-in
 DHCP server. More than one domain suffix can be transmitted by specifying
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index 5bdcbd5..c4b25c9 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -10,9 +10,11 @@ int get_dns_addr(struct in_addr *pdns_addr);
 
 Slirp *slirp_init(int restricted, struct in_addr vnetwork,
                   struct in_addr vnetmask, struct in_addr vhost,
-                  const char *vhostname, const char *tftp_path,
-                  const char *bootfile, struct in_addr vdhcp_start,
-                  struct in_addr vnameserver, const char **vdnssearch,
+                  struct in6_addr vprefix_addr6, uint8_t vprefix_len,
+                  struct in6_addr vhost6, const char *vhostname,
+                  const char *tftp_path, const char *bootfile,
+                  struct in_addr vdhcp_start, struct in_addr vnameserver,
+                  struct in6_addr vnameserver6, const char **vdnssearch,
                   void *opaque);
 void slirp_cleanup(Slirp *slirp);
 
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 9e7e3a6..a6664f8 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -201,9 +201,11 @@ static int slirp_state_load(QEMUFile *f, void *opaque, int version_id);
 
 Slirp *slirp_init(int restricted, struct in_addr vnetwork,
                   struct in_addr vnetmask, struct in_addr vhost,
-                  const char *vhostname, const char *tftp_path,
-                  const char *bootfile, struct in_addr vdhcp_start,
-                  struct in_addr vnameserver, const char **vdnssearch,
+                  struct in6_addr vprefix_addr6, uint8_t vprefix_len,
+                  struct in6_addr vhost6, const char *vhostname,
+                  const char *tftp_path, const char *bootfile,
+                  struct in_addr vdhcp_start, struct in_addr vnameserver,
+                  struct in6_addr vnameserver6, const char **vdnssearch,
                   void *opaque)
 {
     Slirp *slirp = g_malloc0(sizeof(Slirp));
@@ -223,9 +225,9 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
     slirp->vnetwork_addr = vnetwork;
     slirp->vnetwork_mask = vnetmask;
     slirp->vhost_addr = vhost;
-    inet_pton(AF_INET6, "fec0::0", &slirp->vprefix_addr6);
-    slirp->vprefix_len = 64;
-    inet_pton(AF_INET6, "fec0::2", &slirp->vhost_addr6);
+    slirp->vprefix_addr6 = vprefix_addr6;
+    slirp->vprefix_len = vprefix_len;
+    slirp->vhost_addr6 = vhost6;
     if (vhostname) {
         pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
                 vhostname);
@@ -234,7 +236,7 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
     slirp->bootp_filename = g_strdup(bootfile);
     slirp->vdhcp_startaddr = vdhcp_start;
     slirp->vnameserver_addr = vnameserver;
-    inet_pton(AF_INET6, "fec0::3", &slirp->vnameserver_addr6);
+    slirp->vnameserver_addr6 = vnameserver6;
 
     if (vdnssearch) {
         translate_dnssearch(slirp, vdnssearch);
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* [Qemu-devel] [PATCH] slirp: Add IPv6 support to the TFTP code
  2016-02-14 17:47 [Qemu-devel] [PATCHv8 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (8 preceding siblings ...)
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses Samuel Thibault
@ 2016-02-16  8:47 ` Thomas Huth
  2016-02-16 10:30   ` Samuel Thibault
  2016-02-17  8:40   ` [Qemu-devel] [PATCH v2] " Thomas Huth
  9 siblings, 2 replies; 38+ messages in thread
From: Thomas Huth @ 2016-02-16  8:47 UTC (permalink / raw)
  To: qemu-devel, samuel.thibault, jan.kiszka; +Cc: jasowang

Add the handler code for incoming TFTP packets to udp6_input(),
and make sure that the TFTP code can send packets with both,
udp_output() and udp6_output() by introducing a wrapper function
called tftp_udp_output().

Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 This patch has to be applied on top of Samuel's "slirp: Adding IPv6
 support to Qemu -net user mode" patch series.
 Samuel, if you respin your patch series and if you think this patch
 is ok, feel free to also include it in your series.

 Code has been tested with network booting in SLOF:

  qemu-system-ppc64 -vga none -device virtio-net,netdev=mynet \
     -netdev user,id=mynet,tftp=/home/thuth/tmp/tftp -nographic

 ... and then, at the Open Firmware prompt, type:

  boot net:ipv6,fec0::2,zImage,fec0::1234

---
 slirp/tftp.c | 134 +++++++++++++++++++++++++++++++++--------------------------
 slirp/tftp.h |   7 ++--
 slirp/udp.c  |  16 ++++---
 slirp/udp6.c |  16 +++++--
 4 files changed, 101 insertions(+), 72 deletions(-)

diff --git a/slirp/tftp.c b/slirp/tftp.c
index abb0106..ab1c425 100644
--- a/slirp/tftp.c
+++ b/slirp/tftp.c
@@ -46,7 +46,8 @@ static void tftp_session_terminate(struct tftp_session *spt)
     spt->slirp = NULL;
 }
 
-static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
+static int tftp_session_allocate(struct sockaddr_storage *srcsas, Slirp *slirp,
+                                 struct tftp_t *tp)
 {
   struct tftp_session *spt;
   int k;
@@ -68,7 +69,7 @@ static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
 
  found:
   memset(spt, 0, sizeof(*spt));
-  memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip));
+  memcpy(&spt->client_addr, srcsas, sizeof(*srcsas));
   spt->fd = -1;
   spt->client_port = tp->udp.uh_sport;
   spt->slirp = slirp;
@@ -78,7 +79,8 @@ static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
   return k;
 }
 
-static int tftp_session_find(Slirp *slirp, struct tftp_t *tp)
+static int tftp_session_find(struct sockaddr_storage *srcsas, Slirp *slirp,
+                             struct tftp_t *tp)
 {
   struct tftp_session *spt;
   int k;
@@ -87,7 +89,7 @@ static int tftp_session_find(Slirp *slirp, struct tftp_t *tp)
     spt = &slirp->tftp_sessions[k];
 
     if (tftp_session_in_use(spt)) {
-      if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) {
+      if (sockaddr_equal(&spt->client_addr, srcsas)) {
 	if (spt->client_port == tp->udp.uh_sport) {
 	  return k;
 	}
@@ -120,11 +122,54 @@ static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr,
     return bytes_read;
 }
 
+static struct tftp_t *tftp_prep_mbuf_data(struct tftp_session *spt,
+                                          struct mbuf *m)
+{
+    struct tftp_t *tp;
+
+    memset(m->m_data, 0, m->m_size);
+
+    m->m_data += IF_MAXLINKHDR;
+    if (spt->client_addr.ss_family == AF_INET6) {
+        m->m_data += sizeof(struct ip6);
+    } else {
+        m->m_data += sizeof(struct ip);
+    }
+    tp = (void *)m->m_data;
+    m->m_data += sizeof(struct udphdr);
+
+    return tp;
+}
+
+static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
+                            struct tftp_t *recv_tp)
+{
+    if (spt->client_addr.ss_family == AF_INET6) {
+        struct sockaddr_in6 sa6, da6;
+
+        memcpy(&sa6.sin6_addr, spt->slirp->vhost_addr6.s6_addr, 16);
+        sa6.sin6_port = recv_tp->udp.uh_dport;
+        memcpy(&da6.sin6_addr,
+               &((struct sockaddr_in6 *)&spt->client_addr)->sin6_addr, 16);
+        da6.sin6_port = spt->client_port;
+
+        udp6_output(NULL, m, &sa6, &da6);
+    } else {
+        struct sockaddr_in sa4, da4;
+
+        sa4.sin_addr = spt->slirp->vhost_addr;
+        sa4.sin_port = recv_tp->udp.uh_dport;
+        da4.sin_addr = ((struct sockaddr_in *)&spt->client_addr)->sin_addr;
+        da4.sin_port = spt->client_port;
+
+        udp_output(NULL, m, &sa4, &da4, IPTOS_LOWDELAY);
+    }
+}
+
 static int tftp_send_oack(struct tftp_session *spt,
                           const char *keys[], uint32_t values[], int nb,
                           struct tftp_t *recv_tp)
 {
-    struct sockaddr_in saddr, daddr;
     struct mbuf *m;
     struct tftp_t *tp;
     int i, n = 0;
@@ -132,13 +177,9 @@ static int tftp_send_oack(struct tftp_session *spt,
     m = m_get(spt->slirp);
 
     if (!m)
-	return -1;
-
-    memset(m->m_data, 0, m->m_size);
+        return -1;
 
-    m->m_data += IF_MAXLINKHDR;
-    tp = (void *)m->m_data;
-    m->m_data += sizeof(struct udpiphdr);
+    tp = tftp_prep_mbuf_data(spt, m);
 
     tp->tp_op = htons(TFTP_OACK);
     for (i = 0; i < nb; i++) {
@@ -148,15 +189,8 @@ static int tftp_send_oack(struct tftp_session *spt,
                       values[i]) + 1;
     }
 
-    saddr.sin_addr = recv_tp->ip.ip_dst;
-    saddr.sin_port = recv_tp->udp.uh_dport;
-
-    daddr.sin_addr = spt->client_ip;
-    daddr.sin_port = spt->client_port;
-
-    m->m_len = sizeof(struct tftp_t) - 514 + n -
-        sizeof(struct ip) - sizeof(struct udphdr);
-    udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+    m->m_len = sizeof(struct tftp_t) - 514 + n - sizeof(struct udphdr);
+    tftp_udp_output(spt, m, recv_tp);
 
     return 0;
 }
@@ -165,7 +199,6 @@ static void tftp_send_error(struct tftp_session *spt,
                             uint16_t errorcode, const char *msg,
                             struct tftp_t *recv_tp)
 {
-  struct sockaddr_in saddr, daddr;
   struct mbuf *m;
   struct tftp_t *tp;
 
@@ -177,24 +210,15 @@ static void tftp_send_error(struct tftp_session *spt,
 
   memset(m->m_data, 0, m->m_size);
 
-  m->m_data += IF_MAXLINKHDR;
-  tp = (void *)m->m_data;
-  m->m_data += sizeof(struct udpiphdr);
+  tp = tftp_prep_mbuf_data(spt, m);
 
   tp->tp_op = htons(TFTP_ERROR);
   tp->x.tp_error.tp_error_code = htons(errorcode);
   pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg);
 
-  saddr.sin_addr = recv_tp->ip.ip_dst;
-  saddr.sin_port = recv_tp->udp.uh_dport;
-
-  daddr.sin_addr = spt->client_ip;
-  daddr.sin_port = spt->client_port;
-
-  m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
-        sizeof(struct ip) - sizeof(struct udphdr);
-
-  udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+  m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg)
+             - sizeof(struct udphdr);
+  tftp_udp_output(spt, m, recv_tp);
 
 out:
   tftp_session_terminate(spt);
@@ -203,7 +227,6 @@ out:
 static void tftp_send_next_block(struct tftp_session *spt,
                                  struct tftp_t *recv_tp)
 {
-  struct sockaddr_in saddr, daddr;
   struct mbuf *m;
   struct tftp_t *tp;
   int nobytes;
@@ -216,19 +239,11 @@ static void tftp_send_next_block(struct tftp_session *spt,
 
   memset(m->m_data, 0, m->m_size);
 
-  m->m_data += IF_MAXLINKHDR;
-  tp = (void *)m->m_data;
-  m->m_data += sizeof(struct udpiphdr);
+  tp = tftp_prep_mbuf_data(spt, m);
 
   tp->tp_op = htons(TFTP_DATA);
   tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff);
 
-  saddr.sin_addr = recv_tp->ip.ip_dst;
-  saddr.sin_port = recv_tp->udp.uh_dport;
-
-  daddr.sin_addr = spt->client_ip;
-  daddr.sin_port = spt->client_port;
-
   nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf, 512);
 
   if (nobytes < 0) {
@@ -241,10 +256,8 @@ static void tftp_send_next_block(struct tftp_session *spt,
     return;
   }
 
-  m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
-        sizeof(struct ip) - sizeof(struct udphdr);
-
-  udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+  m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - sizeof(struct udphdr);
+  tftp_udp_output(spt, m, recv_tp);
 
   if (nobytes == 512) {
     tftp_session_update(spt);
@@ -256,7 +269,8 @@ static void tftp_send_next_block(struct tftp_session *spt,
   spt->block_nr++;
 }
 
-static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
+static void tftp_handle_rrq(struct sockaddr_storage *srcsas, Slirp *slirp,
+                            struct tftp_t *tp, int pktlen)
 {
   struct tftp_session *spt;
   int s, k;
@@ -267,12 +281,12 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
   int nb_options = 0;
 
   /* check if a session already exists and if so terminate it */
-  s = tftp_session_find(slirp, tp);
+  s = tftp_session_find(srcsas, slirp, tp);
   if (s >= 0) {
     tftp_session_terminate(&slirp->tftp_sessions[s]);
   }
 
-  s = tftp_session_allocate(slirp, tp);
+  s = tftp_session_allocate(srcsas, slirp, tp);
 
   if (s < 0) {
     return;
@@ -397,11 +411,12 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
   tftp_send_next_block(spt, tp);
 }
 
-static void tftp_handle_ack(Slirp *slirp, struct tftp_t *tp, int pktlen)
+static void tftp_handle_ack(struct sockaddr_storage *srcsas, Slirp *slirp,
+                            struct tftp_t *tp, int pktlen)
 {
   int s;
 
-  s = tftp_session_find(slirp, tp);
+  s = tftp_session_find(srcsas, slirp, tp);
 
   if (s < 0) {
     return;
@@ -410,11 +425,12 @@ static void tftp_handle_ack(Slirp *slirp, struct tftp_t *tp, int pktlen)
   tftp_send_next_block(&slirp->tftp_sessions[s], tp);
 }
 
-static void tftp_handle_error(Slirp *slirp, struct tftp_t *tp, int pktlen)
+static void tftp_handle_error(struct sockaddr_storage *srcsas, Slirp *slirp,
+                              struct tftp_t *tp, int pktlen)
 {
   int s;
 
-  s = tftp_session_find(slirp, tp);
+  s = tftp_session_find(srcsas, slirp, tp);
 
   if (s < 0) {
     return;
@@ -423,21 +439,21 @@ static void tftp_handle_error(Slirp *slirp, struct tftp_t *tp, int pktlen)
   tftp_session_terminate(&slirp->tftp_sessions[s]);
 }
 
-void tftp_input(struct mbuf *m)
+void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m)
 {
   struct tftp_t *tp = (struct tftp_t *)m->m_data;
 
   switch(ntohs(tp->tp_op)) {
   case TFTP_RRQ:
-    tftp_handle_rrq(m->slirp, tp, m->m_len);
+    tftp_handle_rrq(srcsas, m->slirp, tp, m->m_len);
     break;
 
   case TFTP_ACK:
-    tftp_handle_ack(m->slirp, tp, m->m_len);
+    tftp_handle_ack(srcsas, m->slirp, tp, m->m_len);
     break;
 
   case TFTP_ERROR:
-    tftp_handle_error(m->slirp, tp, m->m_len);
+    tftp_handle_error(srcsas, m->slirp, tp, m->m_len);
     break;
   }
 }
diff --git a/slirp/tftp.h b/slirp/tftp.h
index e1cc24b..1cb1adf 100644
--- a/slirp/tftp.h
+++ b/slirp/tftp.h
@@ -16,7 +16,6 @@
 #define TFTP_FILENAME_MAX 512
 
 struct tftp_t {
-  struct ip ip;
   struct udphdr udp;
   uint16_t tp_op;
   union {
@@ -30,20 +29,20 @@ struct tftp_t {
     } tp_error;
     char tp_buf[512 + 2];
   } x;
-};
+} __attribute__((packed));
 
 struct tftp_session {
     Slirp *slirp;
     char *filename;
     int fd;
 
-    struct in_addr client_ip;
+    struct sockaddr_storage client_addr;
     uint16_t client_port;
     uint32_t block_nr;
 
     int timestamp;
 };
 
-void tftp_input(struct mbuf *m);
+void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m);
 
 #endif
diff --git a/slirp/udp.c b/slirp/udp.c
index be012fb..247024f 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -128,6 +128,11 @@ udp_input(register struct mbuf *m, int iphlen)
 	  }
 	}
 
+	lhost.ss_family = AF_INET;
+	lhost4 = (struct sockaddr_in *) &lhost;
+	lhost4->sin_addr = ip->ip_src;
+	lhost4->sin_port = uh->uh_sport;
+
         /*
          *  handle DHCP/BOOTP
          */
@@ -143,7 +148,11 @@ udp_input(register struct mbuf *m, int iphlen)
          */
         if (ntohs(uh->uh_dport) == TFTP_SERVER &&
             ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
-            tftp_input(m);
+            m->m_data += iphlen;
+            m->m_len -= iphlen;
+            tftp_input(&lhost, m);
+            m->m_data -= iphlen;
+            m->m_len += iphlen;
             goto bad;
         }
 
@@ -154,11 +163,6 @@ udp_input(register struct mbuf *m, int iphlen)
 	/*
 	 * Locate pcb for datagram.
 	 */
-	lhost.ss_family = AF_INET;
-	lhost4 = (struct sockaddr_in *) &lhost;
-	lhost4->sin_addr = ip->ip_src;
-	lhost4->sin_port = uh->uh_sport;
-
 	so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL);
 
 	if (so == NULL) {
diff --git a/slirp/udp6.c b/slirp/udp6.c
index 6c0d55f..820192a 100644
--- a/slirp/udp6.c
+++ b/slirp/udp6.c
@@ -55,14 +55,24 @@ void udp6_input(struct mbuf *m)
      */
     save_ip = *ip;
 
-    /* TODO handle DHCP/BOOTP */
-    /* TODO handle TFTP */
-
     /* Locate pcb for datagram. */
     lhost.sin6_family = AF_INET6;
     lhost.sin6_addr = ip->ip_src;
     lhost.sin6_port = uh->uh_sport;
 
+    /* TODO handle DHCP/BOOTP */
+
+    /* handle TFTP */
+    if (ntohs(uh->uh_dport) == TFTP_SERVER &&
+        !memcmp(ip->ip_dst.s6_addr, slirp->vhost_addr6.s6_addr, 16)) {
+        m->m_data += hlen;
+        m->m_len -= hlen;
+        tftp_input((struct sockaddr_storage *)&lhost, m);
+        m->m_data -= hlen;
+        m->m_len += hlen;
+        goto bad;
+    }
+
     so = solookup(&slirp->udp_last_so, &slirp->udb,
                   (struct sockaddr_storage *) &lhost, NULL);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCH] slirp: Add IPv6 support to the TFTP code
  2016-02-16  8:47 ` [Qemu-devel] [PATCH] slirp: Add IPv6 support to the TFTP code Thomas Huth
@ 2016-02-16 10:30   ` Samuel Thibault
  2016-02-16 12:09     ` Thomas Huth
  2016-02-17  8:40   ` [Qemu-devel] [PATCH v2] " Thomas Huth
  1 sibling, 1 reply; 38+ messages in thread
From: Samuel Thibault @ 2016-02-16 10:30 UTC (permalink / raw)
  To: Thomas Huth; +Cc: jan.kiszka, jasowang, qemu-devel

Hello,

Thanks for working on it :)

Thomas Huth, on Tue 16 Feb 2016 09:47:38 +0100, wrote:
> -static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
> +static int tftp_session_allocate(struct sockaddr_storage *srcsas, Slirp *slirp,
> +                                 struct tftp_t *tp)

slirp is usually the first parameter, it'd probably be better to keep
this habit.

> -static int tftp_session_find(Slirp *slirp, struct tftp_t *tp)
> +static int tftp_session_find(struct sockaddr_storage *srcsas, Slirp *slirp,
> +                             struct tftp_t *tp)

ditto.

> +static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
> +                            struct tftp_t *recv_tp)
> +{
> +    if (spt->client_addr.ss_family == AF_INET6) {
> +        struct sockaddr_in6 sa6, da6;
> +
> +        memcpy(&sa6.sin6_addr, spt->slirp->vhost_addr6.s6_addr, 16);

Why not simply sa6.sin6_addr = spt->slirp->vhost_addr6?

The compiler will optimize the structure assignment as an inline copy or
memcpy call as appropriate.

> +        sa6.sin6_port = recv_tp->udp.uh_dport;
> +        memcpy(&da6.sin6_addr,
> +               &((struct sockaddr_in6 *)&spt->client_addr)->sin6_addr, 16);

ditto.

Otherwise the patch looks particularly good :)

Samuel

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
@ 2016-02-16 11:36   ` Thomas Huth
  2016-02-19 13:57   ` Thomas Huth
  1 sibling, 0 replies; 38+ messages in thread
From: Thomas Huth @ 2016-02-16 11:36 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei, Jan Kiszka,
	Guillaume Subiron

On 14.02.2016 18:47, Samuel Thibault wrote:
> From: Guillaume Subiron <maethor@subiron.org>
> 
> This patch adds the functions needed to handle IPv6 packets. ICMPv6 and
> NDP headers are implemented.
> 
> Slirp is now able to send NDP Router or Neighbor Advertisement when it
> receives Router or Neighbor Solicitation. Using a 64bit-sized IPv6
> prefix, the guest is now able to perform stateless autoconfiguration
> (SLAAC) and to compute its IPv6 address.
> 
> This patch adds an ndp_table, mainly inspired by arp_table, to keep an
> NDP cache and manage network address resolution.
> Slirp regularly sends NDP Neighbor Advertisement, as recommended by the
> RFC, to make the guest refresh its route.
> 
> This also adds ip6_cksum() to compute ICMPv6 checksums using IPv6
> pseudo-header.
> 
> Some #define ETH_* are moved upper in slirp.h to make them accessible to
> other slirp/*.h
> 
> Signed-off-by: Guillaume Subiron <maethor@subiron.org>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
>  slirp/Makefile.objs |   6 +-
>  slirp/cksum.c       |  25 ++++
>  slirp/if.c          |   2 +-
>  slirp/ip6.h         | 135 ++++++++++++++++++++
>  slirp/ip6_icmp.c    | 347 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  slirp/ip6_icmp.h    | 203 ++++++++++++++++++++++++++++++
>  slirp/ip6_input.c   |  69 +++++++++++
>  slirp/ip6_output.c  |  38 ++++++
>  slirp/ndp_table.c   |  84 +++++++++++++
>  slirp/slirp.c       |  49 +++++++-
>  slirp/slirp.h       |  37 ++++++
>  slirp/socket.h      |   7 ++
>  12 files changed, 996 insertions(+), 6 deletions(-)
>  create mode 100644 slirp/ip6.h
>  create mode 100644 slirp/ip6_icmp.c
>  create mode 100644 slirp/ip6_icmp.h
>  create mode 100644 slirp/ip6_input.c
>  create mode 100644 slirp/ip6_output.c
>  create mode 100644 slirp/ndp_table.c

Patch looks fine to me now.

Reviewed-by: Thomas Huth <thuth@redhat.com>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCH] slirp: Add IPv6 support to the TFTP code
  2016-02-16 10:30   ` Samuel Thibault
@ 2016-02-16 12:09     ` Thomas Huth
  0 siblings, 0 replies; 38+ messages in thread
From: Thomas Huth @ 2016-02-16 12:09 UTC (permalink / raw)
  To: Samuel Thibault; +Cc: jan.kiszka, jasowang, qemu-devel

On 16.02.2016 11:30, Samuel Thibault wrote:
> Hello,
> 
> Thanks for working on it :)
> 
> Thomas Huth, on Tue 16 Feb 2016 09:47:38 +0100, wrote:
>> -static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
>> +static int tftp_session_allocate(struct sockaddr_storage *srcsas, Slirp *slirp,
>> +                                 struct tftp_t *tp)
> 
> slirp is usually the first parameter, it'd probably be better to keep
> this habit.

Ok, I don't have a preference here, so I'll change it.

>> -static int tftp_session_find(Slirp *slirp, struct tftp_t *tp)
>> +static int tftp_session_find(struct sockaddr_storage *srcsas, Slirp *slirp,
>> +                             struct tftp_t *tp)
> 
> ditto.
> 
>> +static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
>> +                            struct tftp_t *recv_tp)
>> +{
>> +    if (spt->client_addr.ss_family == AF_INET6) {
>> +        struct sockaddr_in6 sa6, da6;
>> +
>> +        memcpy(&sa6.sin6_addr, spt->slirp->vhost_addr6.s6_addr, 16);
> 
> Why not simply sa6.sin6_addr = spt->slirp->vhost_addr6?
> 
> The compiler will optimize the structure assignment as an inline copy or
> memcpy call as appropriate.

That makes sense, too, I'll change it.

Thanks for the review!

 Thomas

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 2/9] slirp: Adding ICMPv6 error sending
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 2/9] slirp: Adding ICMPv6 error sending Samuel Thibault
@ 2016-02-16 12:21   ` Thomas Huth
  0 siblings, 0 replies; 38+ messages in thread
From: Thomas Huth @ 2016-02-16 12:21 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, Huangpeng, Yann Bordenave,
	Gonglei, Jan Kiszka, Guillaume Subiron

On 14.02.2016 18:47, Samuel Thibault wrote:
> From: Yann Bordenave <meow@meowstars.org>
> 
> Disambiguation : icmp_error is renamed into icmp_send_error, since it
> doesn't manage errors, but only sends ICMP Error messages.
> 
> Adding icmp6_send_error to send ICMPv6 Error messages. This function is
> simpler than the v4 version.
> Adding some calls in various functions to send ICMP errors, when a
> received packet is too big, or when its hop limit is 0.
> 
> Signed-off-by: Yann Bordenave <meow@meowstars.org>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
>  slirp/ip6_icmp.c  | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  slirp/ip6_icmp.h  | 10 +++++++++
>  slirp/ip6_input.c | 13 ++++++-----
>  slirp/ip_icmp.c   | 12 +++++------
>  slirp/ip_icmp.h   |  4 ++--
>  slirp/ip_input.c  |  8 +++----
>  slirp/socket.c    |  4 ++--
>  slirp/tcp_input.c |  2 +-
>  slirp/udp.c       |  3 ++-
>  9 files changed, 99 insertions(+), 21 deletions(-)

Reviewed-by: Thomas Huth <thuth@redhat.com>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support Samuel Thibault
@ 2016-02-16 12:28   ` Thomas Huth
  0 siblings, 0 replies; 38+ messages in thread
From: Thomas Huth @ 2016-02-16 12:28 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei, Jan Kiszka,
	Guillaume Subiron

On 14.02.2016 18:47, Samuel Thibault wrote:
> From: Guillaume Subiron <maethor@subiron.org>
> 
> This adds the sin6 case in the fhost and lhost unions and related macros.
> It adds udp6_input() and udp6_output().
> It adds the IPv6 case in sorecvfrom().
> Finally, udp_input() is called by ip6_input().
> 
> Signed-off-by: Guillaume Subiron <maethor@subiron.org>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
>  slirp/Makefile.objs |   2 +-
>  slirp/ip6_input.c   |   2 +-
>  slirp/socket.c      |   5 ++
>  slirp/socket.h      |   6 ++
>  slirp/udp.h         |   5 ++
>  slirp/udp6.c        | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 174 insertions(+), 2 deletions(-)
>  create mode 100644 slirp/udp6.c
...
> diff --git a/slirp/udp6.c b/slirp/udp6.c
> new file mode 100644
> index 0000000..6c0d55f
> --- /dev/null
> +++ b/slirp/udp6.c
...
> +int udp6_output(struct socket *so, struct mbuf *m,
> +        struct sockaddr_in6 *saddr, struct sockaddr_in6 *daddr)
> +{
> +    struct ip6 *ip;
> +    struct udphdr *uh;
> +
> +    DEBUG_CALL("udp6_output");
> +    DEBUG_ARG("so = %lx", (long)so);
> +    DEBUG_ARG("m = %lx", (long)m);
> +
> +    /* adjust for header */
> +    m->m_data -= sizeof(struct udphdr);
> +    m->m_len += sizeof(struct udphdr);
> +    uh = mtod(m, struct udphdr *);
> +    m->m_data -= sizeof(struct ip6);
> +    m->m_len += sizeof(struct ip6);
> +    ip = mtod(m, struct ip6 *);
> +
> +    /* Build IP header */
> +    ip->ip_pl = htons(m->m_len - sizeof(struct ip6));
> +    ip->ip_nh = IPPROTO_UDP;
> +    ip->ip_src = saddr->sin6_addr;
> +    ip->ip_dst = daddr->sin6_addr;
> +
> +    /* Build UDP header */
> +    uh->uh_sport = saddr->sin6_port;
> +    uh->uh_dport = daddr->sin6_port;
> +    uh->uh_ulen = ip->ip_pl;
> +    uh->uh_sum = 0;
> +    uh->uh_sum = ip6_cksum(m);
> +    if (uh->uh_sum == 0)
> +        uh->uh_sum = 0xffff;

Nit: QEMU coding style requires braces for all if-statements.

> +    return ip6_output(so, m, 0);
> +}

When you've fixed the small nit, feel free to add my:

Reviewed-by: Thomas Huth <thuth@redhat.com>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 5/9] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 5/9] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff Samuel Thibault
@ 2016-02-17  8:25   ` Thomas Huth
  0 siblings, 0 replies; 38+ messages in thread
From: Thomas Huth @ 2016-02-17  8:25 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei, Jan Kiszka,
	Guillaume Subiron

On 14.02.2016 18:47, Samuel Thibault wrote:
> From: Guillaume Subiron <maethor@subiron.org>
> 
> Basically, this patch adds some switch in various TCP functions to
> prepare them for the IPv6 case.
> 
> To have something to "switch" in tcp_input() and tcp_respond(), a new
> argument is used to give them the sa_family of the addresses they are
> working on.
> 
> This patch does not include the entailed reindentation, to make proofread
> easier. Reindentation is adressed in the following no-op patch.
> 
> Signed-off-by: Guillaume Subiron <maethor@subiron.org>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
...
> diff --git a/slirp/slirp.c b/slirp/slirp.c
> index c2c4597..2321c41 100644
> --- a/slirp/slirp.c
> +++ b/slirp/slirp.c
> @@ -574,7 +574,8 @@ void slirp_pollfds_poll(GArray *pollfds, int select_error)
>                          /*
>                           * Continue tcp_input
>                           */
> -                        tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
> +                        tcp_input((struct mbuf *)NULL, sizeof(struct ip), so,
> +                                so->so_ffamily);

Cosmetic nit: indentation of "so->so_ffamily" should IMHO use two more
spaces.

>                          /* continue; */
>                      } else {
>                          ret = sowrite(so);
> @@ -623,7 +624,8 @@ void slirp_pollfds_poll(GArray *pollfds, int select_error)
>                          }
>  
>                      }
> -                    tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
> +                    tcp_input((struct mbuf *)NULL, sizeof(struct ip), so,
> +                            so->so_ffamily);

dito

>                  } /* SS_ISFCONNECTING */
>  #endif
>              }
...
> diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
> index 7fc6a87..1e5da73 100644
> --- a/slirp/tcp_output.c
> +++ b/slirp/tcp_output.c
> @@ -61,7 +61,8 @@ tcp_output(struct tcpcb *tp)
>  	register long len, win;
>  	int off, flags, error;
>  	register struct mbuf *m;
> -	register struct tcpiphdr *ti;
> +	register struct tcpiphdr *ti, tcpiph_save;
> +	struct ip *ip;
>  	u_char opt[MAX_TCPOPTLEN];
>  	unsigned optlen, hdrlen;
>  	int idle, sendalot;
> @@ -447,13 +448,15 @@ send:
>  	 * the template, but need a way to checksum without them.
>  	 */
>  	m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
> +	tcpiph_save = *(mtod(m, struct tcpiphdr *));

I think you could drop the outermost parentheses here.

> -	struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
> +	switch (so->so_ffamily) {
> +	case AF_INET:
>  	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
>  	                                     - sizeof(struct ip);
>  	m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
>  	                                     - sizeof(struct ip);
> -	struct ip *ip = mtod(m, struct ip *);
> +	ip = mtod(m, struct ip *);
>  
>  	ip->ip_len = m->m_len;
>  	ip->ip_dst = tcpiph_save.ti_dst;
> @@ -464,6 +467,11 @@ send:
>  	ip->ip_tos = so->so_iptos;
>  
>  	error = ip_output(so, m);
> +	    break;
> +
> +	default:
> +	    g_assert_not_reached();
> +	}
...

Only very minor cosmetic nits, patch generally looks fine, so:

Reviewed-by: Thomas Huth <thuth@redhat.com>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [Qemu-devel] [PATCH v2] slirp: Add IPv6 support to the TFTP code
  2016-02-16  8:47 ` [Qemu-devel] [PATCH] slirp: Add IPv6 support to the TFTP code Thomas Huth
  2016-02-16 10:30   ` Samuel Thibault
@ 2016-02-17  8:40   ` Thomas Huth
  2016-02-17  8:42     ` Samuel Thibault
  1 sibling, 1 reply; 38+ messages in thread
From: Thomas Huth @ 2016-02-17  8:40 UTC (permalink / raw)
  To: qemu-devel, samuel.thibault, jan.kiszka; +Cc: jasowang

Add the handler code for incoming TFTP packets to udp6_input(),
and make sure that the TFTP code can send packets with both,
udp_output() and udp6_output() by introducing a wrapper function
called tftp_udp_output().

Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 v2: Changes according to the review of Samuel Thibault:
 - Use the "slirp" parameter as the first parameter
 - Use structure assignments instead of memcpy()

 This patch has to be applied on top of Samuel's "slirp: Adding IPv6
 support to Qemu -net user mode" patch series.
 Samuel, if you respin your patch series and if you think this patch
 is ok, feel free to also include it in your series.

 Code has been tested with network booting in SLOF:

  qemu-system-ppc64 -vga none -device virtio-net,netdev=mynet \
     -netdev user,id=mynet,tftp=/home/thuth/tmp/tftp -nographic

 ... and then, at the Open Firmware prompt, type:

  boot net:ipv6,fec0::2,zImage,fec0::1234
---
 slirp/tftp.c | 133 +++++++++++++++++++++++++++++++++--------------------------
 slirp/tftp.h |   7 ++--
 slirp/udp.c  |  16 ++++---
 slirp/udp6.c |  16 +++++--
 4 files changed, 100 insertions(+), 72 deletions(-)

diff --git a/slirp/tftp.c b/slirp/tftp.c
index abb0106..7d70504 100644
--- a/slirp/tftp.c
+++ b/slirp/tftp.c
@@ -46,7 +46,8 @@ static void tftp_session_terminate(struct tftp_session *spt)
     spt->slirp = NULL;
 }
 
-static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
+static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas,
+                                 struct tftp_t *tp)
 {
   struct tftp_session *spt;
   int k;
@@ -68,7 +69,7 @@ static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
 
  found:
   memset(spt, 0, sizeof(*spt));
-  memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip));
+  spt->client_addr = *srcsas;
   spt->fd = -1;
   spt->client_port = tp->udp.uh_sport;
   spt->slirp = slirp;
@@ -78,7 +79,8 @@ static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
   return k;
 }
 
-static int tftp_session_find(Slirp *slirp, struct tftp_t *tp)
+static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas,
+                             struct tftp_t *tp)
 {
   struct tftp_session *spt;
   int k;
@@ -87,7 +89,7 @@ static int tftp_session_find(Slirp *slirp, struct tftp_t *tp)
     spt = &slirp->tftp_sessions[k];
 
     if (tftp_session_in_use(spt)) {
-      if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) {
+      if (sockaddr_equal(&spt->client_addr, srcsas)) {
 	if (spt->client_port == tp->udp.uh_sport) {
 	  return k;
 	}
@@ -120,11 +122,53 @@ static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr,
     return bytes_read;
 }
 
+static struct tftp_t *tftp_prep_mbuf_data(struct tftp_session *spt,
+                                          struct mbuf *m)
+{
+    struct tftp_t *tp;
+
+    memset(m->m_data, 0, m->m_size);
+
+    m->m_data += IF_MAXLINKHDR;
+    if (spt->client_addr.ss_family == AF_INET6) {
+        m->m_data += sizeof(struct ip6);
+    } else {
+        m->m_data += sizeof(struct ip);
+    }
+    tp = (void *)m->m_data;
+    m->m_data += sizeof(struct udphdr);
+
+    return tp;
+}
+
+static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
+                            struct tftp_t *recv_tp)
+{
+    if (spt->client_addr.ss_family == AF_INET6) {
+        struct sockaddr_in6 sa6, da6;
+
+        sa6.sin6_addr = spt->slirp->vhost_addr6;
+        sa6.sin6_port = recv_tp->udp.uh_dport;
+        da6.sin6_addr = ((struct sockaddr_in6 *)&spt->client_addr)->sin6_addr;
+        da6.sin6_port = spt->client_port;
+
+        udp6_output(NULL, m, &sa6, &da6);
+    } else {
+        struct sockaddr_in sa4, da4;
+
+        sa4.sin_addr = spt->slirp->vhost_addr;
+        sa4.sin_port = recv_tp->udp.uh_dport;
+        da4.sin_addr = ((struct sockaddr_in *)&spt->client_addr)->sin_addr;
+        da4.sin_port = spt->client_port;
+
+        udp_output(NULL, m, &sa4, &da4, IPTOS_LOWDELAY);
+    }
+}
+
 static int tftp_send_oack(struct tftp_session *spt,
                           const char *keys[], uint32_t values[], int nb,
                           struct tftp_t *recv_tp)
 {
-    struct sockaddr_in saddr, daddr;
     struct mbuf *m;
     struct tftp_t *tp;
     int i, n = 0;
@@ -132,13 +176,9 @@ static int tftp_send_oack(struct tftp_session *spt,
     m = m_get(spt->slirp);
 
     if (!m)
-	return -1;
-
-    memset(m->m_data, 0, m->m_size);
+        return -1;
 
-    m->m_data += IF_MAXLINKHDR;
-    tp = (void *)m->m_data;
-    m->m_data += sizeof(struct udpiphdr);
+    tp = tftp_prep_mbuf_data(spt, m);
 
     tp->tp_op = htons(TFTP_OACK);
     for (i = 0; i < nb; i++) {
@@ -148,15 +188,8 @@ static int tftp_send_oack(struct tftp_session *spt,
                       values[i]) + 1;
     }
 
-    saddr.sin_addr = recv_tp->ip.ip_dst;
-    saddr.sin_port = recv_tp->udp.uh_dport;
-
-    daddr.sin_addr = spt->client_ip;
-    daddr.sin_port = spt->client_port;
-
-    m->m_len = sizeof(struct tftp_t) - 514 + n -
-        sizeof(struct ip) - sizeof(struct udphdr);
-    udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+    m->m_len = sizeof(struct tftp_t) - 514 + n - sizeof(struct udphdr);
+    tftp_udp_output(spt, m, recv_tp);
 
     return 0;
 }
@@ -165,7 +198,6 @@ static void tftp_send_error(struct tftp_session *spt,
                             uint16_t errorcode, const char *msg,
                             struct tftp_t *recv_tp)
 {
-  struct sockaddr_in saddr, daddr;
   struct mbuf *m;
   struct tftp_t *tp;
 
@@ -177,24 +209,15 @@ static void tftp_send_error(struct tftp_session *spt,
 
   memset(m->m_data, 0, m->m_size);
 
-  m->m_data += IF_MAXLINKHDR;
-  tp = (void *)m->m_data;
-  m->m_data += sizeof(struct udpiphdr);
+  tp = tftp_prep_mbuf_data(spt, m);
 
   tp->tp_op = htons(TFTP_ERROR);
   tp->x.tp_error.tp_error_code = htons(errorcode);
   pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg);
 
-  saddr.sin_addr = recv_tp->ip.ip_dst;
-  saddr.sin_port = recv_tp->udp.uh_dport;
-
-  daddr.sin_addr = spt->client_ip;
-  daddr.sin_port = spt->client_port;
-
-  m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
-        sizeof(struct ip) - sizeof(struct udphdr);
-
-  udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+  m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg)
+             - sizeof(struct udphdr);
+  tftp_udp_output(spt, m, recv_tp);
 
 out:
   tftp_session_terminate(spt);
@@ -203,7 +226,6 @@ out:
 static void tftp_send_next_block(struct tftp_session *spt,
                                  struct tftp_t *recv_tp)
 {
-  struct sockaddr_in saddr, daddr;
   struct mbuf *m;
   struct tftp_t *tp;
   int nobytes;
@@ -216,19 +238,11 @@ static void tftp_send_next_block(struct tftp_session *spt,
 
   memset(m->m_data, 0, m->m_size);
 
-  m->m_data += IF_MAXLINKHDR;
-  tp = (void *)m->m_data;
-  m->m_data += sizeof(struct udpiphdr);
+  tp = tftp_prep_mbuf_data(spt, m);
 
   tp->tp_op = htons(TFTP_DATA);
   tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff);
 
-  saddr.sin_addr = recv_tp->ip.ip_dst;
-  saddr.sin_port = recv_tp->udp.uh_dport;
-
-  daddr.sin_addr = spt->client_ip;
-  daddr.sin_port = spt->client_port;
-
   nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf, 512);
 
   if (nobytes < 0) {
@@ -241,10 +255,8 @@ static void tftp_send_next_block(struct tftp_session *spt,
     return;
   }
 
-  m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
-        sizeof(struct ip) - sizeof(struct udphdr);
-
-  udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+  m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - sizeof(struct udphdr);
+  tftp_udp_output(spt, m, recv_tp);
 
   if (nobytes == 512) {
     tftp_session_update(spt);
@@ -256,7 +268,8 @@ static void tftp_send_next_block(struct tftp_session *spt,
   spt->block_nr++;
 }
 
-static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
+static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
+                            struct tftp_t *tp, int pktlen)
 {
   struct tftp_session *spt;
   int s, k;
@@ -267,12 +280,12 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
   int nb_options = 0;
 
   /* check if a session already exists and if so terminate it */
-  s = tftp_session_find(slirp, tp);
+  s = tftp_session_find(slirp, srcsas, tp);
   if (s >= 0) {
     tftp_session_terminate(&slirp->tftp_sessions[s]);
   }
 
-  s = tftp_session_allocate(slirp, tp);
+  s = tftp_session_allocate(slirp, srcsas, tp);
 
   if (s < 0) {
     return;
@@ -397,11 +410,12 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
   tftp_send_next_block(spt, tp);
 }
 
-static void tftp_handle_ack(Slirp *slirp, struct tftp_t *tp, int pktlen)
+static void tftp_handle_ack(Slirp *slirp, struct sockaddr_storage *srcsas,
+                            struct tftp_t *tp, int pktlen)
 {
   int s;
 
-  s = tftp_session_find(slirp, tp);
+  s = tftp_session_find(slirp, srcsas, tp);
 
   if (s < 0) {
     return;
@@ -410,11 +424,12 @@ static void tftp_handle_ack(Slirp *slirp, struct tftp_t *tp, int pktlen)
   tftp_send_next_block(&slirp->tftp_sessions[s], tp);
 }
 
-static void tftp_handle_error(Slirp *slirp, struct tftp_t *tp, int pktlen)
+static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas,
+                              struct tftp_t *tp, int pktlen)
 {
   int s;
 
-  s = tftp_session_find(slirp, tp);
+  s = tftp_session_find(slirp, srcsas, tp);
 
   if (s < 0) {
     return;
@@ -423,21 +438,21 @@ static void tftp_handle_error(Slirp *slirp, struct tftp_t *tp, int pktlen)
   tftp_session_terminate(&slirp->tftp_sessions[s]);
 }
 
-void tftp_input(struct mbuf *m)
+void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m)
 {
   struct tftp_t *tp = (struct tftp_t *)m->m_data;
 
   switch(ntohs(tp->tp_op)) {
   case TFTP_RRQ:
-    tftp_handle_rrq(m->slirp, tp, m->m_len);
+    tftp_handle_rrq(m->slirp, srcsas, tp, m->m_len);
     break;
 
   case TFTP_ACK:
-    tftp_handle_ack(m->slirp, tp, m->m_len);
+    tftp_handle_ack(m->slirp, srcsas, tp, m->m_len);
     break;
 
   case TFTP_ERROR:
-    tftp_handle_error(m->slirp, tp, m->m_len);
+    tftp_handle_error(m->slirp, srcsas, tp, m->m_len);
     break;
   }
 }
diff --git a/slirp/tftp.h b/slirp/tftp.h
index e1cc24b..1cb1adf 100644
--- a/slirp/tftp.h
+++ b/slirp/tftp.h
@@ -16,7 +16,6 @@
 #define TFTP_FILENAME_MAX 512
 
 struct tftp_t {
-  struct ip ip;
   struct udphdr udp;
   uint16_t tp_op;
   union {
@@ -30,20 +29,20 @@ struct tftp_t {
     } tp_error;
     char tp_buf[512 + 2];
   } x;
-};
+} __attribute__((packed));
 
 struct tftp_session {
     Slirp *slirp;
     char *filename;
     int fd;
 
-    struct in_addr client_ip;
+    struct sockaddr_storage client_addr;
     uint16_t client_port;
     uint32_t block_nr;
 
     int timestamp;
 };
 
-void tftp_input(struct mbuf *m);
+void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m);
 
 #endif
diff --git a/slirp/udp.c b/slirp/udp.c
index be012fb..247024f 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -128,6 +128,11 @@ udp_input(register struct mbuf *m, int iphlen)
 	  }
 	}
 
+	lhost.ss_family = AF_INET;
+	lhost4 = (struct sockaddr_in *) &lhost;
+	lhost4->sin_addr = ip->ip_src;
+	lhost4->sin_port = uh->uh_sport;
+
         /*
          *  handle DHCP/BOOTP
          */
@@ -143,7 +148,11 @@ udp_input(register struct mbuf *m, int iphlen)
          */
         if (ntohs(uh->uh_dport) == TFTP_SERVER &&
             ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
-            tftp_input(m);
+            m->m_data += iphlen;
+            m->m_len -= iphlen;
+            tftp_input(&lhost, m);
+            m->m_data -= iphlen;
+            m->m_len += iphlen;
             goto bad;
         }
 
@@ -154,11 +163,6 @@ udp_input(register struct mbuf *m, int iphlen)
 	/*
 	 * Locate pcb for datagram.
 	 */
-	lhost.ss_family = AF_INET;
-	lhost4 = (struct sockaddr_in *) &lhost;
-	lhost4->sin_addr = ip->ip_src;
-	lhost4->sin_port = uh->uh_sport;
-
 	so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL);
 
 	if (so == NULL) {
diff --git a/slirp/udp6.c b/slirp/udp6.c
index 6c0d55f..820192a 100644
--- a/slirp/udp6.c
+++ b/slirp/udp6.c
@@ -55,14 +55,24 @@ void udp6_input(struct mbuf *m)
      */
     save_ip = *ip;
 
-    /* TODO handle DHCP/BOOTP */
-    /* TODO handle TFTP */
-
     /* Locate pcb for datagram. */
     lhost.sin6_family = AF_INET6;
     lhost.sin6_addr = ip->ip_src;
     lhost.sin6_port = uh->uh_sport;
 
+    /* TODO handle DHCP/BOOTP */
+
+    /* handle TFTP */
+    if (ntohs(uh->uh_dport) == TFTP_SERVER &&
+        !memcmp(ip->ip_dst.s6_addr, slirp->vhost_addr6.s6_addr, 16)) {
+        m->m_data += hlen;
+        m->m_len -= hlen;
+        tftp_input((struct sockaddr_storage *)&lhost, m);
+        m->m_data -= hlen;
+        m->m_len += hlen;
+        goto bad;
+    }
+
     so = solookup(&slirp->udp_last_so, &slirp->udb,
                   (struct sockaddr_storage *) &lhost, NULL);
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCH v2] slirp: Add IPv6 support to the TFTP code
  2016-02-17  8:40   ` [Qemu-devel] [PATCH v2] " Thomas Huth
@ 2016-02-17  8:42     ` Samuel Thibault
  0 siblings, 0 replies; 38+ messages in thread
From: Samuel Thibault @ 2016-02-17  8:42 UTC (permalink / raw)
  To: Thomas Huth; +Cc: jan.kiszka, jasowang, qemu-devel

Thomas Huth, on Wed 17 Feb 2016 09:40:10 +0100, wrote:
> Add the handler code for incoming TFTP packets to udp6_input(),
> and make sure that the TFTP code can send packets with both,
> udp_output() and udp6_output() by introducing a wrapper function
> called tftp_udp_output().
> 
> Signed-off-by: Thomas Huth <thuth@redhat.com>

Reviewed-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

> ---
>  v2: Changes according to the review of Samuel Thibault:
>  - Use the "slirp" parameter as the first parameter
>  - Use structure assignments instead of memcpy()
> 
>  This patch has to be applied on top of Samuel's "slirp: Adding IPv6
>  support to Qemu -net user mode" patch series.
>  Samuel, if you respin your patch series and if you think this patch
>  is ok, feel free to also include it in your series.
> 
>  Code has been tested with network booting in SLOF:
> 
>   qemu-system-ppc64 -vga none -device virtio-net,netdev=mynet \
>      -netdev user,id=mynet,tftp=/home/thuth/tmp/tftp -nographic
> 
>  ... and then, at the Open Firmware prompt, type:
> 
>   boot net:ipv6,fec0::2,zImage,fec0::1234
> ---
>  slirp/tftp.c | 133 +++++++++++++++++++++++++++++++++--------------------------
>  slirp/tftp.h |   7 ++--
>  slirp/udp.c  |  16 ++++---
>  slirp/udp6.c |  16 +++++--
>  4 files changed, 100 insertions(+), 72 deletions(-)
> 
> diff --git a/slirp/tftp.c b/slirp/tftp.c
> index abb0106..7d70504 100644
> --- a/slirp/tftp.c
> +++ b/slirp/tftp.c
> @@ -46,7 +46,8 @@ static void tftp_session_terminate(struct tftp_session *spt)
>      spt->slirp = NULL;
>  }
>  
> -static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
> +static int tftp_session_allocate(Slirp *slirp, struct sockaddr_storage *srcsas,
> +                                 struct tftp_t *tp)
>  {
>    struct tftp_session *spt;
>    int k;
> @@ -68,7 +69,7 @@ static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
>  
>   found:
>    memset(spt, 0, sizeof(*spt));
> -  memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip));
> +  spt->client_addr = *srcsas;
>    spt->fd = -1;
>    spt->client_port = tp->udp.uh_sport;
>    spt->slirp = slirp;
> @@ -78,7 +79,8 @@ static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp)
>    return k;
>  }
>  
> -static int tftp_session_find(Slirp *slirp, struct tftp_t *tp)
> +static int tftp_session_find(Slirp *slirp, struct sockaddr_storage *srcsas,
> +                             struct tftp_t *tp)
>  {
>    struct tftp_session *spt;
>    int k;
> @@ -87,7 +89,7 @@ static int tftp_session_find(Slirp *slirp, struct tftp_t *tp)
>      spt = &slirp->tftp_sessions[k];
>  
>      if (tftp_session_in_use(spt)) {
> -      if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) {
> +      if (sockaddr_equal(&spt->client_addr, srcsas)) {
>  	if (spt->client_port == tp->udp.uh_sport) {
>  	  return k;
>  	}
> @@ -120,11 +122,53 @@ static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr,
>      return bytes_read;
>  }
>  
> +static struct tftp_t *tftp_prep_mbuf_data(struct tftp_session *spt,
> +                                          struct mbuf *m)
> +{
> +    struct tftp_t *tp;
> +
> +    memset(m->m_data, 0, m->m_size);
> +
> +    m->m_data += IF_MAXLINKHDR;
> +    if (spt->client_addr.ss_family == AF_INET6) {
> +        m->m_data += sizeof(struct ip6);
> +    } else {
> +        m->m_data += sizeof(struct ip);
> +    }
> +    tp = (void *)m->m_data;
> +    m->m_data += sizeof(struct udphdr);
> +
> +    return tp;
> +}
> +
> +static void tftp_udp_output(struct tftp_session *spt, struct mbuf *m,
> +                            struct tftp_t *recv_tp)
> +{
> +    if (spt->client_addr.ss_family == AF_INET6) {
> +        struct sockaddr_in6 sa6, da6;
> +
> +        sa6.sin6_addr = spt->slirp->vhost_addr6;
> +        sa6.sin6_port = recv_tp->udp.uh_dport;
> +        da6.sin6_addr = ((struct sockaddr_in6 *)&spt->client_addr)->sin6_addr;
> +        da6.sin6_port = spt->client_port;
> +
> +        udp6_output(NULL, m, &sa6, &da6);
> +    } else {
> +        struct sockaddr_in sa4, da4;
> +
> +        sa4.sin_addr = spt->slirp->vhost_addr;
> +        sa4.sin_port = recv_tp->udp.uh_dport;
> +        da4.sin_addr = ((struct sockaddr_in *)&spt->client_addr)->sin_addr;
> +        da4.sin_port = spt->client_port;
> +
> +        udp_output(NULL, m, &sa4, &da4, IPTOS_LOWDELAY);
> +    }
> +}
> +
>  static int tftp_send_oack(struct tftp_session *spt,
>                            const char *keys[], uint32_t values[], int nb,
>                            struct tftp_t *recv_tp)
>  {
> -    struct sockaddr_in saddr, daddr;
>      struct mbuf *m;
>      struct tftp_t *tp;
>      int i, n = 0;
> @@ -132,13 +176,9 @@ static int tftp_send_oack(struct tftp_session *spt,
>      m = m_get(spt->slirp);
>  
>      if (!m)
> -	return -1;
> -
> -    memset(m->m_data, 0, m->m_size);
> +        return -1;
>  
> -    m->m_data += IF_MAXLINKHDR;
> -    tp = (void *)m->m_data;
> -    m->m_data += sizeof(struct udpiphdr);
> +    tp = tftp_prep_mbuf_data(spt, m);
>  
>      tp->tp_op = htons(TFTP_OACK);
>      for (i = 0; i < nb; i++) {
> @@ -148,15 +188,8 @@ static int tftp_send_oack(struct tftp_session *spt,
>                        values[i]) + 1;
>      }
>  
> -    saddr.sin_addr = recv_tp->ip.ip_dst;
> -    saddr.sin_port = recv_tp->udp.uh_dport;
> -
> -    daddr.sin_addr = spt->client_ip;
> -    daddr.sin_port = spt->client_port;
> -
> -    m->m_len = sizeof(struct tftp_t) - 514 + n -
> -        sizeof(struct ip) - sizeof(struct udphdr);
> -    udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
> +    m->m_len = sizeof(struct tftp_t) - 514 + n - sizeof(struct udphdr);
> +    tftp_udp_output(spt, m, recv_tp);
>  
>      return 0;
>  }
> @@ -165,7 +198,6 @@ static void tftp_send_error(struct tftp_session *spt,
>                              uint16_t errorcode, const char *msg,
>                              struct tftp_t *recv_tp)
>  {
> -  struct sockaddr_in saddr, daddr;
>    struct mbuf *m;
>    struct tftp_t *tp;
>  
> @@ -177,24 +209,15 @@ static void tftp_send_error(struct tftp_session *spt,
>  
>    memset(m->m_data, 0, m->m_size);
>  
> -  m->m_data += IF_MAXLINKHDR;
> -  tp = (void *)m->m_data;
> -  m->m_data += sizeof(struct udpiphdr);
> +  tp = tftp_prep_mbuf_data(spt, m);
>  
>    tp->tp_op = htons(TFTP_ERROR);
>    tp->x.tp_error.tp_error_code = htons(errorcode);
>    pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg);
>  
> -  saddr.sin_addr = recv_tp->ip.ip_dst;
> -  saddr.sin_port = recv_tp->udp.uh_dport;
> -
> -  daddr.sin_addr = spt->client_ip;
> -  daddr.sin_port = spt->client_port;
> -
> -  m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
> -        sizeof(struct ip) - sizeof(struct udphdr);
> -
> -  udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
> +  m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg)
> +             - sizeof(struct udphdr);
> +  tftp_udp_output(spt, m, recv_tp);
>  
>  out:
>    tftp_session_terminate(spt);
> @@ -203,7 +226,6 @@ out:
>  static void tftp_send_next_block(struct tftp_session *spt,
>                                   struct tftp_t *recv_tp)
>  {
> -  struct sockaddr_in saddr, daddr;
>    struct mbuf *m;
>    struct tftp_t *tp;
>    int nobytes;
> @@ -216,19 +238,11 @@ static void tftp_send_next_block(struct tftp_session *spt,
>  
>    memset(m->m_data, 0, m->m_size);
>  
> -  m->m_data += IF_MAXLINKHDR;
> -  tp = (void *)m->m_data;
> -  m->m_data += sizeof(struct udpiphdr);
> +  tp = tftp_prep_mbuf_data(spt, m);
>  
>    tp->tp_op = htons(TFTP_DATA);
>    tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff);
>  
> -  saddr.sin_addr = recv_tp->ip.ip_dst;
> -  saddr.sin_port = recv_tp->udp.uh_dport;
> -
> -  daddr.sin_addr = spt->client_ip;
> -  daddr.sin_port = spt->client_port;
> -
>    nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf, 512);
>  
>    if (nobytes < 0) {
> @@ -241,10 +255,8 @@ static void tftp_send_next_block(struct tftp_session *spt,
>      return;
>    }
>  
> -  m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
> -        sizeof(struct ip) - sizeof(struct udphdr);
> -
> -  udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
> +  m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - sizeof(struct udphdr);
> +  tftp_udp_output(spt, m, recv_tp);
>  
>    if (nobytes == 512) {
>      tftp_session_update(spt);
> @@ -256,7 +268,8 @@ static void tftp_send_next_block(struct tftp_session *spt,
>    spt->block_nr++;
>  }
>  
> -static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
> +static void tftp_handle_rrq(Slirp *slirp, struct sockaddr_storage *srcsas,
> +                            struct tftp_t *tp, int pktlen)
>  {
>    struct tftp_session *spt;
>    int s, k;
> @@ -267,12 +280,12 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
>    int nb_options = 0;
>  
>    /* check if a session already exists and if so terminate it */
> -  s = tftp_session_find(slirp, tp);
> +  s = tftp_session_find(slirp, srcsas, tp);
>    if (s >= 0) {
>      tftp_session_terminate(&slirp->tftp_sessions[s]);
>    }
>  
> -  s = tftp_session_allocate(slirp, tp);
> +  s = tftp_session_allocate(slirp, srcsas, tp);
>  
>    if (s < 0) {
>      return;
> @@ -397,11 +410,12 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
>    tftp_send_next_block(spt, tp);
>  }
>  
> -static void tftp_handle_ack(Slirp *slirp, struct tftp_t *tp, int pktlen)
> +static void tftp_handle_ack(Slirp *slirp, struct sockaddr_storage *srcsas,
> +                            struct tftp_t *tp, int pktlen)
>  {
>    int s;
>  
> -  s = tftp_session_find(slirp, tp);
> +  s = tftp_session_find(slirp, srcsas, tp);
>  
>    if (s < 0) {
>      return;
> @@ -410,11 +424,12 @@ static void tftp_handle_ack(Slirp *slirp, struct tftp_t *tp, int pktlen)
>    tftp_send_next_block(&slirp->tftp_sessions[s], tp);
>  }
>  
> -static void tftp_handle_error(Slirp *slirp, struct tftp_t *tp, int pktlen)
> +static void tftp_handle_error(Slirp *slirp, struct sockaddr_storage *srcsas,
> +                              struct tftp_t *tp, int pktlen)
>  {
>    int s;
>  
> -  s = tftp_session_find(slirp, tp);
> +  s = tftp_session_find(slirp, srcsas, tp);
>  
>    if (s < 0) {
>      return;
> @@ -423,21 +438,21 @@ static void tftp_handle_error(Slirp *slirp, struct tftp_t *tp, int pktlen)
>    tftp_session_terminate(&slirp->tftp_sessions[s]);
>  }
>  
> -void tftp_input(struct mbuf *m)
> +void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m)
>  {
>    struct tftp_t *tp = (struct tftp_t *)m->m_data;
>  
>    switch(ntohs(tp->tp_op)) {
>    case TFTP_RRQ:
> -    tftp_handle_rrq(m->slirp, tp, m->m_len);
> +    tftp_handle_rrq(m->slirp, srcsas, tp, m->m_len);
>      break;
>  
>    case TFTP_ACK:
> -    tftp_handle_ack(m->slirp, tp, m->m_len);
> +    tftp_handle_ack(m->slirp, srcsas, tp, m->m_len);
>      break;
>  
>    case TFTP_ERROR:
> -    tftp_handle_error(m->slirp, tp, m->m_len);
> +    tftp_handle_error(m->slirp, srcsas, tp, m->m_len);
>      break;
>    }
>  }
> diff --git a/slirp/tftp.h b/slirp/tftp.h
> index e1cc24b..1cb1adf 100644
> --- a/slirp/tftp.h
> +++ b/slirp/tftp.h
> @@ -16,7 +16,6 @@
>  #define TFTP_FILENAME_MAX 512
>  
>  struct tftp_t {
> -  struct ip ip;
>    struct udphdr udp;
>    uint16_t tp_op;
>    union {
> @@ -30,20 +29,20 @@ struct tftp_t {
>      } tp_error;
>      char tp_buf[512 + 2];
>    } x;
> -};
> +} __attribute__((packed));
>  
>  struct tftp_session {
>      Slirp *slirp;
>      char *filename;
>      int fd;
>  
> -    struct in_addr client_ip;
> +    struct sockaddr_storage client_addr;
>      uint16_t client_port;
>      uint32_t block_nr;
>  
>      int timestamp;
>  };
>  
> -void tftp_input(struct mbuf *m);
> +void tftp_input(struct sockaddr_storage *srcsas, struct mbuf *m);
>  
>  #endif
> diff --git a/slirp/udp.c b/slirp/udp.c
> index be012fb..247024f 100644
> --- a/slirp/udp.c
> +++ b/slirp/udp.c
> @@ -128,6 +128,11 @@ udp_input(register struct mbuf *m, int iphlen)
>  	  }
>  	}
>  
> +	lhost.ss_family = AF_INET;
> +	lhost4 = (struct sockaddr_in *) &lhost;
> +	lhost4->sin_addr = ip->ip_src;
> +	lhost4->sin_port = uh->uh_sport;
> +
>          /*
>           *  handle DHCP/BOOTP
>           */
> @@ -143,7 +148,11 @@ udp_input(register struct mbuf *m, int iphlen)
>           */
>          if (ntohs(uh->uh_dport) == TFTP_SERVER &&
>              ip->ip_dst.s_addr == slirp->vhost_addr.s_addr) {
> -            tftp_input(m);
> +            m->m_data += iphlen;
> +            m->m_len -= iphlen;
> +            tftp_input(&lhost, m);
> +            m->m_data -= iphlen;
> +            m->m_len += iphlen;
>              goto bad;
>          }
>  
> @@ -154,11 +163,6 @@ udp_input(register struct mbuf *m, int iphlen)
>  	/*
>  	 * Locate pcb for datagram.
>  	 */
> -	lhost.ss_family = AF_INET;
> -	lhost4 = (struct sockaddr_in *) &lhost;
> -	lhost4->sin_addr = ip->ip_src;
> -	lhost4->sin_port = uh->uh_sport;
> -
>  	so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL);
>  
>  	if (so == NULL) {
> diff --git a/slirp/udp6.c b/slirp/udp6.c
> index 6c0d55f..820192a 100644
> --- a/slirp/udp6.c
> +++ b/slirp/udp6.c
> @@ -55,14 +55,24 @@ void udp6_input(struct mbuf *m)
>       */
>      save_ip = *ip;
>  
> -    /* TODO handle DHCP/BOOTP */
> -    /* TODO handle TFTP */
> -
>      /* Locate pcb for datagram. */
>      lhost.sin6_family = AF_INET6;
>      lhost.sin6_addr = ip->ip_src;
>      lhost.sin6_port = uh->uh_sport;
>  
> +    /* TODO handle DHCP/BOOTP */
> +
> +    /* handle TFTP */
> +    if (ntohs(uh->uh_dport) == TFTP_SERVER &&
> +        !memcmp(ip->ip_dst.s6_addr, slirp->vhost_addr6.s6_addr, 16)) {
> +        m->m_data += hlen;
> +        m->m_len -= hlen;
> +        tftp_input((struct sockaddr_storage *)&lhost, m);
> +        m->m_data -= hlen;
> +        m->m_len += hlen;
> +        goto bad;
> +    }
> +
>      so = solookup(&slirp->udp_last_so, &slirp->udb,
>                    (struct sockaddr_storage *) &lhost, NULL);
>  
> -- 
> 1.8.3.1
> 

-- 
Samuel
In mutt, type cthis
Dans mutt, taper cceci

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring Samuel Thibault
@ 2016-02-17  9:03   ` Thomas Huth
  0 siblings, 0 replies; 38+ messages in thread
From: Thomas Huth @ 2016-02-17  9:03 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei, Jan Kiszka,
	Guillaume Subiron

On 14.02.2016 18:47, Samuel Thibault wrote:
> From: Guillaume Subiron <maethor@subiron.org>
> 
> No code change.
> 
> Signed-off-by: Guillaume Subiron <maethor@subiron.org>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
>  slirp/tcp_input.c  | 92 +++++++++++++++++++++++++++---------------------------
>  slirp/tcp_output.c | 29 +++++++++--------
>  slirp/tcp_subr.c   | 50 ++++++++++++++---------------
>  3 files changed, 85 insertions(+), 86 deletions(-)

I've checked it, no code change, just re-indention.

Reviewed-by: Thomas Huth <thuth@redhat.com>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 7/9] slirp: Handle IPv6 in TCP functions
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 7/9] slirp: Handle IPv6 in TCP functions Samuel Thibault
@ 2016-02-17  9:18   ` Thomas Huth
  2016-02-17  9:30     ` Samuel Thibault
  0 siblings, 1 reply; 38+ messages in thread
From: Thomas Huth @ 2016-02-17  9:18 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei, Jan Kiszka,
	Guillaume Subiron

On 14.02.2016 18:47, Samuel Thibault wrote:
> From: Guillaume Subiron <maethor@subiron.org>
> 
> This patch adds IPv6 case in TCP functions refactored by the last
> patches.
> This also adds IPv6 pseudo-header in tcpiphdr structure.
> Finally, tcp_input() is called by ip6_input().
> 
> Signed-off-by: Guillaume Subiron <maethor@subiron.org>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
...
> diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
> index fac2a24..7aad1bc 100644
> --- a/slirp/tcp_input.c
> +++ b/slirp/tcp_input.c
> @@ -216,7 +216,8 @@ present:
>  void
>  tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
>  {
> -  	struct ip save_ip, *ip;
> +	struct ip save_ip, *ip;
> +	struct ip6 save_ip6, *ip6;
>  	register struct tcpiphdr *ti;
>  	caddr_t optp = NULL;
>  	int optlen = 0;
> @@ -230,6 +231,7 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
>  	int ret;
>  	struct sockaddr_storage lhost, fhost;
>  	struct sockaddr_in *lhost4, *fhost4;
> +	struct sockaddr_in6 *lhost6, *fhost6;
>      struct ex_list *ex_ptr;
>      Slirp *slirp;
>  
> @@ -256,21 +258,18 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
>  	}
>  	slirp = m->slirp;
>  
> +	ip = mtod(m, struct ip *);
> +	ip6 = mtod(m, struct ip6 *);
> +
>  	switch (af) {
>  	case AF_INET:
> +	    save_ip = *ip;
>  	    if (iphlen > sizeof(struct ip)) {
>  	        ip_stripoptions(m, (struct mbuf *)0);
>  	        iphlen = sizeof(struct ip);
>  	    }
>  	    /* XXX Check if too short */
>  
> -
> -	    /*
> -	     * Save a copy of the IP header in case we want restore it
> -	     * for sending an ICMP error message in response.
> -	     */
> -	    ip = mtod(m, struct ip *);
> -	    save_ip = *ip;

I think you could also leave the "save_ip = *ip" here instead of moving
it to the beginning of this case statement.

>  	    save_ip.ip_len += iphlen;
>  
>  	    /*
> @@ -295,16 +294,36 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
>  	    ti->ti_dst = save_ip.ip_dst;
>  	    ti->ti_pr = save_ip.ip_p;
>  	    ti->ti_len = htons((uint16_t)tlen);
> -	    len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
> -	    if (cksum(m, len)) {
> -	        goto drop;
> -	    }
> +	    break;
> +
> +	case AF_INET6:
> +	    save_ip6 = *ip6;
> +	    m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip6)
> +	                                         + sizeof(struct tcphdr));
> +	    m->m_len  += sizeof(struct tcpiphdr) - (sizeof(struct ip6)
> +	                                         + sizeof(struct tcphdr));
> +	    ti = mtod(m, struct tcpiphdr *);
> +
> +	    tlen = ip6->ip_pl;
> +	    tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
> +	    memset(&ti->ih_mbuf, 0 , sizeof(struct mbuf_ptr));
> +	    memset(&ti->ti, 0, sizeof(ti->ti));
> +	    ti->ti_x0 = 0;
> +	    ti->ti_src6 = save_ip6.ip_src;
> +	    ti->ti_dst6 = save_ip6.ip_dst;
> +	    ti->ti_nh6 = save_ip6.ip_nh;
> +	    ti->ti_len = htons((uint16_t)tlen);
>  	    break;
>  
>  	default:
>  	    g_assert_not_reached();
>  	}
>  
> +	len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
> +	if (cksum(m, len)) {
> +	    goto drop;
> +	}
> +
...
> diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
> index c16b29d..6991b21 100644
> --- a/slirp/tcp_subr.c
> +++ b/slirp/tcp_subr.c
> @@ -88,6 +88,15 @@ tcp_template(struct tcpcb *tp)
>  	    n->ti_dport = so->so_lport;
>  	    break;
>  
> +	case AF_INET6:
> +	    n->ti_nh6 = IPPROTO_TCP;
> +	    n->ti_len = htons(sizeof(struct tcphdr));
> +	    n->ti_src6 = so->so_faddr6;
> +	    n->ti_dst6 = so->so_laddr6;
> +	    n->ti_sport = so->so_fport6;
> +	    n->ti_dport = so->so_lport6;
> +	    break;
> +
>  	default:
>  	    g_assert_not_reached();
>  	}
> @@ -156,6 +165,10 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
>  		    xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, uint32_t);
>  		    xchg(ti->ti_dport, ti->ti_sport, uint16_t);
>  		    break;
> +		case AF_INET6:
> +		    xchg(ti->ti_dst6, ti->ti_src6, struct in6_addr);
> +		    xchg(ti->ti_dport, ti->ti_sport, uint16_t);
> +		    break;
>  		default:
>  		    g_assert_not_reached();
>  		}
> @@ -182,6 +195,7 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
>  
>  	struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
>  	struct ip *ip;
> +	struct ip6 *ip6;
>  
>  	switch (af) {
>  	case AF_INET:
> @@ -204,6 +218,20 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
>  	    (void) ip_output((struct socket *)0, m);
>  	    break;
>  
> +	case AF_INET6:
> +	    m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
> +	                                         - sizeof(struct ip6);
> +	    m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
> +	                                         - sizeof(struct ip6);
> +	    ip6 = mtod(m, struct ip6 *);
> +	    ip6->ip_pl = tlen;
> +	    ip6->ip_dst = tcpiph_save.ti_dst6;
> +	    ip6->ip_src = tcpiph_save.ti_src6;
> +	    ip6->ip_nh = tcpiph_save.ti_nh6;
> +
> +	    (void) ip6_output((struct socket *)0, m, 0);

Is that "(void)" really necessary here? Also, I think you could simply
use "NULL" instead of "(struct socket *)0".

> +	    break;
> +
>  	default:
>  	    g_assert_not_reached();
>  	}
...

Just some cosmetic nits, patch generally looks fine to me, so:

Reviewed-by: Thomas Huth <thuth@redhat.com>

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 8/9] slirp: Adding IPv6 address for DNS relay
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 8/9] slirp: Adding IPv6 address for DNS relay Samuel Thibault
@ 2016-02-17  9:28   ` Thomas Huth
  2016-02-17  9:36     ` Samuel Thibault
  0 siblings, 1 reply; 38+ messages in thread
From: Thomas Huth @ 2016-02-17  9:28 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei, Jan Kiszka,
	Guillaume Subiron

On 14.02.2016 18:47, Samuel Thibault wrote:
> From: Guillaume Subiron <maethor@subiron.org>
> 
> This patch adds an IPv6 address to the DNS relay. in6_equal_dns() is
> developed using this Slirp attribute.
> sotranslate_in/out/accept() are also updated to manage the IPv6 case so the
> guest can be able to join the host using one of the Slirp addresses.
> 
> For now this only points to localhost. Further development will be needed to
> automatically fetch the IPv6 address from resolv.conf, and announce this via
> RDNSS.
> 
> Signed-off-by: Guillaume Subiron <maethor@subiron.org>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
>  slirp/ip6.h    |  5 ++++-
>  slirp/slirp.c  |  1 +
>  slirp/slirp.h  |  1 +
>  slirp/socket.c | 32 ++++++++++++++++++++++++++++++++
>  4 files changed, 38 insertions(+), 1 deletion(-)
> 
> diff --git a/slirp/ip6.h b/slirp/ip6.h
> index 9f7623f..ded6d78 100644
> --- a/slirp/ip6.h
> +++ b/slirp/ip6.h
> @@ -70,7 +70,10 @@ static inline bool in6_equal_mach(const struct in6_addr *a,
>    || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)\
>        && in6_equal_mach(a, &slirp->vhost_addr6, 64)))
>  
> -#define in6_equal_dns(a) 0
> +#define in6_equal_dns(a)\
> +    ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len)\
> +     || in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64))\
> +     && in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len))

Does this work properly if vprefix_len < 64 ? I think this rather should
be done similar to in6_equal_router(), i.e. something like:

#define in6_equal_dns(a)\
    ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len) && \
      in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len)) \
    || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)) && \
        in6_equal_mach(a, &slirp->vnameserver_addr6, 64))

?

 Thomas

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 7/9] slirp: Handle IPv6 in TCP functions
  2016-02-17  9:18   ` Thomas Huth
@ 2016-02-17  9:30     ` Samuel Thibault
  0 siblings, 0 replies; 38+ messages in thread
From: Samuel Thibault @ 2016-02-17  9:30 UTC (permalink / raw)
  To: Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, Dave Gilbert, Gonglei, Jan Kiszka,
	Huangpeng, Guillaume Subiron

Thomas Huth, on Wed 17 Feb 2016 10:18:20 +0100, wrote:
> > @@ -204,6 +218,20 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
> >  	    (void) ip_output((struct socket *)0, m);
> >  	    break;
> >  
> > +	case AF_INET6:
> > +	    m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
> > +	                                         - sizeof(struct ip6);
> > +	    m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
> > +	                                         - sizeof(struct ip6);
> > +	    ip6 = mtod(m, struct ip6 *);
> > +	    ip6->ip_pl = tlen;
> > +	    ip6->ip_dst = tcpiph_save.ti_dst6;
> > +	    ip6->ip_src = tcpiph_save.ti_src6;
> > +	    ip6->ip_nh = tcpiph_save.ti_nh6;
> > +
> > +	    (void) ip6_output((struct socket *)0, m, 0);
> 
> Is that "(void)" really necessary here? Also, I think you could simply
> use "NULL" instead of "(struct socket *)0".

Indeed. That was just for coherency with the ip_output call above.
I've now updated that line too.

Samuel

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 8/9] slirp: Adding IPv6 address for DNS relay
  2016-02-17  9:28   ` Thomas Huth
@ 2016-02-17  9:36     ` Samuel Thibault
  2016-02-19  0:26       ` Samuel Thibault
  0 siblings, 1 reply; 38+ messages in thread
From: Samuel Thibault @ 2016-02-17  9:36 UTC (permalink / raw)
  To: Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, Dave Gilbert, Gonglei, Jan Kiszka,
	Huangpeng, Guillaume Subiron

Thomas Huth, on Wed 17 Feb 2016 10:28:26 +0100, wrote:
> On 14.02.2016 18:47, Samuel Thibault wrote:
> > From: Guillaume Subiron <maethor@subiron.org>
> > 
> > This patch adds an IPv6 address to the DNS relay. in6_equal_dns() is
> > developed using this Slirp attribute.
> > sotranslate_in/out/accept() are also updated to manage the IPv6 case so the
> > guest can be able to join the host using one of the Slirp addresses.
> > 
> > For now this only points to localhost. Further development will be needed to
> > automatically fetch the IPv6 address from resolv.conf, and announce this via
> > RDNSS.
> > 
> > Signed-off-by: Guillaume Subiron <maethor@subiron.org>
> > Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> > ---
> >  slirp/ip6.h    |  5 ++++-
> >  slirp/slirp.c  |  1 +
> >  slirp/slirp.h  |  1 +
> >  slirp/socket.c | 32 ++++++++++++++++++++++++++++++++
> >  4 files changed, 38 insertions(+), 1 deletion(-)
> > 
> > diff --git a/slirp/ip6.h b/slirp/ip6.h
> > index 9f7623f..ded6d78 100644
> > --- a/slirp/ip6.h
> > +++ b/slirp/ip6.h
> > @@ -70,7 +70,10 @@ static inline bool in6_equal_mach(const struct in6_addr *a,
> >    || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)\
> >        && in6_equal_mach(a, &slirp->vhost_addr6, 64)))
> >  
> > -#define in6_equal_dns(a) 0
> > +#define in6_equal_dns(a)\
> > +    ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len)\
> > +     || in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64))\
> > +     && in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len))
> 
> Does this work properly if vprefix_len < 64 ? I think this rather should
> be done similar to in6_equal_router(), i.e. something like:
> 
> #define in6_equal_dns(a)\
>     ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len) && \
>       in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len)) \
>     || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)) && \
>         in6_equal_mach(a, &slirp->vnameserver_addr6, 64))
> 
> ?

Right, I guess the change in the in6_equal_router didn't get propagated
to this patch.

That's now like this in my tree:

diff --git a/slirp/ip6.h b/slirp/ip6.h
index 9f7623f..9e4844e 100644
--- a/slirp/ip6.h
+++ b/slirp/ip6.h
@@ -70,7 +70,11 @@ static inline bool in6_equal_mach(const struct in6_addr *a,
   || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)\
       && in6_equal_mach(a, &slirp->vhost_addr6, 64)))
 
-#define in6_equal_dns(a) 0
+#define in6_equal_dns(a)\
+    ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len)\
+      && in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len))\
+  || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64))\
+      && in6_equal_mach(a, &slirp->vnameserver_addr6, 64))
 
 #define in6_equal_host(a)\
     (in6_equal_router(a) || in6_equal_dns(a))

Samuel

^ permalink raw reply related	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses Samuel Thibault
@ 2016-02-17 11:59   ` Thomas Huth
  2016-02-19  0:35     ` Samuel Thibault
  0 siblings, 1 reply; 38+ messages in thread
From: Thomas Huth @ 2016-02-17 11:59 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, Huangpeng, Yann Bordenave,
	Gonglei, Jan Kiszka, Guillaume Subiron

On 14.02.2016 18:47, Samuel Thibault wrote:
> From: Yann Bordenave <meow@meowstars.org>
> 
> This patch adds parameters to manage some new options in the qemu -net
> command.
> Slirp IPv6 address, network prefix, and DNS IPv6 address can be given in
> argument to the qemu command.
> Defaults parameters are respectively fec0::2, fec0::, /64 and fec0::3.
> 
> Signed-off-by: Yann Bordenave <meow@meowstars.org>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
>  net/net.c        | 31 +++++++++++++++++++++++++++++++
>  net/slirp.c      | 50 ++++++++++++++++++++++++++++++++++++++++++++------
>  qapi-schema.json | 40 ++++++++++++++++++++++++++--------------
>  qemu-options.hx  | 18 ++++++++++++++++--
>  slirp/libslirp.h |  8 +++++---
>  slirp/slirp.c    | 16 +++++++++-------
>  6 files changed, 131 insertions(+), 32 deletions(-)
> 
> diff --git a/net/net.c b/net/net.c
> index c5e414f..a097971 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -1060,6 +1060,37 @@ int net_client_init(QemuOpts *opts, int is_netdev, Error **errp)
>      int ret = -1;
>  
>      {
> +        /* Parse convenience option format ip6-net=fec0::0[/64] */
> +        const char *ip6_net = qemu_opt_get(opts, "ip6-net");
> +
> +        if (ip6_net) {
> +            char buf[strlen(ip6_net) + 1];
> +
> +            if (get_str_sep(buf, sizeof(buf), &ip6_net, '/') < 0) {
> +                /* Default 64bit prefix length.  */
> +                qemu_opt_set(opts, "ip6-prefix", ip6_net, &error_abort);
> +                qemu_opt_set_number(opts, "ip6-prefixlen", 64, &error_abort);
> +            } else {
> +                /* User-specified prefix length.  */
> +                unsigned long len;
> +                int err;
> +
> +                qemu_opt_set(opts, "ip6-prefix", buf, &error_abort);
> +                err = qemu_strtoul(ip6_net, NULL, 10, &len);
> +
> +                if (err) {
> +                    error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
> +                              "ip6-prefix", "a number");
> +                } else {
> +                    qemu_opt_set_number(opts, "ip6-prefixlen", len,
> +                                        &error_abort);
> +                }
> +            }
> +            qemu_opt_unset(opts, "ip6-net");
> +        }
> +    }
> +
> +    {
>          OptsVisitor *ov = opts_visitor_new(opts);
>  
>          net_visit(opts_get_visitor(ov), is_netdev, &object, &err);
> diff --git a/net/slirp.c b/net/slirp.c
> index 6b51fbc..076dd27 100644
> --- a/net/slirp.c
> +++ b/net/slirp.c
> @@ -135,17 +135,23 @@ static NetClientInfo net_slirp_info = {
>  static int net_slirp_init(NetClientState *peer, const char *model,
>                            const char *name, int restricted,
>                            const char *vnetwork, const char *vhost,
> +                          const char *vprefix6, int vprefix6_len,
> +                          const char *vhost6,
>                            const char *vhostname, const char *tftp_export,
>                            const char *bootfile, const char *vdhcp_start,
> -                          const char *vnameserver, const char *smb_export,
> -                          const char *vsmbserver, const char **dnssearch)
> +                          const char *vnameserver, const char *vnameserver6,
> +                          const char *smb_export, const char *vsmbserver,
> +                          const char **dnssearch)
>  {
>      /* default settings according to historic slirp */
>      struct in_addr net  = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
>      struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
>      struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
> +    struct in6_addr ip6_prefix;
> +    struct in6_addr ip6_host;
>      struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
>      struct in_addr dns  = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
> +    struct in6_addr ip6_dns;
>  #ifndef _WIN32
>      struct in_addr smbsrv = { .s_addr = 0 };
>  #endif
> @@ -213,6 +219,27 @@ static int net_slirp_init(NetClientState *peer, const char *model,
>          return -1;
>      }
>  
> +    if (!vprefix6) {
> +        vprefix6 = "fec0::";
> +    }
> +    if (!inet_pton(AF_INET6, vprefix6, &ip6_prefix)) {
> +        return -1;
> +    }
> +
> +    if (!vprefix6_len) {
> +        vprefix6_len = 64;
> +    }
> +    if (vprefix6_len < 0 || vprefix6_len > 128) {
> +        return -1;
> +    }
> +
> +    if (!vhost6) {
> +        vhost6 = "fec0::2";
> +    }
> +    if (!inet_pton(AF_INET6, vhost6, &ip6_host)) {
> +        return -1;
> +    }

The IPv4 code seems to have a sanity check that the vhost address is
within the same net as specified with the "net=" parameter... maybe the
IPv6 part should have that, too? Or use the prefix from "ip6-net=" here
if ip6-host has not been specified manually?

>      if (vnameserver && !inet_aton(vnameserver, &dns)) {
>          return -1;
>      }
> @@ -221,6 +248,13 @@ static int net_slirp_init(NetClientState *peer, const char *model,
>          return -1;
>      }
>  
> +    if (!vnameserver6) {
> +        vnameserver6 = "fec0::3";
> +    }
> +    if (!inet_pton(AF_INET6, vnameserver6, &ip6_dns)) {
> +        return -1;
> +    }

dito?

>      if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) {
>          return -1;
>      }
> @@ -243,8 +277,10 @@ static int net_slirp_init(NetClientState *peer, const char *model,
>  
>      s = DO_UPCAST(SlirpState, nc, nc);
>  
> -    s->slirp = slirp_init(restricted, net, mask, host, vhostname,
> -                          tftp_export, bootfile, dhcp, dns, dnssearch, s);
> +    s->slirp = slirp_init(restricted, net, mask, host,
> +                          ip6_prefix, vprefix6_len, ip6_host,
> +                          vhostname, tftp_export, bootfile, dhcp,
> +                          dns, ip6_dns, dnssearch, s);
>      QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
>  
>      for (config = slirp_configs; config; config = config->next) {
> @@ -761,8 +797,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->hostname, user->tftp,
> -                         user->bootfile, user->dhcpstart, user->dns, user->smb,
> +                         user->host, user->ip6_prefix, user->ip6_prefixlen,
> +                         user->ip6_host, user->hostname, user->tftp,
> +                         user->bootfile, user->dhcpstart,
> +                         user->dns, user->ip6_dns, user->smb,
>                           user->smbserver, dnssearch);
>  
>      while (slirp_configs) {
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 8d04897..a62c2ec 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -2399,6 +2399,14 @@
>  # @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)
> +#
> +# @ip6-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)
> +#
> +# @ip6-dns: #optional guest-visible IPv6 address of the virtual nameserver (since 2.6)
> +#
>  # @smb: #optional root directory of the built-in SMB server
>  #
>  # @smbserver: #optional IP address of the built-in SMB server
> @@ -2412,20 +2420,24 @@
>  ##
>  { 'struct': 'NetdevUserOptions',
>    'data': {
> -    '*hostname':  'str',
> -    '*restrict':  'bool',
> -    '*ip':        'str',
> -    '*net':       'str',
> -    '*host':      'str',
> -    '*tftp':      'str',
> -    '*bootfile':  'str',
> -    '*dhcpstart': 'str',
> -    '*dns':       'str',
> -    '*dnssearch': ['String'],
> -    '*smb':       'str',
> -    '*smbserver': 'str',
> -    '*hostfwd':   ['String'],
> -    '*guestfwd':  ['String'] } }
> +    '*hostname':        'str',
> +    '*restrict':        'bool',
> +    '*ip':              'str',
> +    '*net':             'str',
> +    '*host':            'str',
> +    '*tftp':            'str',
> +    '*bootfile':        'str',
> +    '*dhcpstart':       'str',
> +    '*dns':             'str',
> +    '*dnssearch':       ['String'],
> +    '*ip6-prefix':      'str',
> +    '*ip6-prefixlen':   'int',
> +    '*ip6-host':        'str',
> +    '*ip6-dns':         'str',
> +    '*smb':             'str',
> +    '*smbserver':       'str',
> +    '*hostfwd':         ['String'],
> +    '*guestfwd':        ['String'] } }
>  
>  ##
>  # @NetdevTapOptions
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 733a194..de9e314 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -1542,8 +1542,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][,restrict=on|off]\n"
> -    "         [,hostname=host][,dhcpstart=addr][,dns=addr][,dnssearch=domain][,tftp=dir]\n"
> +    "-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"
>      "         [,bootfile=f][,hostfwd=rule][,guestfwd=rule]"
>  #ifndef _WIN32
>                                               "[,smb=dir[,smbserver=addr]]\n"
> @@ -1700,6 +1701,14 @@ 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 ip6-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.

At least this does currently not match the code - the current default is
always fec0::2, no matter what has been specified for "ip6-net=...".

>  @item restrict=on|off
>  If this option is enabled, the guest will be isolated, i.e. it will not be
>  able to contact the host and no guest IP packets will be routed over the host
> @@ -1717,6 +1726,11 @@ 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}
> +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.

dito

>  @item dnssearch=@var{domain}
>  Provides an entry for the domain-search list sent by the built-in
>  DHCP server. More than one domain suffix can be transmitted by specifying
...

The other parts of the patch look good to me.

 Thomas

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 8/9] slirp: Adding IPv6 address for DNS relay
  2016-02-17  9:36     ` Samuel Thibault
@ 2016-02-19  0:26       ` Samuel Thibault
  0 siblings, 0 replies; 38+ messages in thread
From: Samuel Thibault @ 2016-02-19  0:26 UTC (permalink / raw)
  To: Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, Dave Gilbert, Gonglei, Jan Kiszka,
	Huangpeng, Guillaume Subiron

Samuel Thibault, on Wed 17 Feb 2016 10:36:35 +0100, wrote:
> That's now like this in my tree:
> 
> diff --git a/slirp/ip6.h b/slirp/ip6.h
> index 9f7623f..9e4844e 100644
> --- a/slirp/ip6.h
> +++ b/slirp/ip6.h
> @@ -70,7 +70,11 @@ static inline bool in6_equal_mach(const struct in6_addr *a,
>    || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)\
>        && in6_equal_mach(a, &slirp->vhost_addr6, 64)))
>  
> -#define in6_equal_dns(a) 0
> +#define in6_equal_dns(a)\
> +    ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len)\
> +      && in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len))\
> +  || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64))\
> +      && in6_equal_mach(a, &slirp->vnameserver_addr6, 64))

Oops, I meant

+#define in6_equal_dns(a)\
+    ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len)\
+      && in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len))\
+  || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)\
+      && in6_equal_mach(a, &slirp->vnameserver_addr6, 64)))

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses
  2016-02-17 11:59   ` Thomas Huth
@ 2016-02-19  0:35     ` Samuel Thibault
  0 siblings, 0 replies; 38+ messages in thread
From: Samuel Thibault @ 2016-02-19  0:35 UTC (permalink / raw)
  To: Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, Dave Gilbert, Yann Bordenave,
	Gonglei, Jan Kiszka, Huangpeng, Guillaume Subiron

Thomas Huth, on Wed 17 Feb 2016 12:59:04 +0100, wrote:
> The IPv4 code seems to have a sanity check that the vhost address is
> within the same net as specified with the "net=" parameter... maybe the
> IPv6 part should have that, too? Or use the prefix from "ip6-net=" here
> if ip6-host has not been specified manually?

I'd say the latter indeed.  I have reworked this part of the code, and
then the implementation matches the documentation :)

@@ -235,6 +242,52 @@ static int net_slirp_init(NetClientState *peer, const char *model,
     }
 #endif
 
+
+    if (!vprefix6) {
+        vprefix6 = "fec0::";
+    }
+    if (!inet_pton(AF_INET6, vprefix6, &ip6_prefix)) {
+        return -1;
+    }
+
+    if (!vprefix6_len) {
+        vprefix6_len = 64;
+    }
+    if (vprefix6_len < 0 || vprefix6_len > 128) {
+        return -1;
+    }
+
+    if (vhost6) {
+        if (!inet_pton(AF_INET6, vhost6, &ip6_host)) {
+            return -1;
+        }
+        if (!in6_equal_net(&ip6_prefix, &ip6_host, vprefix6_len)) {
+            return -1;
+        }
+    } else {
+        if (vprefix6_len > 126) {
+            return -1;
+        }
+        ip6_host = ip6_prefix;
+        ip6_host.s6_addr[15] |= 2;
+    }
+
+    if (vnameserver6) {
+        if (!inet_pton(AF_INET6, vnameserver6, &ip6_dns)) {
+            return -1;
+        }
+        if (!in6_equal_net(&ip6_prefix, &ip6_dns, vprefix6_len)) {
+            return -1;
+        }
+    } else {
+        if (vprefix6_len > 126) {
+            return -1;
+        }
+        ip6_dns = ip6_prefix;
+        ip6_dns.s6_addr[15] |= 3;
+    }
+
+
     nc = qemu_new_net_client(&net_slirp_info, peer, model, name);
 
     snprintf(nc->info_str, sizeof(nc->info_str),

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union Samuel Thibault
@ 2016-02-19  0:36   ` Samuel Thibault
  2016-02-19 13:44   ` Thomas Huth
  1 sibling, 0 replies; 38+ messages in thread
From: Samuel Thibault @ 2016-02-19  0:36 UTC (permalink / raw)
  To: qemu-devel
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei,
	Jan Kiszka, Guillaume Subiron

Hello,

Just to make sure: we have not received comments on this patch.

(that said, it's the most complex part of the series, so I'm not
surprised if it takes more time :) )

Samuel

Samuel Thibault, on Sun 14 Feb 2016 18:47:38 +0100, wrote:
> From: Guillaume Subiron <maethor@subiron.org>
> 
> This patch factorizes the tcpiphdr structure to put the IPv4 fields in
> an union, for addition of version 6 in further patch.
> Using some macros, retrocompatibility of the existing code is assured.
> 
> This patch also fixes the SLIRP_MSIZE and margin computation in various
> functions, and makes them compatible with the new tcpiphdr structure,
> whose size will be bigger than sizeof(struct tcphdr) + sizeof(struct ip)
> 
> Signed-off-by: Guillaume Subiron <maethor@subiron.org>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
>  slirp/if.h         |  4 ++--
>  slirp/mbuf.c       |  3 ++-
>  slirp/slirp.c      | 15 ++++++++-------
>  slirp/socket.c     | 13 ++++++++++++-
>  slirp/tcp_input.c  | 31 ++++++++++++++++++++-----------
>  slirp/tcp_output.c | 18 +++++++++++++-----
>  slirp/tcp_subr.c   | 31 ++++++++++++++++++++++---------
>  slirp/tcpip.h      | 31 +++++++++++++++++++++++--------
>  8 files changed, 102 insertions(+), 44 deletions(-)
> 
> diff --git a/slirp/if.h b/slirp/if.h
> index 3327023..c7a5c57 100644
> --- a/slirp/if.h
> +++ b/slirp/if.h
> @@ -17,7 +17,7 @@
>  #define IF_MRU 1500
>  #define	IF_COMP IF_AUTOCOMP	/* Flags for compression */
>  
> -/* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
> -#define IF_MAXLINKHDR (2 + 14 + 40)
> +/* 2 for alignment, 14 for ethernet */
> +#define IF_MAXLINKHDR (2 + ETH_HLEN)
>  
>  #endif
> diff --git a/slirp/mbuf.c b/slirp/mbuf.c
> index c959758..f081c69 100644
> --- a/slirp/mbuf.c
> +++ b/slirp/mbuf.c
> @@ -24,7 +24,8 @@
>   * Find a nice value for msize
>   * XXX if_maxlinkhdr already in mtu
>   */
> -#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6)
> +#define SLIRP_MSIZE\
> +    (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)
>  
>  void
>  m_init(Slirp *slirp)
> diff --git a/slirp/slirp.c b/slirp/slirp.c
> index 5f42ada..c2c4597 100644
> --- a/slirp/slirp.c
> +++ b/slirp/slirp.c
> @@ -754,15 +754,16 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
>          m = m_get(slirp);
>          if (!m)
>              return;
> -        /* Note: we add to align the IP header */
> -        if (M_FREEROOM(m) < pkt_len + 2) {
> -            m_inc(m, pkt_len + 2);
> +        /* Note: we add 2 to align the IP header on 4 bytes,
> +         * and add the margin for the tcpiphdr overhead  */
> +        if (M_FREEROOM(m) < pkt_len + TCPIPHDR_DELTA + 2) {
> +            m_inc(m, pkt_len + TCPIPHDR_DELTA + 2);
>          }
> -        m->m_len = pkt_len + 2;
> -        memcpy(m->m_data + 2, pkt, pkt_len);
> +        m->m_len = pkt_len + TCPIPHDR_DELTA + 2;
> +        memcpy(m->m_data + TCPIPHDR_DELTA + 2, pkt, pkt_len);
>  
> -        m->m_data += 2 + ETH_HLEN;
> -        m->m_len -= 2 + ETH_HLEN;
> +        m->m_data += TCPIPHDR_DELTA + 2 + ETH_HLEN;
> +        m->m_len -= TCPIPHDR_DELTA + 2 + ETH_HLEN;
>  
>          if (proto == ETH_P_IP) {
>              ip_input(m);
> diff --git a/slirp/socket.c b/slirp/socket.c
> index b79ddec..d4b02c8 100644
> --- a/slirp/socket.c
> +++ b/slirp/socket.c
> @@ -483,7 +483,18 @@ sorecvfrom(struct socket *so)
>  	  if (!m) {
>  	      return;
>  	  }
> -	  m->m_data += IF_MAXLINKHDR;
> +	  switch (so->so_ffamily) {
> +	  case AF_INET:
> +	      m->m_data += IF_MAXLINKHDR + sizeof(struct udpiphdr);
> +	      break;
> +	  case AF_INET6:
> +	      m->m_data += IF_MAXLINKHDR + sizeof(struct ip6)
> +	                                 + sizeof(struct udphdr);
> +	      break;
> +	  default:
> +	      g_assert_not_reached();
> +	      break;
> +	  }
>  
>  	  /*
>  	   * XXX Shouldn't FIONREAD packets destined for port 53,
> diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
> index 5f845da..26b0c8b 100644
> --- a/slirp/tcp_input.c
> +++ b/slirp/tcp_input.c
> @@ -256,11 +256,6 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
>  	}
>  	slirp = m->slirp;
>  
> -	/*
> -	 * Get IP and TCP header together in first mbuf.
> -	 * Note: IP leaves IP header in first mbuf.
> -	 */
> -	ti = mtod(m, struct tcpiphdr *);
>  	if (iphlen > sizeof(struct ip )) {
>  	  ip_stripoptions(m, (struct mbuf *)0);
>  	  iphlen=sizeof(struct ip );
> @@ -277,14 +272,28 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
>  	save_ip.ip_len+= iphlen;
>  
>  	/*
> +	 * Get IP and TCP header together in first mbuf.
> +	 * Note: IP leaves IP header in first mbuf.
> +	 */
> +	m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip)
> +	                                     + sizeof(struct tcphdr));
> +	m->m_len += sizeof(struct tcpiphdr) - (sizeof(struct ip)
> +	                                    + sizeof(struct tcphdr));
> +	ti = mtod(m, struct tcpiphdr *);
> +
> +	/*
>  	 * Checksum extended TCP header and data.
>  	 */
> -	tlen = ((struct ip *)ti)->ip_len;
> -        tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
> -        memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
> -	ti->ti_x1 = 0;
> +	tlen = ip->ip_len;
> +	tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
> +	memset(&ti->ih_mbuf, 0 , sizeof(struct mbuf_ptr));
> +	memset(&ti->ti, 0, sizeof(ti->ti));
> +	ti->ti_x0 = 0;
> +	ti->ti_src = save_ip.ip_src;
> +	ti->ti_dst = save_ip.ip_dst;
> +	ti->ti_pr = save_ip.ip_p;
>  	ti->ti_len = htons((uint16_t)tlen);
> -	len = sizeof(struct ip ) + tlen;
> +	len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
>  	if(cksum(m, len)) {
>  	  goto drop;
>  	}
> @@ -1475,7 +1484,7 @@ tcp_mss(struct tcpcb *tp, u_int offer)
>  	DEBUG_ARG("tp = %p", tp);
>  	DEBUG_ARG("offer = %d", offer);
>  
> -	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcpiphdr);
> +	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr) + sizeof(struct ip);
>  	if (offer)
>  		mss = min(mss, offer);
>  	mss = max(mss, 32);
> diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
> index 34e4d2e..7fc6a87 100644
> --- a/slirp/tcp_output.c
> +++ b/slirp/tcp_output.c
> @@ -448,15 +448,23 @@ send:
>  	 */
>  	m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
>  
> -    {
> +	struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
> +	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
> +	                                     - sizeof(struct ip);
> +	m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
> +	                                     - sizeof(struct ip);
> +	struct ip *ip = mtod(m, struct ip *);
>  
> -	((struct ip *)ti)->ip_len = m->m_len;
> +	ip->ip_len = m->m_len;
> +	ip->ip_dst = tcpiph_save.ti_dst;
> +	ip->ip_src = tcpiph_save.ti_src;
> +	ip->ip_p = tcpiph_save.ti_pr;
>  
> -	((struct ip *)ti)->ip_ttl = IPDEFTTL;
> -	((struct ip *)ti)->ip_tos = so->so_iptos;
> +	ip->ip_ttl = IPDEFTTL;
> +	ip->ip_tos = so->so_iptos;
>  
>  	error = ip_output(so, m);
> -    }
> +
>  	if (error) {
>  out:
>  		return (error);
> diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
> index b1aa1f2..cd021df 100644
> --- a/slirp/tcp_subr.c
> +++ b/slirp/tcp_subr.c
> @@ -76,9 +76,10 @@ tcp_template(struct tcpcb *tp)
>  	register struct tcpiphdr *n = &tp->t_template;
>  
>  	n->ti_mbuf = NULL;
> -	n->ti_x1 = 0;
> +	memset(&n->ti, 0, sizeof(n->ti));
> +	n->ti_x0 = 0;
>  	n->ti_pr = IPPROTO_TCP;
> -	n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
> +	n->ti_len = htons(sizeof(struct tcphdr));
>  	n->ti_src = so->so_faddr;
>  	n->ti_dst = so->so_laddr;
>  	n->ti_sport = so->so_fport;
> @@ -131,6 +132,7 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
>  		m->m_data += IF_MAXLINKHDR;
>  		*mtod(m, struct tcpiphdr *) = *ti;
>  		ti = mtod(m, struct tcpiphdr *);
> +		memset(&ti->ti, 0, sizeof(ti->ti));
>  		flags = TH_ACK;
>  	} else {
>  		/*
> @@ -150,8 +152,8 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
>  	tlen += sizeof (struct tcpiphdr);
>  	m->m_len = tlen;
>  
> -        ti->ti_mbuf = NULL;
> -	ti->ti_x1 = 0;
> +	ti->ti_mbuf = NULL;
> +	ti->ti_x0 = 0;
>  	ti->ti_seq = htonl(seq);
>  	ti->ti_ack = htonl(ack);
>  	ti->ti_x2 = 0;
> @@ -164,12 +166,23 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
>  	ti->ti_urp = 0;
>  	ti->ti_sum = 0;
>  	ti->ti_sum = cksum(m, tlen);
> -	((struct ip *)ti)->ip_len = tlen;
>  
> -	if(flags & TH_RST)
> -	  ((struct ip *)ti)->ip_ttl = MAXTTL;
> -	else
> -	  ((struct ip *)ti)->ip_ttl = IPDEFTTL;
> +	struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
> +	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
> +	                                     - sizeof(struct ip);
> +	m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
> +	                                     - sizeof(struct ip);
> +	struct ip *ip = mtod(m, struct ip *);
> +	ip->ip_len = tlen;
> +	ip->ip_dst = tcpiph_save.ti_dst;
> +	ip->ip_src = tcpiph_save.ti_src;
> +	ip->ip_p = tcpiph_save.ti_pr;
> +
> +	if (flags & TH_RST) {
> +		ip->ip_ttl = MAXTTL;
> +	} else {
> +		ip->ip_ttl = IPDEFTTL;
> +	}
>  
>  	(void) ip_output((struct socket *)0, m);
>  }
> diff --git a/slirp/tcpip.h b/slirp/tcpip.h
> index 7974ce3..3c5d127 100644
> --- a/slirp/tcpip.h
> +++ b/slirp/tcpip.h
> @@ -37,15 +37,23 @@
>   * Tcp+ip header, after ip options removed.
>   */
>  struct tcpiphdr {
> -	struct 	ipovly ti_i;		/* overlaid ip structure */
> -	struct	tcphdr ti_t;		/* tcp header */
> +    struct mbuf_ptr ih_mbuf;	/* backpointer to mbuf */
> +    union {
> +        struct {
> +            struct  in_addr ih_src; /* source internet address */
> +            struct  in_addr ih_dst; /* destination internet address */
> +            uint8_t ih_x1;          /* (unused) */
> +            uint8_t ih_pr;          /* protocol */
> +        } ti_i4;
> +    } ti;
> +    uint16_t    ti_x0;
> +    uint16_t    ti_len;             /* protocol length */
> +    struct      tcphdr ti_t;        /* tcp header */
>  };
> -#define	ti_mbuf		ti_i.ih_mbuf.mptr
> -#define	ti_x1		ti_i.ih_x1
> -#define	ti_pr		ti_i.ih_pr
> -#define	ti_len		ti_i.ih_len
> -#define	ti_src		ti_i.ih_src
> -#define	ti_dst		ti_i.ih_dst
> +#define	ti_mbuf		ih_mbuf.mptr
> +#define	ti_pr		ti.ti_i4.ih_pr
> +#define	ti_src		ti.ti_i4.ih_src
> +#define	ti_dst		ti.ti_i4.ih_dst
>  #define	ti_sport	ti_t.th_sport
>  #define	ti_dport	ti_t.th_dport
>  #define	ti_seq		ti_t.th_seq
> @@ -65,6 +73,13 @@ struct tcpiphdr {
>  #define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink*)(T))
>  #define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr*)(T))
>  
> +/* This is the difference between the size of a tcpiphdr structure, and the
> + * size of actual ip+tcp headers, rounded up since we need to align data.  */
> +#define TCPIPHDR_DELTA\
> +    (max(0,\
> +         (sizeof(struct tcpiphdr)\
> +          - sizeof(struct ip) - sizeof(struct tcphdr) + 3) & ~3))
> +
>  /*
>   * Just a clean way to get to the first byte
>   * of the packet
> -- 
> 2.7.0
> 
> 

-- 
Samuel
> X..., c'est un millefeuille avec une couche de crème patissière, une
> de sauce tomate et une de crème d'anchois... Mais c'est vrai que
> c'est un système ouvert: tu peux y rajouter des pépites de chocolat...
-+- Ol in Guide du linuxien pervers - "Remettez m'en une couche !" -+-

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union Samuel Thibault
  2016-02-19  0:36   ` Samuel Thibault
@ 2016-02-19 13:44   ` Thomas Huth
  2016-02-22  1:48     ` Samuel Thibault
  1 sibling, 1 reply; 38+ messages in thread
From: Thomas Huth @ 2016-02-19 13:44 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei, Jan Kiszka,
	Guillaume Subiron

On 14.02.2016 18:47, Samuel Thibault wrote:
> From: Guillaume Subiron <maethor@subiron.org>
> 
> This patch factorizes the tcpiphdr structure to put the IPv4 fields in
> an union, for addition of version 6 in further patch.
> Using some macros, retrocompatibility of the existing code is assured.
> 
> This patch also fixes the SLIRP_MSIZE and margin computation in various
> functions, and makes them compatible with the new tcpiphdr structure,
> whose size will be bigger than sizeof(struct tcphdr) + sizeof(struct ip)
> 
> Signed-off-by: Guillaume Subiron <maethor@subiron.org>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
>  slirp/if.h         |  4 ++--
>  slirp/mbuf.c       |  3 ++-
>  slirp/slirp.c      | 15 ++++++++-------
>  slirp/socket.c     | 13 ++++++++++++-
>  slirp/tcp_input.c  | 31 ++++++++++++++++++++-----------
>  slirp/tcp_output.c | 18 +++++++++++++-----
>  slirp/tcp_subr.c   | 31 ++++++++++++++++++++++---------
>  slirp/tcpip.h      | 31 +++++++++++++++++++++++--------
>  8 files changed, 102 insertions(+), 44 deletions(-)
> 
> diff --git a/slirp/if.h b/slirp/if.h
> index 3327023..c7a5c57 100644
> --- a/slirp/if.h
> +++ b/slirp/if.h
> @@ -17,7 +17,7 @@
>  #define IF_MRU 1500
>  #define	IF_COMP IF_AUTOCOMP	/* Flags for compression */
>  
> -/* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
> -#define IF_MAXLINKHDR (2 + 14 + 40)
> +/* 2 for alignment, 14 for ethernet */
> +#define IF_MAXLINKHDR (2 + ETH_HLEN)
>  
>  #endif
> diff --git a/slirp/mbuf.c b/slirp/mbuf.c
> index c959758..f081c69 100644
> --- a/slirp/mbuf.c
> +++ b/slirp/mbuf.c
> @@ -24,7 +24,8 @@
>   * Find a nice value for msize
>   * XXX if_maxlinkhdr already in mtu

Maybe you should now remove the XXX line, now that the size of the
TCP/IP headers is counted via IF_MTU instead?

>   */
> -#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6)
> +#define SLIRP_MSIZE\
> +    (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)
>  
>  void
>  m_init(Slirp *slirp)
...
> diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
> index 5f845da..26b0c8b 100644
> --- a/slirp/tcp_input.c
> +++ b/slirp/tcp_input.c
> @@ -256,11 +256,6 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
>  	}
>  	slirp = m->slirp;
>  
> -	/*
> -	 * Get IP and TCP header together in first mbuf.
> -	 * Note: IP leaves IP header in first mbuf.
> -	 */
> -	ti = mtod(m, struct tcpiphdr *);
>  	if (iphlen > sizeof(struct ip )) {
>  	  ip_stripoptions(m, (struct mbuf *)0);
>  	  iphlen=sizeof(struct ip );
> @@ -277,14 +272,28 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
>  	save_ip.ip_len+= iphlen;
>  
>  	/*
> +	 * Get IP and TCP header together in first mbuf.
> +	 * Note: IP leaves IP header in first mbuf.
> +	 */
> +	m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip)
> +	                                     + sizeof(struct tcphdr));
> +	m->m_len += sizeof(struct tcpiphdr) - (sizeof(struct ip)
> +	                                    + sizeof(struct tcphdr));

I'm somewhat having a hard time to understand the  "+ sizeof(struct
tcphdr))" here.

In the tcp_output.c code, there is this:

	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
	                                     - sizeof(struct ip);

So with my limited point of view, I'd rather expect this here in
tcp_input.c:

	m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip)
	                                     - sizeof(struct tcphdr));
i.e. "-" instead of "+" here ----------------^

Could you maybe elaborate a little bit on the above calculation? Or is
it just a bug?

> +	ti = mtod(m, struct tcpiphdr *);
> +
> +	/*
>  	 * Checksum extended TCP header and data.
>  	 */
> -	tlen = ((struct ip *)ti)->ip_len;
> -        tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
> -        memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
> -	ti->ti_x1 = 0;
> +	tlen = ip->ip_len;
> +	tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
> +	memset(&ti->ih_mbuf, 0 , sizeof(struct mbuf_ptr));
> +	memset(&ti->ti, 0, sizeof(ti->ti));
> +	ti->ti_x0 = 0;
> +	ti->ti_src = save_ip.ip_src;
> +	ti->ti_dst = save_ip.ip_dst;
> +	ti->ti_pr = save_ip.ip_p;
>  	ti->ti_len = htons((uint16_t)tlen);
> -	len = sizeof(struct ip ) + tlen;
> +	len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
>  	if(cksum(m, len)) {
>  	  goto drop;
>  	}
> @@ -1475,7 +1484,7 @@ tcp_mss(struct tcpcb *tp, u_int offer)
>  	DEBUG_ARG("tp = %p", tp);
>  	DEBUG_ARG("offer = %d", offer);
>  
> -	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcpiphdr);
> +	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr) + sizeof(struct ip);
>  	if (offer)
>  		mss = min(mss, offer);
>  	mss = max(mss, 32);
> diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
> index 34e4d2e..7fc6a87 100644
> --- a/slirp/tcp_output.c
> +++ b/slirp/tcp_output.c
> @@ -448,15 +448,23 @@ send:
>  	 */
>  	m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
>  
> -    {
> +	struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
> +	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
> +	                                     - sizeof(struct ip);
> +	m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
> +	                                     - sizeof(struct ip);
> +	struct ip *ip = mtod(m, struct ip *);
>  
> -	((struct ip *)ti)->ip_len = m->m_len;
> +	ip->ip_len = m->m_len;
> +	ip->ip_dst = tcpiph_save.ti_dst;
> +	ip->ip_src = tcpiph_save.ti_src;
> +	ip->ip_p = tcpiph_save.ti_pr;
>  
> -	((struct ip *)ti)->ip_ttl = IPDEFTTL;
> -	((struct ip *)ti)->ip_tos = so->so_iptos;
> +	ip->ip_ttl = IPDEFTTL;
> +	ip->ip_tos = so->so_iptos;
>  
>  	error = ip_output(so, m);
> -    }
> +
>  	if (error) {
>  out:
>  		return (error);

 Thomas

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
  2016-02-16 11:36   ` Thomas Huth
@ 2016-02-19 13:57   ` Thomas Huth
  1 sibling, 0 replies; 38+ messages in thread
From: Thomas Huth @ 2016-02-19 13:57 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei, Jan Kiszka,
	Guillaume Subiron

On 14.02.2016 18:47, Samuel Thibault wrote:
> From: Guillaume Subiron <maethor@subiron.org>
> 
> This patch adds the functions needed to handle IPv6 packets. ICMPv6 and
> NDP headers are implemented.
> 
> Slirp is now able to send NDP Router or Neighbor Advertisement when it
> receives Router or Neighbor Solicitation. Using a 64bit-sized IPv6
> prefix, the guest is now able to perform stateless autoconfiguration
> (SLAAC) and to compute its IPv6 address.
> 
> This patch adds an ndp_table, mainly inspired by arp_table, to keep an
> NDP cache and manage network address resolution.
> Slirp regularly sends NDP Neighbor Advertisement, as recommended by the
> RFC, to make the guest refresh its route.
> 
> This also adds ip6_cksum() to compute ICMPv6 checksums using IPv6
> pseudo-header.
> 
> Some #define ETH_* are moved upper in slirp.h to make them accessible to
> other slirp/*.h
> 
> Signed-off-by: Guillaume Subiron <maethor@subiron.org>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
...
> diff --git a/slirp/slirp.c b/slirp/slirp.c
> index 0466d33..5f42ada 100644
> --- a/slirp/slirp.c
> +++ b/slirp/slirp.c
> @@ -210,10 +210,12 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
>  
>      slirp_init_once();
>  
> +    slirp->grand = g_rand_new();
>      slirp->restricted = restricted;
>  
>      if_init(slirp);
>      ip_init(slirp);
> +    ip6_init(slirp);
>  
>      /* Initialise mbufs *after* setting the MTU */
>      m_init(slirp);
> @@ -221,6 +223,9 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
>      slirp->vnetwork_addr = vnetwork;
>      slirp->vnetwork_mask = vnetmask;
>      slirp->vhost_addr = vhost;
> +    inet_pton(AF_INET6, "fec0::0", &slirp->vprefix_addr6);
> +    slirp->vprefix_len = 64;
> +    inet_pton(AF_INET6, "fec0::2", &slirp->vhost_addr6);
>      if (vhostname) {
>          pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
>                  vhostname);
> @@ -251,6 +256,7 @@ void slirp_cleanup(Slirp *slirp)
>      unregister_savevm(NULL, "slirp", slirp);
>  
>      ip_cleanup(slirp);
> +    ip6_cleanup(slirp);
>      m_cleanup(slirp);
>  
>      g_free(slirp->vdnssearch);

Could you please also do a g_rand_free(slirp->grand) during the
slirp_cleanup() function? Otherwise, the memory allocated for the rng
won't be freed and you get a big fat "2,500 bytes in 1 blocks are
definitely lost" from valgrind...

 Thomas

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union
  2016-02-19 13:44   ` Thomas Huth
@ 2016-02-22  1:48     ` Samuel Thibault
  2016-02-22  7:56       ` Thomas Huth
  0 siblings, 1 reply; 38+ messages in thread
From: Samuel Thibault @ 2016-02-22  1:48 UTC (permalink / raw)
  To: Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, qemu-devel, Gonglei, Jan Kiszka,
	Huangpeng, Guillaume Subiron

Hello,

Thomas Huth, on Fri 19 Feb 2016 14:44:59 +0100, wrote:
> > +	m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip)
> > +	                                     + sizeof(struct tcphdr));
> > +	m->m_len += sizeof(struct tcpiphdr) - (sizeof(struct ip)
> > +	                                    + sizeof(struct tcphdr));
> 
> I'm somewhat having a hard time to understand the  "+ sizeof(struct
> tcphdr))" here.
> 
> In the tcp_output.c code, there is this:
> 
> 	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
> 	                                     - sizeof(struct ip);
> 
> So with my limited point of view, I'd rather expect this here in
> tcp_input.c:
> 
> 	m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip)
> 	                                     - sizeof(struct tcphdr));
> i.e. "-" instead of "+" here ----------------^

The parentheses and indentation were misleading actually, here is how it
should actually looks like:

> > +	m->m_data -= sizeof(struct tcpiphdr) - ( sizeof(struct ip)
> > +	                                         + sizeof(struct tcphdr));

I've now dropped the parentheses, so it looks like the tcp_output.c code:

	m->m_data -= sizeof(struct tcpiphdr) - sizeof(struct ip)
	                                     - sizeof(struct tcphdr);

Samuel

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union
  2016-02-22  1:48     ` Samuel Thibault
@ 2016-02-22  7:56       ` Thomas Huth
  2016-02-22 10:20         ` Samuel Thibault
  0 siblings, 1 reply; 38+ messages in thread
From: Thomas Huth @ 2016-02-22  7:56 UTC (permalink / raw)
  To: Samuel Thibault
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, qemu-devel, Gonglei, Jan Kiszka,
	Huangpeng, Guillaume Subiron

On 22.02.2016 02:48, Samuel Thibault wrote:
> Hello,
> 
> Thomas Huth, on Fri 19 Feb 2016 14:44:59 +0100, wrote:
>>> +	m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip)
>>> +	                                     + sizeof(struct tcphdr));
>>> +	m->m_len += sizeof(struct tcpiphdr) - (sizeof(struct ip)
>>> +	                                    + sizeof(struct tcphdr));
>>
>> I'm somewhat having a hard time to understand the  "+ sizeof(struct
>> tcphdr))" here.
>>
>> In the tcp_output.c code, there is this:
>>
>> 	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
>> 	                                     - sizeof(struct ip);
>>
>> So with my limited point of view, I'd rather expect this here in
>> tcp_input.c:
>>
>> 	m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip)
>> 	                                     - sizeof(struct tcphdr));
>> i.e. "-" instead of "+" here ----------------^
> 
> The parentheses and indentation were misleading actually, here is how it
> should actually looks like:
> 
>>> +	m->m_data -= sizeof(struct tcpiphdr) - ( sizeof(struct ip)
>>> +	                                         + sizeof(struct tcphdr));
> 
> I've now dropped the parentheses, so it looks like the tcp_output.c code:
> 
> 	m->m_data -= sizeof(struct tcpiphdr) - sizeof(struct ip)
> 	                                     - sizeof(struct tcphdr);

Ah, sorry, I indeed simply got confused because it was written in two
different ways :-/ ... would it maybe be applicable to use the
TCPIPHDR_DELTA macro here instead?

Apart from that, the patch looks ok to me.

 Thomas

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union
  2016-02-22  7:56       ` Thomas Huth
@ 2016-02-22 10:20         ` Samuel Thibault
  0 siblings, 0 replies; 38+ messages in thread
From: Samuel Thibault @ 2016-02-22 10:20 UTC (permalink / raw)
  To: Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, qemu-devel, Gonglei, Jan Kiszka,
	Huangpeng, Guillaume Subiron

Hello,

Thomas Huth, on Mon 22 Feb 2016 08:56:59 +0100, wrote:
> would it maybe be applicable to use the
> TCPIPHDR_DELTA macro here instead?

No, because that includes a round up, while here we need an exact
difference.

Samuel

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union
  2016-02-10 10:08       ` Thomas Huth
@ 2016-02-10 12:20         ` Samuel Thibault
  0 siblings, 0 replies; 38+ messages in thread
From: Samuel Thibault @ 2016-02-10 12:20 UTC (permalink / raw)
  To: Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, Dave Gilbert, Gonglei, Jan Kiszka,
	Huangpeng, Guillaume Subiron

Thomas Huth, on Wed 10 Feb 2016 11:08:55 +0100, wrote:
> On 10.02.2016 10:28, Samuel Thibault wrote:
> > Thomas Huth, on Wed 10 Feb 2016 09:05:32 +0100, wrote:
> >>> -#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6)
> >>> +#define SLIRP_MSIZE\
> >>> +    (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)
> >>
> >> I'm somehow having a hard time to understand why TCPIPHDR_DELTA is used
> >> here. As far as I understand, TCPIPHDR_DELTA is the difference between
> >> the size of struct tcpiphdr and the size of the IPv4 + TCP header. But
> >> if it's just the difference, where does the base size of the headers
> >> come from in this define, since the headers are stored in the mbuf, too,
> >> aren't they? ... I've got the feeling that I miss something here, could
> >> you enlighten me?
> > 
> > TCP/IP headers are within IF_MTU.
> 
> Ah, of course, that makes sense, thanks! ... so in the old definition of
> SLIRP_MSIZE, the TCP/IP headers were counted twice, I guess?

Something like this, yes. The formula was looking very magic (what is
that 6 from?), so we rewrote it to make it clear for sure.

Samuel

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union
  2016-02-10  9:28     ` Samuel Thibault
@ 2016-02-10 10:08       ` Thomas Huth
  2016-02-10 12:20         ` Samuel Thibault
  0 siblings, 1 reply; 38+ messages in thread
From: Thomas Huth @ 2016-02-10 10:08 UTC (permalink / raw)
  To: Samuel Thibault
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, Dave Gilbert, Gonglei, Jan Kiszka,
	Huangpeng, Guillaume Subiron

On 10.02.2016 10:28, Samuel Thibault wrote:
> That one is tricky, yes :)
> 
> Thomas Huth, on Wed 10 Feb 2016 09:05:32 +0100, wrote:
>>> -#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6)
>>> +#define SLIRP_MSIZE\
>>> +    (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)
>>
>> I'm somehow having a hard time to understand why TCPIPHDR_DELTA is used
>> here. As far as I understand, TCPIPHDR_DELTA is the difference between
>> the size of struct tcpiphdr and the size of the IPv4 + TCP header. But
>> if it's just the difference, where does the base size of the headers
>> come from in this define, since the headers are stored in the mbuf, too,
>> aren't they? ... I've got the feeling that I miss something here, could
>> you enlighten me?
> 
> TCP/IP headers are within IF_MTU.

Ah, of course, that makes sense, thanks! ... so in the old definition of
SLIRP_MSIZE, the TCP/IP headers were counted twice, I guess? Anyway, the
definition looks fine to me now.

 Thomas

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union
  2016-02-10  8:05   ` Thomas Huth
@ 2016-02-10  9:28     ` Samuel Thibault
  2016-02-10 10:08       ` Thomas Huth
  0 siblings, 1 reply; 38+ messages in thread
From: Samuel Thibault @ 2016-02-10  9:28 UTC (permalink / raw)
  To: Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, Dave Gilbert, Gonglei, Jan Kiszka,
	Huangpeng, Guillaume Subiron

That one is tricky, yes :)

Thomas Huth, on Wed 10 Feb 2016 09:05:32 +0100, wrote:
> > -#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6)
> > +#define SLIRP_MSIZE\
> > +    (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)
> 
> I'm somehow having a hard time to understand why TCPIPHDR_DELTA is used
> here. As far as I understand, TCPIPHDR_DELTA is the difference between
> the size of struct tcpiphdr and the size of the IPv4 + TCP header. But
> if it's just the difference, where does the base size of the headers
> come from in this define, since the headers are stored in the mbuf, too,
> aren't they? ... I've got the feeling that I miss something here, could
> you enlighten me?

TCP/IP headers are within IF_MTU.

Samuel

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union Samuel Thibault
@ 2016-02-10  8:05   ` Thomas Huth
  2016-02-10  9:28     ` Samuel Thibault
  0 siblings, 1 reply; 38+ messages in thread
From: Thomas Huth @ 2016-02-10  8:05 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei, Jan Kiszka,
	Guillaume Subiron

On 08.02.2016 11:28, Samuel Thibault wrote:
> From: Guillaume Subiron <maethor@subiron.org>
> 
> This patch factorizes the tcpiphdr structure to put the IPv4 fields in
> an union, for addition of version 6 in further patch.
> Using some macros, retrocompatibility of the existing code is assured.
> 
> This patch also fixes the SLIRP_MSIZE and margin computation in various
> functions, and makes them compatible with the new tcpiphdr structure,
> whose size will be bigger than sizeof(struct tcphdr) + sizeof(struct ip)
> 
> Signed-off-by: Guillaume Subiron <maethor@subiron.org>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
>  slirp/if.h         |  4 ++--
>  slirp/mbuf.c       |  3 ++-
>  slirp/slirp.c      | 15 ++++++++-------
>  slirp/socket.c     | 13 ++++++++++++-
>  slirp/tcp_input.c  | 31 ++++++++++++++++++++-----------
>  slirp/tcp_output.c | 18 +++++++++++++-----
>  slirp/tcp_subr.c   | 31 ++++++++++++++++++++++---------
>  slirp/tcpip.h      | 31 +++++++++++++++++++++++--------
>  8 files changed, 102 insertions(+), 44 deletions(-)
> 
> diff --git a/slirp/if.h b/slirp/if.h
> index 3327023..c7a5c57 100644
> --- a/slirp/if.h
> +++ b/slirp/if.h
> @@ -17,7 +17,7 @@
>  #define IF_MRU 1500
>  #define	IF_COMP IF_AUTOCOMP	/* Flags for compression */
>  
> -/* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
> -#define IF_MAXLINKHDR (2 + 14 + 40)
> +/* 2 for alignment, 14 for ethernet */
> +#define IF_MAXLINKHDR (2 + ETH_HLEN)
>  
>  #endif
> diff --git a/slirp/mbuf.c b/slirp/mbuf.c
> index c959758..f081c69 100644
> --- a/slirp/mbuf.c
> +++ b/slirp/mbuf.c
> @@ -24,7 +24,8 @@
>   * Find a nice value for msize
>   * XXX if_maxlinkhdr already in mtu
>   */
> -#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6)
> +#define SLIRP_MSIZE\
> +    (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)

I'm somehow having a hard time to understand why TCPIPHDR_DELTA is used
here. As far as I understand, TCPIPHDR_DELTA is the difference between
the size of struct tcpiphdr and the size of the IPv4 + TCP header. But
if it's just the difference, where does the base size of the headers
come from in this define, since the headers are stored in the mbuf, too,
aren't they? ... I've got the feeling that I miss something here, could
you enlighten me?

 Thomas

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union
  2016-02-08 10:28 [Qemu-devel] [PATCHv7 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
@ 2016-02-08 10:28 ` Samuel Thibault
  2016-02-10  8:05   ` Thomas Huth
  0 siblings, 1 reply; 38+ messages in thread
From: Samuel Thibault @ 2016-02-08 10:28 UTC (permalink / raw)
  To: qemu-devel
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei,
	Jan Kiszka, Samuel Thibault, Yang Hongyang, Guillaume Subiron

From: Guillaume Subiron <maethor@subiron.org>

This patch factorizes the tcpiphdr structure to put the IPv4 fields in
an union, for addition of version 6 in further patch.
Using some macros, retrocompatibility of the existing code is assured.

This patch also fixes the SLIRP_MSIZE and margin computation in various
functions, and makes them compatible with the new tcpiphdr structure,
whose size will be bigger than sizeof(struct tcphdr) + sizeof(struct ip)

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
 slirp/if.h         |  4 ++--
 slirp/mbuf.c       |  3 ++-
 slirp/slirp.c      | 15 ++++++++-------
 slirp/socket.c     | 13 ++++++++++++-
 slirp/tcp_input.c  | 31 ++++++++++++++++++++-----------
 slirp/tcp_output.c | 18 +++++++++++++-----
 slirp/tcp_subr.c   | 31 ++++++++++++++++++++++---------
 slirp/tcpip.h      | 31 +++++++++++++++++++++++--------
 8 files changed, 102 insertions(+), 44 deletions(-)

diff --git a/slirp/if.h b/slirp/if.h
index 3327023..c7a5c57 100644
--- a/slirp/if.h
+++ b/slirp/if.h
@@ -17,7 +17,7 @@
 #define IF_MRU 1500
 #define	IF_COMP IF_AUTOCOMP	/* Flags for compression */
 
-/* 2 for alignment, 14 for ethernet, 40 for TCP/IP */
-#define IF_MAXLINKHDR (2 + 14 + 40)
+/* 2 for alignment, 14 for ethernet */
+#define IF_MAXLINKHDR (2 + ETH_HLEN)
 
 #endif
diff --git a/slirp/mbuf.c b/slirp/mbuf.c
index c959758..f081c69 100644
--- a/slirp/mbuf.c
+++ b/slirp/mbuf.c
@@ -24,7 +24,8 @@
  * Find a nice value for msize
  * XXX if_maxlinkhdr already in mtu
  */
-#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6)
+#define SLIRP_MSIZE\
+    (offsetof(struct mbuf, m_dat) + IF_MAXLINKHDR + TCPIPHDR_DELTA + IF_MTU)
 
 void
 m_init(Slirp *slirp)
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 0e652bd..551f100 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -753,15 +753,16 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int pkt_len)
         m = m_get(slirp);
         if (!m)
             return;
-        /* Note: we add to align the IP header */
-        if (M_FREEROOM(m) < pkt_len + 2) {
-            m_inc(m, pkt_len + 2);
+        /* Note: we add 2 to align the IP header on 4 bytes,
+         * and add the margin for the tcpiphdr overhead  */
+        if (M_FREEROOM(m) < pkt_len + TCPIPHDR_DELTA + 2) {
+            m_inc(m, pkt_len + TCPIPHDR_DELTA + 2);
         }
-        m->m_len = pkt_len + 2;
-        memcpy(m->m_data + 2, pkt, pkt_len);
+        m->m_len = pkt_len + TCPIPHDR_DELTA + 2;
+        memcpy(m->m_data + TCPIPHDR_DELTA + 2, pkt, pkt_len);
 
-        m->m_data += 2 + ETH_HLEN;
-        m->m_len -= 2 + ETH_HLEN;
+        m->m_data += TCPIPHDR_DELTA + 2 + ETH_HLEN;
+        m->m_len -= TCPIPHDR_DELTA + 2 + ETH_HLEN;
 
         if (proto == ETH_P_IP) {
             ip_input(m);
diff --git a/slirp/socket.c b/slirp/socket.c
index b79ddec..d4b02c8 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -483,7 +483,18 @@ sorecvfrom(struct socket *so)
 	  if (!m) {
 	      return;
 	  }
-	  m->m_data += IF_MAXLINKHDR;
+	  switch (so->so_ffamily) {
+	  case AF_INET:
+	      m->m_data += IF_MAXLINKHDR + sizeof(struct udpiphdr);
+	      break;
+	  case AF_INET6:
+	      m->m_data += IF_MAXLINKHDR + sizeof(struct ip6)
+	                                 + sizeof(struct udphdr);
+	      break;
+	  default:
+	      g_assert_not_reached();
+	      break;
+	  }
 
 	  /*
 	   * XXX Shouldn't FIONREAD packets destined for port 53,
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index 5f845da..26b0c8b 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -256,11 +256,6 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
 	}
 	slirp = m->slirp;
 
-	/*
-	 * Get IP and TCP header together in first mbuf.
-	 * Note: IP leaves IP header in first mbuf.
-	 */
-	ti = mtod(m, struct tcpiphdr *);
 	if (iphlen > sizeof(struct ip )) {
 	  ip_stripoptions(m, (struct mbuf *)0);
 	  iphlen=sizeof(struct ip );
@@ -277,14 +272,28 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
 	save_ip.ip_len+= iphlen;
 
 	/*
+	 * Get IP and TCP header together in first mbuf.
+	 * Note: IP leaves IP header in first mbuf.
+	 */
+	m->m_data -= sizeof(struct tcpiphdr) - (sizeof(struct ip)
+	                                     + sizeof(struct tcphdr));
+	m->m_len += sizeof(struct tcpiphdr) - (sizeof(struct ip)
+	                                    + sizeof(struct tcphdr));
+	ti = mtod(m, struct tcpiphdr *);
+
+	/*
 	 * Checksum extended TCP header and data.
 	 */
-	tlen = ((struct ip *)ti)->ip_len;
-        tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
-        memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
-	ti->ti_x1 = 0;
+	tlen = ip->ip_len;
+	tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
+	memset(&ti->ih_mbuf, 0 , sizeof(struct mbuf_ptr));
+	memset(&ti->ti, 0, sizeof(ti->ti));
+	ti->ti_x0 = 0;
+	ti->ti_src = save_ip.ip_src;
+	ti->ti_dst = save_ip.ip_dst;
+	ti->ti_pr = save_ip.ip_p;
 	ti->ti_len = htons((uint16_t)tlen);
-	len = sizeof(struct ip ) + tlen;
+	len = ((sizeof(struct tcpiphdr) - sizeof(struct tcphdr)) + tlen);
 	if(cksum(m, len)) {
 	  goto drop;
 	}
@@ -1475,7 +1484,7 @@ tcp_mss(struct tcpcb *tp, u_int offer)
 	DEBUG_ARG("tp = %p", tp);
 	DEBUG_ARG("offer = %d", offer);
 
-	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcpiphdr);
+	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr) + sizeof(struct ip);
 	if (offer)
 		mss = min(mss, offer);
 	mss = max(mss, 32);
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index 34e4d2e..7fc6a87 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -448,15 +448,23 @@ send:
 	 */
 	m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
 
-    {
+	struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
+	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                     - sizeof(struct ip);
+	m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                     - sizeof(struct ip);
+	struct ip *ip = mtod(m, struct ip *);
 
-	((struct ip *)ti)->ip_len = m->m_len;
+	ip->ip_len = m->m_len;
+	ip->ip_dst = tcpiph_save.ti_dst;
+	ip->ip_src = tcpiph_save.ti_src;
+	ip->ip_p = tcpiph_save.ti_pr;
 
-	((struct ip *)ti)->ip_ttl = IPDEFTTL;
-	((struct ip *)ti)->ip_tos = so->so_iptos;
+	ip->ip_ttl = IPDEFTTL;
+	ip->ip_tos = so->so_iptos;
 
 	error = ip_output(so, m);
-    }
+
 	if (error) {
 out:
 		return (error);
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index b1aa1f2..cd021df 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -76,9 +76,10 @@ tcp_template(struct tcpcb *tp)
 	register struct tcpiphdr *n = &tp->t_template;
 
 	n->ti_mbuf = NULL;
-	n->ti_x1 = 0;
+	memset(&n->ti, 0, sizeof(n->ti));
+	n->ti_x0 = 0;
 	n->ti_pr = IPPROTO_TCP;
-	n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
+	n->ti_len = htons(sizeof(struct tcphdr));
 	n->ti_src = so->so_faddr;
 	n->ti_dst = so->so_laddr;
 	n->ti_sport = so->so_fport;
@@ -131,6 +132,7 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 		m->m_data += IF_MAXLINKHDR;
 		*mtod(m, struct tcpiphdr *) = *ti;
 		ti = mtod(m, struct tcpiphdr *);
+		memset(&ti->ti, 0, sizeof(ti->ti));
 		flags = TH_ACK;
 	} else {
 		/*
@@ -150,8 +152,8 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 	tlen += sizeof (struct tcpiphdr);
 	m->m_len = tlen;
 
-        ti->ti_mbuf = NULL;
-	ti->ti_x1 = 0;
+	ti->ti_mbuf = NULL;
+	ti->ti_x0 = 0;
 	ti->ti_seq = htonl(seq);
 	ti->ti_ack = htonl(ack);
 	ti->ti_x2 = 0;
@@ -164,12 +166,23 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 	ti->ti_urp = 0;
 	ti->ti_sum = 0;
 	ti->ti_sum = cksum(m, tlen);
-	((struct ip *)ti)->ip_len = tlen;
 
-	if(flags & TH_RST)
-	  ((struct ip *)ti)->ip_ttl = MAXTTL;
-	else
-	  ((struct ip *)ti)->ip_ttl = IPDEFTTL;
+	struct tcpiphdr tcpiph_save = *(mtod(m, struct tcpiphdr *));
+	m->m_data += sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                     - sizeof(struct ip);
+	m->m_len  -= sizeof(struct tcpiphdr) - sizeof(struct tcphdr)
+	                                     - sizeof(struct ip);
+	struct ip *ip = mtod(m, struct ip *);
+	ip->ip_len = tlen;
+	ip->ip_dst = tcpiph_save.ti_dst;
+	ip->ip_src = tcpiph_save.ti_src;
+	ip->ip_p = tcpiph_save.ti_pr;
+
+	if (flags & TH_RST) {
+		ip->ip_ttl = MAXTTL;
+	} else {
+		ip->ip_ttl = IPDEFTTL;
+	}
 
 	(void) ip_output((struct socket *)0, m);
 }
diff --git a/slirp/tcpip.h b/slirp/tcpip.h
index 7974ce3..d9b5d70 100644
--- a/slirp/tcpip.h
+++ b/slirp/tcpip.h
@@ -37,15 +37,23 @@
  * Tcp+ip header, after ip options removed.
  */
 struct tcpiphdr {
-	struct 	ipovly ti_i;		/* overlaid ip structure */
-	struct	tcphdr ti_t;		/* tcp header */
+    struct mbuf_ptr ih_mbuf;	/* backpointer to mbuf */
+    union {
+        struct {
+            struct  in_addr ih_src; /* source internet address */
+            struct  in_addr ih_dst; /* destination internet address */
+            uint8_t ih_x1;          /* (unused) */
+            uint8_t ih_pr;          /* protocol */
+        } ti_i4;
+    } ti;
+    uint16_t    ti_x0;
+    uint16_t    ti_len;             /* protocol length */
+    struct      tcphdr ti_t;        /* tcp header */
 };
-#define	ti_mbuf		ti_i.ih_mbuf.mptr
-#define	ti_x1		ti_i.ih_x1
-#define	ti_pr		ti_i.ih_pr
-#define	ti_len		ti_i.ih_len
-#define	ti_src		ti_i.ih_src
-#define	ti_dst		ti_i.ih_dst
+#define	ti_mbuf		ih_mbuf.mptr
+#define	ti_pr		ti.ti_i4.ih_pr
+#define	ti_src		ti.ti_i4.ih_src
+#define	ti_dst		ti.ti_i4.ih_dst
 #define	ti_sport	ti_t.th_sport
 #define	ti_dport	ti_t.th_dport
 #define	ti_seq		ti_t.th_seq
@@ -65,6 +73,13 @@ struct tcpiphdr {
 #define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink*)(T))
 #define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr*)(T))
 
+/* This is the difference between the size of a tcpiphdr structure, and the
+ * size of actual ip+tcp headers, rounded up since we need to align data.  */
+#define TCPIPHDR_DELTA\
+    (max(0,\
+         (sizeof(struct tcpiphdr)\
+          - sizeof(struct ip) - sizeof(struct tcphdr) + 3)&~3))
+
 /*
  * Just a clean way to get to the first byte
  * of the packet
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2016-02-22 10:20 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-14 17:47 [Qemu-devel] [PATCHv8 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
2016-02-16 11:36   ` Thomas Huth
2016-02-19 13:57   ` Thomas Huth
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 2/9] slirp: Adding ICMPv6 error sending Samuel Thibault
2016-02-16 12:21   ` Thomas Huth
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support Samuel Thibault
2016-02-16 12:28   ` Thomas Huth
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union Samuel Thibault
2016-02-19  0:36   ` Samuel Thibault
2016-02-19 13:44   ` Thomas Huth
2016-02-22  1:48     ` Samuel Thibault
2016-02-22  7:56       ` Thomas Huth
2016-02-22 10:20         ` Samuel Thibault
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 5/9] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff Samuel Thibault
2016-02-17  8:25   ` Thomas Huth
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring Samuel Thibault
2016-02-17  9:03   ` Thomas Huth
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 7/9] slirp: Handle IPv6 in TCP functions Samuel Thibault
2016-02-17  9:18   ` Thomas Huth
2016-02-17  9:30     ` Samuel Thibault
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 8/9] slirp: Adding IPv6 address for DNS relay Samuel Thibault
2016-02-17  9:28   ` Thomas Huth
2016-02-17  9:36     ` Samuel Thibault
2016-02-19  0:26       ` Samuel Thibault
2016-02-14 17:47 ` [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses Samuel Thibault
2016-02-17 11:59   ` Thomas Huth
2016-02-19  0:35     ` Samuel Thibault
2016-02-16  8:47 ` [Qemu-devel] [PATCH] slirp: Add IPv6 support to the TFTP code Thomas Huth
2016-02-16 10:30   ` Samuel Thibault
2016-02-16 12:09     ` Thomas Huth
2016-02-17  8:40   ` [Qemu-devel] [PATCH v2] " Thomas Huth
2016-02-17  8:42     ` Samuel Thibault
  -- strict thread matches above, loose matches on Subject: below --
2016-02-08 10:28 [Qemu-devel] [PATCHv7 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union Samuel Thibault
2016-02-10  8:05   ` Thomas Huth
2016-02-10  9:28     ` Samuel Thibault
2016-02-10 10:08       ` Thomas Huth
2016-02-10 12:20         ` Samuel Thibault

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).