qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCHv7 0/9] slirp: Adding IPv6 support to Qemu -net user mode
@ 2016-02-08 10:28 Samuel Thibault
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
                   ` (8 more replies)
  0 siblings, 9 replies; 49+ 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

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 6 is:
- drop second-precision timer addition
- use ms precision for RA timer
- Use unsigned short instead of sa_family_t
- Use error_report instead of printing to stderr
- Use g_assert_not_reached instead of assert(0)

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 |   4 +-
 slirp/cksum.c       |  23 +++
 slirp/if.c          |   2 +-
 slirp/if.h          |   4 +-
 slirp/ip6.h         | 142 ++++++++++++++++++
 slirp/ip6_icmp.c    | 410 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 slirp/ip6_icmp.h    | 254 ++++++++++++++++++++++++++++++++
 slirp/ip6_input.c   |  76 ++++++++++
 slirp/ip6_output.c  |  41 ++++++
 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   |  87 +++++++++++
 slirp/slirp.c       |  78 ++++++++--
 slirp/slirp.h       |  40 ++++-
 slirp/socket.c      |  54 ++++++-
 slirp/socket.h      |  13 ++
 slirp/tcp.h         |   2 +
 slirp/tcp_input.c   | 176 ++++++++++++++++------
 slirp/tcp_output.c  |  51 +++++--
 slirp/tcp_subr.c    | 117 +++++++++++----
 slirp/tcp_timer.c   |   3 +-
 slirp/tcpip.h       |  40 ++++-
 slirp/udp.c         |   3 +-
 slirp/udp.h         |   5 +
 slirp/udp6.c        | 150 +++++++++++++++++++
 32 files changed, 1793 insertions(+), 158 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] 49+ messages in thread

* [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  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-09 16:14   ` Thomas Huth
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 2/9] slirp: Adding ICMPv6 error sending Samuel Thibault
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 49+ 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 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 |   4 +-
 slirp/cksum.c       |  23 ++++
 slirp/if.c          |   2 +-
 slirp/ip6.h         | 139 +++++++++++++++++++++
 slirp/ip6_icmp.c    | 350 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 slirp/ip6_icmp.h    | 244 ++++++++++++++++++++++++++++++++++++
 slirp/ip6_input.c   |  72 +++++++++++
 slirp/ip6_output.c  |  41 ++++++
 slirp/ndp_table.c   |  87 +++++++++++++
 slirp/slirp.c       |  48 ++++++-
 slirp/slirp.h       |  34 +++++
 slirp/socket.h      |   7 ++
 12 files changed, 1045 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..2dfe8e0 100644
--- a/slirp/Makefile.objs
+++ b/slirp/Makefile.objs
@@ -1,3 +1,3 @@
-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..d2b0a83 100644
--- a/slirp/cksum.c
+++ b/slirp/cksum.c
@@ -138,3 +138,26 @@ cont:
 	REDUCE;
 	return (~sum & 0xffff);
 }
+
+int ip6_cksum(struct mbuf *m)
+{
+    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..9e65acd
--- /dev/null
+++ b/slirp/ip6.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef _IP6_H_
+#define _IP6_H_
+
+#define in6_multicast(a) IN6_IS_ADDR_MULTICAST(&(a))
+#define in6_linklocal(a) IN6_IS_ADDR_LINKLOCAL(&(a))
+#define in6_unspecified(a) IN6_IS_ADDR_UNSPECIFIED(&(a))
+
+#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 int in6_equal(struct in6_addr a, struct in6_addr b)
+{
+    return memcmp(&a, &b, sizeof(a)) == 0;
+}
+
+static inline int in6_equal_net(struct in6_addr a, 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 int in6_equal_mach(struct in6_addr a, 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..13f89af
--- /dev/null
+++ b/slirp/ip6_icmp.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.h"
+#include "ip6_icmp.h"
+#include "qemu/timer.h"
+#include "qemu/error-report.h"
+#include <stdlib.h>
+#include <time.h>
+
+#define rand_a_b(a, b)\
+    (rand()%(int)(b-a)+a)
+#define NDP_Interval rand_a_b(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)
+{
+    srand(time(NULL));
+    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);
+}
+
+#undef NDP_Interval
+#undef rand_a_b
+
+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);
+}
+
+/*
+ * 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 = Routeur 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 = Routeur Advertisement");
+        error_report("Warning: guest sent NDP RA, but shouldn't\n");
+        break;
+
+    case ICMP6_NDP_NS:
+        DEBUG_CALL(" type = Neighbor Solicitation");
+        if (ip->ip_hl == 255
+                && icmp->icmp6_code == 0
+                && !in6_multicast(icmp->icmp6_nns.target)
+                && ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN
+                && (!in6_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);
+
+                /* 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_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_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);
+            }
+        }
+        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_multicast(icmp->icmp6_nna.target)
+                && (!in6_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");
+        error_report("Warning: guest sent NDP REDIRECT, but shouldn't\n");
+        break;
+
+    default:
+       return;
+    }
+    return;
+}
+
+/*
+ * 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);
+}
+
+/*
+ * 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\n");
+        }
+        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);
+    return;
+}
diff --git a/slirp/ip6_icmp.h b/slirp/ip6_icmp.h
new file mode 100644
index 0000000..1ae003b
--- /dev/null
+++ b/slirp/ip6_icmp.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef _NETINET_ICMP6_H_
+#define _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 */
+#define NDPOPT_REDIRECTED_HDR       4   /* Redirected Header */
+#define NDPOPT_MTU                  5   /* MTU */
+
+/* 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_MCASTLST_QUERY    130 /* Multicast Listener Query */
+#define ICMP6_MCASTLST_REPORT   131 /* Multicast Listener Report */
+#define ICMP6_MCASTLST_DONE     132 /* Multicast Listener Done */
+#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) */
+#define ICMP6_ROUTERRENUM       138 /* Router Renumbering */
+#define     ICMP6_ROUTERRENUM_COMMAND   0       /* router renum command */
+#define     ICMP6_ROUTERRENUM_RESULT    1       /* router renum result */
+#define     ICMP6_ROUTERRENUM_RESET     255     /* sequence number reset */
+#define ICMP6_NODEINFO_QUERY    139 /* ICMP Node Information Query */
+#define     ICMP6_NODEINFO_QUERY_IPV6   0       /* subject is an IPv6 */
+#define     ICMP6_NODEINFO_QUERY_NAME   1       /* subj is a name (or empty) */
+#define     ICMP6_NODEINFO_QUERY_IPV4   2       /* subject is an IPv4 */
+#define ICMP6_NODEINFO_RESP     140 /* ICMP Node Information Response */
+#define     ICMP6_NODEINFO_RESP_SUCCESS 0       /* successful reply */
+#define     ICMP6_NODEINFO_RESP_REFUSAL 1       /* refuses to supply answer */
+#define     ICMP6_NODEINFO_RESP_UNKNOWN 2       /* Qtype unknown to the resp */
+#define ICMP6_IND_S             141 /* Inverse Neighbor Discovery Sol. */
+#define ICMP6_IND_A             142 /* Inverse Neighbor Discovery Adv. */
+#define ICMP6_MLD               143 /* Multicast Listener Discovery reports */
+#define ICMP6_HAAD_REQUEST      144 /* Home Agent Address Discovery Request */
+#define ICMP6_HAAD_REPLY        145 /* Home Agent Address Discovery Reply */
+#define ICMP6_MP_SOL            146 /* Mobile Prefix Solicitation */
+#define ICMP6_MP_ADV            147 /* Mobile Prefix Advertisement */
+#define ICMP6_SEND_CPS          148 /* Certification Path Solicitation (SEND) */
+#define ICMP6_SEND_CPA          149 /* Certification Path Adv. (SEND) */
+#define ICMP6_MRD_RA            151 /* Multicast Router Advertisement (MRD) */
+#define ICMP6_MRD_RS            152 /* Multicast Router Solicitation (MRD) */
+#define ICMP6_MRD_TERM          153 /* Multicast Router Termination (MRD) */
+#define ICMP6_FMIP6             154 /* FMIPv6 Messages */
+#define     ICMP6_FMIP6_RTSOLPR         2       /* RtSolPr */
+#define     ICMP6_FMIP6_PRRTADV         3       /* PrRtAdv */
+#define ICMP6_RPL_CONTROL       155 /* RPL Control Message */
+#define ICMP6_ILNP6_LU          156 /* ILNPv6 Locator Update Message */
+#define ICMP6_DUPADDR_REQUEST   157 /* Duplicate Address Request */
+#define ICMP6_DUPADDR_CONFIRM   158 /* Duplicate Address Confirmation */
+
+#define ICMP6_INFOTYPE(type) ((type) >= 128)
+
+/*
+ * Router Configuration Variables (rfc4861#section-6)
+ */
+#define NDP_IsRouter                1
+#define NDP_AdvSendAdvertisements   1
+#define NDP_MaxRtrAdvInterval       600000
+#define NDP_MinRtrAdvInterval       ((NDP_MaxRtrAdvInterval >= 9) ? \
+                                        0.33*NDP_MaxRtrAdvInterval : \
+                                        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..e1e6229
--- /dev/null
+++ b/slirp/ip6_input.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+#include <qemu/osdep.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)) {
+        return;
+    }
+
+    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..178a968
--- /dev/null
+++ b/slirp/ip6_output.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#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..7468485
--- /dev/null
+++ b/slirp/ndp_table.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#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_multicast(ip_addr) || in6_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_unspecified(ip_addr));
+
+    /* Multicast address: fec0::abcd:efgh/8 -> 33:33:ab:cd:ef:gh */
+    if (in6_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..0e652bd 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -214,6 +214,7 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
 
     if_init(slirp);
     ip_init(slirp);
+    ip6_init(slirp);
 
     /* Initialise mbufs *after* setting the MTU */
     m_init(slirp);
@@ -221,6 +222,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 +255,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 +749,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 +763,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 +837,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 +885,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..1772222 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -139,12 +139,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 +198,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 +225,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 +276,9 @@ struct Slirp {
     struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
 
     ArpTable arp_table;
+    NdpTable ndp_table;
+
+    QEMUTimer *ra_timer;
 
     void *opaque;
 };
@@ -296,6 +321,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 +337,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..9dae491 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] 49+ messages in thread

* [Qemu-devel] [PATCHv7 2/9] slirp: Adding ICMPv6 error sending
  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 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
@ 2016-02-08 10:28 ` Samuel Thibault
  2016-02-09 19:48   ` Thomas Huth
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support Samuel Thibault
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 49+ 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,
	Yann Bordenave, Gonglei, Jan Kiszka, Samuel Thibault,
	Yang Hongyang, 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  | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 slirp/ip6_icmp.h  | 10 ++++++++++
 slirp/ip6_input.c | 15 ++++++++------
 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, 96 insertions(+), 22 deletions(-)

diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c
index 13f89af..41e034b 100644
--- a/slirp/ip6_icmp.c
+++ b/slirp/ip6_icmp.c
@@ -67,6 +67,66 @@ 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 = m_get(slirp);
+    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));
+
+    /* IPv6 packet */
+    struct ip6 *rip = mtod(t, struct ip6 *);
+    rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
+    if (in6_multicast(ip->ip_src) || in6_unspecified(ip->ip_src)) {
+        /* TODO icmp error? */
+        return;
+    }
+    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);
+}
+
 /*
  * Process a NDP message
  */
diff --git a/slirp/ip6_icmp.h b/slirp/ip6_icmp.h
index 1ae003b..f47c29f 100644
--- a/slirp/ip6_icmp.h
+++ b/slirp/ip6_icmp.h
@@ -22,6 +22,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
  */
@@ -85,6 +91,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;
@@ -92,6 +99,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
@@ -101,6 +109,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
@@ -238,6 +247,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 e1e6229..828f47c 100644
--- a/slirp/ip6_input.c
+++ b/slirp/ip6_input.c
@@ -33,7 +33,7 @@ void ip6_input(struct mbuf *m)
     DEBUG_ARG("m_len = %d", m->m_len);
 
     if (m->m_len < sizeof(struct ip6)) {
-        return;
+        goto bad;
     }
 
     ip6 = mtod(m, struct ip6 *);
@@ -42,9 +42,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;
     }
 
@@ -52,14 +57,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] 49+ messages in thread

* [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support
  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 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 2/9] slirp: Adding ICMPv6 error sending Samuel Thibault
@ 2016-02-08 10:28 ` Samuel Thibault
  2016-02-09 20:44   ` Thomas Huth
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union Samuel Thibault
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 49+ 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 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        | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 168 insertions(+), 2 deletions(-)
 create mode 100644 slirp/udp6.c

diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs
index 2dfe8e0..faa32b6 100644
--- a/slirp/Makefile.objs
+++ b/slirp/Makefile.objs
@@ -1,3 +1,3 @@
 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 ndp_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 828f47c..d7c612e 100644
--- a/slirp/ip6_input.c
+++ b/slirp/ip6_input.c
@@ -61,7 +61,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 9dae491..39ef592 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..63d6a8c
--- /dev/null
+++ b/slirp/udp6.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.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);
+    }
+
+    /* 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);
+
+    return ip6_output(so, m, 0);
+}
-- 
2.7.0

^ permalink raw reply related	[flat|nested] 49+ 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
                   ` (2 preceding siblings ...)
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support Samuel Thibault
@ 2016-02-08 10:28 ` Samuel Thibault
  2016-02-10  8:05   ` Thomas Huth
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 5/9] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff Samuel Thibault
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 49+ 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] 49+ messages in thread

* [Qemu-devel] [PATCHv7 5/9] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff
  2016-02-08 10:28 [Qemu-devel] [PATCHv7 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (3 preceding siblings ...)
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 4/9] slirp: Factorizing tcpiphdr structure with an union Samuel Thibault
@ 2016-02-08 10:28 ` Samuel Thibault
  2016-02-10  8:35   ` Thomas Huth
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring Samuel Thibault
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 49+ 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>

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  | 52 ++++++++++++++++++++++++++++++++++++++++++++--------
 slirp/tcp_output.c | 14 +++++++++++---
 slirp/tcp_subr.c   | 37 +++++++++++++++++++++++++++++--------
 slirp/tcp_timer.c  |  3 ++-
 7 files changed, 94 insertions(+), 25 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 551f100..cca5a80 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -573,7 +573,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);
@@ -622,7 +623,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 1772222..3261815 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -346,7 +346,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 */
@@ -357,7 +357,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..0cc279b 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:
+	    goto drop;
+	}
 
 	/*
 	 * 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:
+	    goto drop;
+	}
 
 	so = solookup(&slirp->tcp_last_so, &slirp->tcb, &lhost, &fhost);
 
@@ -389,8 +402,17 @@ findso:
 	  so->lhost.ss = lhost;
 	  so->fhost.ss = fhost;
 
-	  if ((so->so_iptos = tcp_tos(so)) == 0)
+	  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:
+	          goto drop;
+	          break;
+	      }
+	  }
 
 	  tp = sototcpcb(so);
 	  tp->t_state = TCPS_LISTEN;
@@ -569,7 +591,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) {
@@ -607,7 +630,7 @@ findso:
 	    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);
+			  TH_RST|TH_ACK, af);
 	    } else {
 	      if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
 	      HTONL(ti->ti_seq);             /* restore tcp header */
@@ -616,7 +639,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);
+	      switch (af) {
+	      case AF_INET:
 	      *ip=save_ip;
+	          break;
+	      default:
+	          goto drop;
+	      }
 	      icmp_send_error(m, ICMP_UNREACH, code, 0, strerror(errno));
 	    }
             tcp_close(tp);
@@ -1289,11 +1318,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);
+		    TH_RST|TH_ACK, af);
 	}
 
 	return;
@@ -1484,7 +1513,14 @@ tcp_mss(struct tcpcb *tp, u_int offer)
 	DEBUG_ARG("tp = %p", tp);
 	DEBUG_ARG("offer = %d", offer);
 
+	switch (so->so_ffamily) {
+	case AF_INET:
 	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr) + sizeof(struct ip);
+	    break;
+	default:
+	    break;
+	}
+
 	if (offer)
 		mss = min(mss, offer);
 	mss = max(mss, 32);
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index 7fc6a87..62ab1e5 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:
+	    goto out;
+	}
 
 	if (error) {
 out:
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index cd021df..f1d62f6 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:
+	    break;
+	}
 
 	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:
+		    break;
+		}
 #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:
+	    break;
+	}
 }
 
 /*
@@ -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] 49+ messages in thread

* [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring
  2016-02-08 10:28 [Qemu-devel] [PATCHv7 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (4 preceding siblings ...)
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 5/9] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff Samuel Thibault
@ 2016-02-08 10:28 ` Samuel Thibault
  2016-02-10  8:42   ` Thomas Huth
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 7/9] slirp: Handle IPv6 in TCP functions Samuel Thibault
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 49+ 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>

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  | 99 +++++++++++++++++++++++++++---------------------------
 slirp/tcp_output.c | 29 ++++++++--------
 slirp/tcp_subr.c   | 50 +++++++++++++--------------
 3 files changed, 89 insertions(+), 89 deletions(-)

diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index 0cc279b..eb0df81 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:
 	    goto drop;
@@ -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:
 	    goto drop;
@@ -406,7 +406,7 @@ findso:
 	  if (so->so_iptos == 0) {
 	      switch (af) {
 	      case AF_INET:
-	    so->so_iptos = ((struct ip *)ti)->ip_tos;
+	          so->so_iptos = ((struct ip *)ti)->ip_tos;
 	          break;
 	      default:
 	          goto drop;
@@ -592,8 +592,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 */
@@ -641,7 +641,7 @@ findso:
 	      m->m_len  += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
 	      switch (af) {
 	      case AF_INET:
-	      *ip=save_ip;
+	          *ip = save_ip;
 	          break;
 	      default:
 	          goto drop;
@@ -1515,7 +1515,8 @@ tcp_mss(struct tcpcb *tp, u_int offer)
 
 	switch (so->so_ffamily) {
 	case AF_INET:
-	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr) + sizeof(struct ip);
+	    mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr)
+	                              + sizeof(struct ip);
 	    break;
 	default:
 	    break;
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index 62ab1e5..429018a 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 f1d62f6..f2ef8f3 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:
 		    break;
@@ -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] 49+ messages in thread

* [Qemu-devel] [PATCHv7 7/9] slirp: Handle IPv6 in TCP functions
  2016-02-08 10:28 [Qemu-devel] [PATCHv7 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (5 preceding siblings ...)
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring Samuel Thibault
@ 2016-02-08 10:28 ` Samuel Thibault
  2016-02-10 10:47   ` Thomas Huth
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 8/9] slirp: Adding IPv6 address for DNS relay Samuel Thibault
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses Samuel Thibault
  8 siblings, 1 reply; 49+ 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 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   | 33 +++++++++++++++++++++++++++++-
 slirp/tcpip.h      |  9 ++++++++
 6 files changed, 108 insertions(+), 15 deletions(-)

diff --git a/slirp/ip6_input.c b/slirp/ip6_input.c
index d7c612e..b03b795 100644
--- a/slirp/ip6_input.c
+++ b/slirp/ip6_input.c
@@ -58,7 +58,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 eb0df81..5840471 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,6 +258,11 @@ 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 *);
+	save_ip = *ip;
+	save_ip6 = *ip6;
+
 	switch (af) {
 	case AF_INET:
 	    if (iphlen > sizeof(struct ip)) {
@@ -264,13 +271,6 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
 	    }
 	    /* 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 +295,35 @@ 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:
+	    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:
 	    goto drop;
 	}
 
+	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:
 	    goto drop;
 	}
@@ -409,7 +436,6 @@ findso:
 	          so->so_iptos = ((struct ip *)ti)->ip_tos;
 	          break;
 	      default:
-	          goto drop;
 	          break;
 	      }
 	  }
@@ -643,6 +669,9 @@ findso:
 	      case AF_INET:
 	          *ip = save_ip;
 	          break;
+	      case AF_INET6:
+	          *ip6 = save_ip6;
+	          break;
 	      default:
 	          goto drop;
 	      }
@@ -1518,7 +1547,12 @@ 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();
 	    break;
 	}
 
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index 429018a..b016a56 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:
 	    goto out;
 	}
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index f2ef8f3..b18e0da 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -88,7 +88,17 @@ 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();
 	    break;
 	}
 
@@ -156,7 +166,12 @@ 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();
 		    break;
 		}
 #undef xchg
@@ -182,6 +197,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,7 +220,22 @@ 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();
 	    break;
 	}
 }
@@ -225,7 +256,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 d9b5d70..4a2987f 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] 49+ messages in thread

* [Qemu-devel] [PATCHv7 8/9] slirp: Adding IPv6 address for DNS relay
  2016-02-08 10:28 [Qemu-devel] [PATCHv7 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (6 preceding siblings ...)
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 7/9] slirp: Handle IPv6 in TCP functions Samuel Thibault
@ 2016-02-08 10:28 ` Samuel Thibault
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses Samuel Thibault
  8 siblings, 0 replies; 49+ 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 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 9e65acd..c799421 100644
--- a/slirp/ip6.h
+++ b/slirp/ip6.h
@@ -74,7 +74,10 @@ static inline int in6_equal_mach(struct in6_addr a, struct in6_addr b,
   || (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 cca5a80..4d6203a 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -233,6 +233,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 3261815..88d9be1 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -230,6 +230,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..5d4930a 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] 49+ messages in thread

* [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses
  2016-02-08 10:28 [Qemu-devel] [PATCHv7 0/9] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (7 preceding siblings ...)
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 8/9] slirp: Adding IPv6 address for DNS relay Samuel Thibault
@ 2016-02-08 10:28 ` Samuel Thibault
  2016-02-08 22:12   ` Eric Blake
  2016-02-10 11:39   ` Thomas Huth
  8 siblings, 2 replies; 49+ 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,
	Yann Bordenave, Gonglei, Jan Kiszka, Samuel Thibault,
	Yang Hongyang, 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..0ececcb 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.  */
+                int len;
+                char *end;
+
+                qemu_opt_set(opts, "ip6-prefix", buf, &error_abort);
+                len = strtol(ip6_net, &end, 10);
+
+                if (*end != '\0') {
+                    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..cba041e 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 (since 2.6)
+#
+# @ip6-prefixlen: #optional IPv6 network prefix length (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 4d6203a..c09c7cc 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));
@@ -222,9 +224,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);
@@ -233,7 +235,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] 49+ messages in thread

* Re: [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses Samuel Thibault
@ 2016-02-08 22:12   ` Eric Blake
  2016-02-10 11:39   ` Thomas Huth
  1 sibling, 0 replies; 49+ messages in thread
From: Eric Blake @ 2016-02-08 22:12 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, Dave Gilbert, Vasiliy Tolstov, Huangpeng,
	Yann Bordenave, Gonglei, Jan Kiszka, Yang Hongyang,
	Guillaume Subiron

[-- Attachment #1: Type: text/plain, Size: 3293 bytes --]

On 02/08/2016 03:28 AM, 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..0ececcb 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];

Spaces around binary '+'

> +
> +            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.  */
> +                int len;
> +                char *end;
> +
> +                qemu_opt_set(opts, "ip6-prefix", buf, &error_abort);
> +                len = strtol(ip6_net, &end, 10);
> +
> +                if (*end != '\0') {
> +                    error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
> +                              "ip6-prefix", "a number");
> +                } else {
> +                    qemu_opt_set_number(opts, "ip6-prefixlen", len,
> +                                        &error_abort);
> +                }

Incorrect use of strtol() (you failed to check for overflow, which
requires priming errno to 0).  I recommend using qemu_strtol() instead,
as it does the grunt work for you and is harder to use incorrectly.

> +++ 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 (since 2.6)
> +#
> +# @ip6-prefixlen: #optional IPv6 network prefix length (since 2.6)

Would be worth mentioning the default values.

> +#
> +# @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

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

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

* Re: [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
@ 2016-02-09 16:14   ` Thomas Huth
  2016-02-09 16:31     ` Samuel Thibault
                       ` (3 more replies)
  0 siblings, 4 replies; 49+ messages in thread
From: Thomas Huth @ 2016-02-09 16:14 UTC (permalink / raw)
  To: Samuel Thibault, qemu-devel
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei, Jan Kiszka,
	Yang Hongyang, Guillaume Subiron

On 08.02.2016 11:28, 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 |   4 +-
>  slirp/cksum.c       |  23 ++++
>  slirp/if.c          |   2 +-
>  slirp/ip6.h         | 139 +++++++++++++++++++++
>  slirp/ip6_icmp.c    | 350 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  slirp/ip6_icmp.h    | 244 ++++++++++++++++++++++++++++++++++++
>  slirp/ip6_input.c   |  72 +++++++++++
>  slirp/ip6_output.c  |  41 ++++++
>  slirp/ndp_table.c   |  87 +++++++++++++
>  slirp/slirp.c       |  48 ++++++-
>  slirp/slirp.h       |  34 +++++
>  slirp/socket.h      |   7 ++
>  12 files changed, 1045 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..2dfe8e0 100644
> --- a/slirp/Makefile.objs
> +++ b/slirp/Makefile.objs
> @@ -1,3 +1,3 @@
> -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

The lines in this file are now longer than 80 columns ... could you
please rearrange them so that they do not exceed this limit anymore?

> diff --git a/slirp/cksum.c b/slirp/cksum.c
> index bc0d017..d2b0a83 100644
> --- a/slirp/cksum.c
> +++ b/slirp/cksum.c
> @@ -138,3 +138,26 @@ cont:
>  	REDUCE;
>  	return (~sum & 0xffff);
>  }
> +
> +int ip6_cksum(struct mbuf *m)
> +{
> +    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;
> +}

Just a small remark here: The function looks ok to me, so it should be
OK for now, but I think there's some possibility for optimization here:
Either the fields in the pseudohdr could be aligned with the fields in
the real ip6 header, so that you would not need to copy all fields over
here, or the cksum() function could maybe be changed in a way so that it
is possible to calculate the checksum of the pseudoheader and upper
layer header separately (and then return the sum of both checksums), so
that you don't have to replace the ip6 header in-place here.
Anyway, no need to do that right now, IMHO, but we might keep this in
mind as a future possibility for optimization.

> 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..9e65acd
> --- /dev/null
> +++ b/slirp/ip6.h
> @@ -0,0 +1,139 @@
> +/*
> + * Copyright (c) 2013
> + * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
> + *
> + * Please read the file COPYRIGHT for the
> + * terms and conditions of the copyright.
> + */
> +
> +#ifndef _IP6_H_
> +#define _IP6_H_

IIRC, defines that start with an underscore are reserved by the C
standard ... so maybe better use SLIRP_IP6_H or so instead of _IP6_H_ ?

> +#define in6_multicast(a) IN6_IS_ADDR_MULTICAST(&(a))
> +#define in6_linklocal(a) IN6_IS_ADDR_LINKLOCAL(&(a))
> +#define in6_unspecified(a) IN6_IS_ADDR_UNSPECIFIED(&(a))

I think at least I personally would not introduce these additional three
macros here, and use the original macros instead. But that's likely just
my personal taste.

BTW, at least in6_linklocal() seems to be unused, so you could remove
that one.

> +#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 int in6_equal(struct in6_addr a, struct in6_addr b)

What about using pointers to the structs as parameters? Passing whole
structs here sounds cumbersome to me.
(that also applies to the other inline functions below)

> +{
> +    return memcmp(&a, &b, sizeof(a)) == 0;
> +}
> +
> +static inline int in6_equal_net(struct in6_addr a, 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)));

checkpatch.pl complains here:

ERROR: return is not a function, parentheses are not required

There are also some other stylistic problems that checkpatch.pl reports
in this file ... would be nice to fix them.

> +}
> +
> +static inline int in6_equal_mach(struct in6_addr a, 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);

checkpatch.pl complains about the style here ... and I think you could
also drop the parentheses around "ip.s6_addr[16-(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..13f89af
> --- /dev/null
> +++ b/slirp/ip6_icmp.c
> @@ -0,0 +1,350 @@
> +/*
> + * Copyright (c) 2013
> + * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
> + *
> + * Please read the file COPYRIGHT for the
> + * terms and conditions of the copyright.
> + */
> +
> +#include "slirp.h"
> +#include "ip6_icmp.h"
> +#include "qemu/timer.h"
> +#include "qemu/error-report.h"
> +#include <stdlib.h>
> +#include <time.h>
> +
> +#define rand_a_b(a, b)\
> +    (rand()%(int)(b-a)+a)
> +#define NDP_Interval rand_a_b(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)
> +{
> +    srand(time(NULL));

That srand should maybe be done in main() instead? (Otherwise every
subsystem might end up in repeating this all over the place)

> +    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);
> +}
> +
> +#undef NDP_Interval
> +#undef rand_a_b
> +
> +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 *);

Not sure how strictly this is handled in QEMU, but for proper portable
C, variables should be declared at the beginning of a scope, as far as I
know.

> +    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 *);

dito

> +    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);
> +}
> +
> +/*
> + * 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;

Manipulating m_len is not really required here, is it?
Also the variable declaration should be at the beginning of the scope again.

> +    switch (icmp->icmp6_type) {
> +    case ICMP6_NDP_RS:
> +        DEBUG_CALL(" type = Routeur Solicitation");

s/Routeur/Router/

> +        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 = Routeur Advertisement");

s/Routeur/Router/

> +        error_report("Warning: guest sent NDP RA, but shouldn't\n");

If you use error_report, then please do not use "\n" in the strings.
OTOH, I wonder whether this should maybe rather be a
qemu_log_mask(LOG_GUEST_ERROR, ...) instead?

> +        break;
> +
> +    case ICMP6_NDP_NS:
> +        DEBUG_CALL(" type = Neighbor Solicitation");
> +        if (ip->ip_hl == 255
> +                && icmp->icmp6_code == 0
> +                && !in6_multicast(icmp->icmp6_nns.target)
> +                && ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN
> +                && (!in6_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);
> +
> +                /* 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_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_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);

Since this case statement is rather long and has a big indentation depth
already, I'd like to suggest to move the above code into a separate
function instead.

> +            }
> +        }
> +        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_multicast(icmp->icmp6_nna.target)
> +                && (!in6_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");
> +        error_report("Warning: guest sent NDP REDIRECT, but shouldn't\n");

Either remove the "\n" or use qemu_log_mask(LOG_GUEST_ERROR, ...)

> +        break;
> +
> +    default:
> +       return;

You can remove that default case.

> +    }
> +    return;

You can remove that return statement.

> +}
> +
> +/*
> + * 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 *);

Please move the variable declaration to the beginning of the scope.

> +    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 *);

dito

> +    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 *);

dito

> +    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);

I think you could shorten this to:

    t_m_data = rip;

?

> +    ricmp->icmp6_cksum = ip6_cksum(t);
> +
> +    ip6_output(NULL, t, 0);
> +}
...
> +/*
> + * 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\n");

Please remove the "\n" in the string.

> +        }
> +        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);
> +    return;

Superfluous return statement.

> +}
> diff --git a/slirp/ip6_icmp.h b/slirp/ip6_icmp.h
> new file mode 100644
> index 0000000..1ae003b
> --- /dev/null
> +++ b/slirp/ip6_icmp.h
> @@ -0,0 +1,244 @@
> +/*
> + * Copyright (c) 2013
> + * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
> + *
> + * Please read the file COPYRIGHT for the
> + * terms and conditions of the copyright.
> + */
> +
> +#ifndef _NETINET_ICMP6_H_
> +#define _NETINET_ICMP6_H_

Could you please use "SLIRP_IP6_ICMP_H" or so instead? At least please
don't use underscore in the beginning.

> +
> +/*
> + * 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 */
> +#define NDPOPT_REDIRECTED_HDR       4   /* Redirected Header */
> +#define NDPOPT_MTU                  5   /* MTU */
> +
> +/* 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_MCASTLST_QUERY    130 /* Multicast Listener Query */
> +#define ICMP6_MCASTLST_REPORT   131 /* Multicast Listener Report */
> +#define ICMP6_MCASTLST_DONE     132 /* Multicast Listener Done */
> +#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) */
> +#define ICMP6_ROUTERRENUM       138 /* Router Renumbering */
> +#define     ICMP6_ROUTERRENUM_COMMAND   0       /* router renum command */
> +#define     ICMP6_ROUTERRENUM_RESULT    1       /* router renum result */
> +#define     ICMP6_ROUTERRENUM_RESET     255     /* sequence number reset */
> +#define ICMP6_NODEINFO_QUERY    139 /* ICMP Node Information Query */
> +#define     ICMP6_NODEINFO_QUERY_IPV6   0       /* subject is an IPv6 */
> +#define     ICMP6_NODEINFO_QUERY_NAME   1       /* subj is a name (or empty) */
> +#define     ICMP6_NODEINFO_QUERY_IPV4   2       /* subject is an IPv4 */
> +#define ICMP6_NODEINFO_RESP     140 /* ICMP Node Information Response */
> +#define     ICMP6_NODEINFO_RESP_SUCCESS 0       /* successful reply */
> +#define     ICMP6_NODEINFO_RESP_REFUSAL 1       /* refuses to supply answer */
> +#define     ICMP6_NODEINFO_RESP_UNKNOWN 2       /* Qtype unknown to the resp */
> +#define ICMP6_IND_S             141 /* Inverse Neighbor Discovery Sol. */
> +#define ICMP6_IND_A             142 /* Inverse Neighbor Discovery Adv. */
> +#define ICMP6_MLD               143 /* Multicast Listener Discovery reports */
> +#define ICMP6_HAAD_REQUEST      144 /* Home Agent Address Discovery Request */
> +#define ICMP6_HAAD_REPLY        145 /* Home Agent Address Discovery Reply */
> +#define ICMP6_MP_SOL            146 /* Mobile Prefix Solicitation */
> +#define ICMP6_MP_ADV            147 /* Mobile Prefix Advertisement */
> +#define ICMP6_SEND_CPS          148 /* Certification Path Solicitation (SEND) */
> +#define ICMP6_SEND_CPA          149 /* Certification Path Adv. (SEND) */
> +#define ICMP6_MRD_RA            151 /* Multicast Router Advertisement (MRD) */
> +#define ICMP6_MRD_RS            152 /* Multicast Router Solicitation (MRD) */
> +#define ICMP6_MRD_TERM          153 /* Multicast Router Termination (MRD) */
> +#define ICMP6_FMIP6             154 /* FMIPv6 Messages */
> +#define     ICMP6_FMIP6_RTSOLPR         2       /* RtSolPr */
> +#define     ICMP6_FMIP6_PRRTADV         3       /* PrRtAdv */
> +#define ICMP6_RPL_CONTROL       155 /* RPL Control Message */
> +#define ICMP6_ILNP6_LU          156 /* ILNPv6 Locator Update Message */
> +#define ICMP6_DUPADDR_REQUEST   157 /* Duplicate Address Request */
> +#define ICMP6_DUPADDR_CONFIRM   158 /* Duplicate Address Confirmation */
> +
> +#define ICMP6_INFOTYPE(type) ((type) >= 128)

A lot of these defines seem to be define in <netinet/icmp6.h> already
(as recommended by RFC 3542) ... would it be feasible to use that
standard header, instead of redefining here everything?

> +/*
> + * Router Configuration Variables (rfc4861#section-6)
> + */
> +#define NDP_IsRouter                1
> +#define NDP_AdvSendAdvertisements   1
> +#define NDP_MaxRtrAdvInterval       600000
> +#define NDP_MinRtrAdvInterval       ((NDP_MaxRtrAdvInterval >= 9) ? \
> +                                        0.33*NDP_MaxRtrAdvInterval : \

Could you use NDP_MaxRtrAdvInterval/3 instead of
0.33*NDP_MaxRtrAdvInterval to avoid the usage of floats here?

> +                                        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
...

 Thomas

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

* Re: [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  2016-02-09 16:14   ` Thomas Huth
@ 2016-02-09 16:31     ` Samuel Thibault
  2016-02-09 19:32       ` Thomas Huth
  2016-02-09 16:31     ` Eric Blake
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 49+ messages in thread
From: Samuel Thibault @ 2016-02-09 16:31 UTC (permalink / raw)
  To: Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, qemu-devel, Gonglei, Jan Kiszka,
	Huangpeng, Yang Hongyang, Guillaume Subiron

Thomas Huth, on Tue 09 Feb 2016 17:14:15 +0100, wrote:
> > +    return (a.s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8)))
> > +        == (b.s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8)));
> 
> checkpatch.pl complains here:
> 
> ERROR: return is not a function, parentheses are not required

This is a false positive, there are no outer parentheses here.

> There are also some other stylistic problems that checkpatch.pl reports
> in this file ... would be nice to fix them.

Uh, it seems they are new, I had made a checkpatch run at the time (but
that was like several months ago now...). So I'll have to go through it
again...

> > +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 *);
> 
> Not sure how strictly this is handled in QEMU, but for proper portable
> C, variables should be declared at the beginning of a scope, as far as I
> know.

AIUI, qemu requires C99, doesn't it?

Personnally I find it more readable to declare variables where they
start mattering instead of far away.

> > +    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;
> 
> Manipulating m_len is not really required here, is it?

Indeed, I however preferred to keep it for always keeping consistency,
in case mtod starts doing other stuff.

> > +    /* ICMPv6 Checksum */
> > +    t->m_data -= NDPOPT_LINKLAYER_LEN;
> > +    t->m_data -= ICMP6_NDP_RA_MINLEN;
> > +    t->m_data -= sizeof(struct ip6);
> 
> I think you could shorten this to:
> 
>     t_m_data = rip;

That's equivalent, yes.  We are here however following the current slirp
practice, which explicits what is happening here.

I'll also have a closer look at the rest, thanks,
Samuel

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

* Re: [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  2016-02-09 16:14   ` Thomas Huth
  2016-02-09 16:31     ` Samuel Thibault
@ 2016-02-09 16:31     ` Eric Blake
  2016-02-09 16:35       ` Samuel Thibault
  2016-02-09 19:56     ` Samuel Thibault
  2016-02-09 20:31     ` Samuel Thibault
  3 siblings, 1 reply; 49+ messages in thread
From: Eric Blake @ 2016-02-09 16:31 UTC (permalink / raw)
  To: Thomas Huth, Samuel Thibault, qemu-devel
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, Huangpeng, Gonglei, Jan Kiszka,
	Yang Hongyang, Guillaume Subiron

[-- Attachment #1: Type: text/plain, Size: 3361 bytes --]

On 02/09/2016 09:14 AM, Thomas Huth wrote:
> On 08.02.2016 11:28, 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.
>>

>> +static inline int in6_equal_net(struct in6_addr a, 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)));
> 
> checkpatch.pl complains here:
> 
> ERROR: return is not a function, parentheses are not required

'>>' binds higher than '==', so you could write:

return a.s6... % 8))
    == b.s6... % 8));

Make this function return bool, while you are at it.

> 
> There are also some other stylistic problems that checkpatch.pl reports
> in this file ... would be nice to fix them.
> 
>> +}
>> +
>> +static inline int in6_equal_mach(struct in6_addr a, struct in6_addr b,
>> +        int prefix_len)

Another candidate for returning bool.


>> +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);
> 
> checkpatch.pl complains about the style here ... and I think you could
> also drop the parentheses around "ip.s6_addr[16-(ETH_ALEN-2)]".

And remember spaces around both binary '-'

>> +++ b/slirp/ip6_icmp.c
>> @@ -0,0 +1,350 @@
>> +/*
>> + * Copyright (c) 2013

Want to add 2016?

>> + * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
>> + *
>> + * Please read the file COPYRIGHT for the
>> + * terms and conditions of the copyright.

We don't have a file named 'COPYRIGHT' in the tree.  By default you are
getting GPLv2+; be explicit if you meant something else.

>> + */
>> +
>> +#include "slirp.h"
>> +#include "ip6_icmp.h"
>> +#include "qemu/timer.h"
>> +#include "qemu/error-report.h"
>> +#include <stdlib.h>
>> +#include <time.h>

New .c files need to include "qemu/osdep.h" first; at which point
<stdlib.h> is pre-included.

>> +
>> +#define rand_a_b(a, b)\
>> +    (rand()%(int)(b-a)+a)

Spacing around binary operators.  Should we rely on glib for nicer
random interval functions?


>> +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 *);
> 
> Not sure how strictly this is handled in QEMU, but for proper portable
> C, variables should be declared at the beginning of a scope, as far as I
> know.

It's not portable to C89, but QEMU requires C99 where it is completely
portable.  However, being portable and being commonly used in the rest
of the source tree are two different things.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

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

* Re: [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  2016-02-09 16:31     ` Eric Blake
@ 2016-02-09 16:35       ` Samuel Thibault
  0 siblings, 0 replies; 49+ messages in thread
From: Samuel Thibault @ 2016-02-09 16:35 UTC (permalink / raw)
  To: Eric Blake
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, qemu-devel, Vasiliy Tolstov, Dave Gilbert, Gonglei,
	Jan Kiszka, Huangpeng, Yang Hongyang, Guillaume Subiron

Eric Blake, on Tue 09 Feb 2016 09:31:30 -0700, wrote:
> >> +++ b/slirp/ip6_icmp.c
> >> @@ -0,0 +1,350 @@
> >> +/*
> >> + * Copyright (c) 2013
> 
> Want to add 2016?

Well, nothing copyrightable has happened to these files since 2013...

Samuel

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

* Re: [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  2016-02-09 16:31     ` Samuel Thibault
@ 2016-02-09 19:32       ` Thomas Huth
  2016-02-09 20:16         ` Samuel Thibault
  0 siblings, 1 reply; 49+ messages in thread
From: Thomas Huth @ 2016-02-09 19:32 UTC (permalink / raw)
  To: Samuel Thibault
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, qemu-devel, Gonglei, Jan Kiszka,
	Huangpeng, Yang Hongyang, Guillaume Subiron

On 09.02.2016 17:31, Samuel Thibault wrote:
> Thomas Huth, on Tue 09 Feb 2016 17:14:15 +0100, wrote:
>>> +    return (a.s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8)))
>>> +        == (b.s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8)));
>>
>> checkpatch.pl complains here:
>>
>> ERROR: return is not a function, parentheses are not required
> 
> This is a false positive, there are no outer parentheses here.

Ah, you're right, of course, I haven't looked closely enough, sorry.
Maybe checkpatch.pl could also be silenced by putting the "==" at the
end of the first line instead?

>>> +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 *);
>>
>> Not sure how strictly this is handled in QEMU, but for proper portable
>> C, variables should be declared at the beginning of a scope, as far as I
>> know.
> 
> AIUI, qemu requires C99, doesn't it?

Ok, you're right again, this is even declared in the HACKING file of
QEMU, so this should be fine, I think.

 Thomas

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

* Re: [Qemu-devel] [PATCHv7 2/9] slirp: Adding ICMPv6 error sending
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 2/9] slirp: Adding ICMPv6 error sending Samuel Thibault
@ 2016-02-09 19:48   ` Thomas Huth
  0 siblings, 0 replies; 49+ messages in thread
From: Thomas Huth @ 2016-02-09 19:48 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 08.02.2016 11:28, 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.

You could maybe also put the icmp_error (for IPv4) related stuff into a
separate patch ... but I don't mind too much, this patch is also still
readable as it is right now.

> 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  | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  slirp/ip6_icmp.h  | 10 ++++++++++
>  slirp/ip6_input.c | 15 ++++++++------
>  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, 96 insertions(+), 22 deletions(-)
> 
> diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c
> index 13f89af..41e034b 100644
> --- a/slirp/ip6_icmp.c
> +++ b/slirp/ip6_icmp.c
> @@ -67,6 +67,66 @@ 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 = m_get(slirp);
> +    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));
> +
> +    /* IPv6 packet */
> +    struct ip6 *rip = mtod(t, struct ip6 *);
> +    rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
> +    if (in6_multicast(ip->ip_src) || in6_unspecified(ip->ip_src)) {
> +        /* TODO icmp error? */
> +        return;

I think you're leaking the buffer from "struct mbuf *t = m_get(slirp)"
here ... so "t" should be assigned after the above check instead.

> +    }
> +    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);
> +}
> +
>  /*
>   * Process a NDP message
>   */
> diff --git a/slirp/ip6_icmp.h b/slirp/ip6_icmp.h
> index 1ae003b..f47c29f 100644
> --- a/slirp/ip6_icmp.h
> +++ b/slirp/ip6_icmp.h
> @@ -22,6 +22,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
>   */
> @@ -85,6 +91,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;
> @@ -92,6 +99,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
> @@ -101,6 +109,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
> @@ -238,6 +247,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 e1e6229..828f47c 100644
> --- a/slirp/ip6_input.c
> +++ b/slirp/ip6_input.c
> @@ -33,7 +33,7 @@ void ip6_input(struct mbuf *m)
>      DEBUG_ARG("m_len = %d", m->m_len);
>  
>      if (m->m_len < sizeof(struct ip6)) {
> -        return;
> +        goto bad;
>      }

I think you could also merge this hunk into the previous patch instead.

>      ip6 = mtod(m, struct ip6 *);
> @@ -42,9 +42,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;
>      }
>  
> @@ -52,14 +57,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;
>  	}
>  
> 

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

* Re: [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  2016-02-09 16:14   ` Thomas Huth
  2016-02-09 16:31     ` Samuel Thibault
  2016-02-09 16:31     ` Eric Blake
@ 2016-02-09 19:56     ` Samuel Thibault
  2016-02-09 20:49       ` Thomas Huth
  2016-02-09 20:31     ` Samuel Thibault
  3 siblings, 1 reply; 49+ messages in thread
From: Samuel Thibault @ 2016-02-09 19:56 UTC (permalink / raw)
  To: Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, qemu-devel, Gonglei, Jan Kiszka,
	Huangpeng, Yang Hongyang, Guillaume Subiron

Thomas Huth, on Tue 09 Feb 2016 17:14:15 +0100, wrote:
> A lot of these defines seem to be define in <netinet/icmp6.h> already
> (as recommended by RFC 3542) ... would it be feasible to use that
> standard header, instead of redefining here everything?

I'm wondering how widely available that is.  On windows, for instance?

Samuel

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

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

Thomas Huth, on Tue 09 Feb 2016 20:32:49 +0100, wrote:
> Maybe checkpatch.pl could also be silenced by putting the "==" at the
> end of the first line instead?

No, it still warns.

Samuel

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

* Re: [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  2016-02-09 16:14   ` Thomas Huth
                       ` (2 preceding siblings ...)
  2016-02-09 19:56     ` Samuel Thibault
@ 2016-02-09 20:31     ` Samuel Thibault
  3 siblings, 0 replies; 49+ messages in thread
From: Samuel Thibault @ 2016-02-09 20:31 UTC (permalink / raw)
  To: Thomas Huth, Eric Blake
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, qemu-devel, Gonglei, Jan Kiszka,
	Huangpeng, Yang Hongyang, Guillaume Subiron

Thomas Huth, on Tue 09 Feb 2016 17:14:15 +0100, wrote:
> > +    srand(time(NULL));
> 
> That srand should maybe be done in main() instead? (Otherwise every
> subsystem might end up in repeating this all over the place)

Eric Blake added:
> >> +#define rand_a_b(a, b)\
> >> +    (rand()%(int)(b-a)+a)
> 
>   Should we rely on glib for nicer random interval functions?

Why not indeed.  What do you prefer?  A global GRand (as suggested
above), or a GRand local to the Slirp?

Samuel

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

* Re: [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support Samuel Thibault
@ 2016-02-09 20:44   ` Thomas Huth
  2016-02-09 21:13     ` Samuel Thibault
  0 siblings, 1 reply; 49+ messages in thread
From: Thomas Huth @ 2016-02-09 20: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,
	Yang Hongyang, Guillaume Subiron

On 08.02.2016 11:28, 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>
> ---
...
> 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();

Could this be triggered by the guest? If so, I'd like to suggest to use
qemu_log_mask(LOG_GUEST_ERROR, ...) instead, since a guest should not be
able to terminate QEMU like this.

>  	        break;
>  	    }
>  	  } /* rx error */
...
> diff --git a/slirp/udp6.c b/slirp/udp6.c
> new file mode 100644
> index 0000000..63d6a8c
> --- /dev/null
> +++ b/slirp/udp6.c
> @@ -0,0 +1,150 @@
> +/*
> + * Copyright (c) 2013
> + * Guillaume Subiron
> + *
> + * Please read the file COPYRIGHT for the
> + * terms and conditions of the copyright.
> + */
> +
> +#include "slirp.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);
> +    }
> +
> +    /* 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 */

Why use the XXXs here? Some additional words in the comments would be
nice...

> +    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;

It's getting late already and maybe I should stop reviewing ... but ...
using save_ip here looks bogus to me. Is this right, or just a
copy-n-paste error from the udpv4 code? Where is save_ip initialized?

> +        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;

dito.

> +    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);

I think you're missing the check for uh_sum = 0.

According to RFC768:

"If the computed  checksum  is zero,  it is transmitted  as all ones"

And according to RFC2460:

"whenever originating a UDP packet, an IPv6 node must compute a UDP
 checksum over the packet and the pseudo-header, and, if that
 computation yields a result of zero, it must be changed to hex
 FFFF for placement in the UDP header."

This is already done in udp.c, so you should also do this in udp6.c, I
think.

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

 Thomas

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

* Re: [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  2016-02-09 19:56     ` Samuel Thibault
@ 2016-02-09 20:49       ` Thomas Huth
  0 siblings, 0 replies; 49+ messages in thread
From: Thomas Huth @ 2016-02-09 20:49 UTC (permalink / raw)
  To: Samuel Thibault
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	Dave Gilbert, Vasiliy Tolstov, qemu-devel, Gonglei, Jan Kiszka,
	Huangpeng, Yang Hongyang, Guillaume Subiron

On 09.02.2016 20:56, Samuel Thibault wrote:
> Thomas Huth, on Tue 09 Feb 2016 17:14:15 +0100, wrote:
>> A lot of these defines seem to be define in <netinet/icmp6.h> already
>> (as recommended by RFC 3542) ... would it be feasible to use that
>> standard header, instead of redefining here everything?
> 
> I'm wondering how widely available that is.  On windows, for instance?

Ok, good point, I just tried with my MinGW cross-compiler, and the
header is apparently not available there. So never mind, and better keep
the #defines here.

 Thomas

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

* Re: [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support
  2016-02-09 20:44   ` Thomas Huth
@ 2016-02-09 21:13     ` Samuel Thibault
  2016-02-09 21:19       ` Samuel Thibault
  0 siblings, 1 reply; 49+ messages in thread
From: Samuel Thibault @ 2016-02-09 21:13 UTC (permalink / raw)
  To: Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, Dave Gilbert, Gonglei, Jan Kiszka,
	Huangpeng, Yang Hongyang, Guillaume Subiron

Thomas Huth, on Tue 09 Feb 2016 21:44:18 +0100, wrote:
> > +	    case AF_INET6:
> > +	        udp6_output(so, m, (struct sockaddr_in6 *) &saddr,
> > +	                    (struct sockaddr_in6 *) &daddr);
> > +	        break;
> >  	    default:
> > +	        g_assert_not_reached();
> 
> Could this be triggered by the guest?

No, here we are in sorecvfrom, which only reads ipv4 or ipv6 packets
from the udp socket.

> > +    so->so_ffamily = AF_INET6;
> > +    so->so_faddr6 = ip->ip_dst; /* XXX */
> > +    so->so_fport6 = uh->uh_dport; /* XXX */
> 
> Why use the XXXs here? Some additional words in the comments would be
> nice...

That's a copy/paste from the UDPv4 code.  I don't know why they are there.

Samuel

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

* Re: [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support
  2016-02-09 21:13     ` Samuel Thibault
@ 2016-02-09 21:19       ` Samuel Thibault
  2016-02-10  7:18         ` Thomas Huth
  0 siblings, 1 reply; 49+ messages in thread
From: Samuel Thibault @ 2016-02-09 21:19 UTC (permalink / raw)
  To: Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, Dave Gilbert, Gonglei, Jan Kiszka,
	Huangpeng, Yang Hongyang, Guillaume Subiron

Thanks for your reviews so far!  I have integrated the rest of comments,
the only remaining question for patches 1-3 is about srand() and rand().

Samuel

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

* Re: [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support
  2016-02-09 21:19       ` Samuel Thibault
@ 2016-02-10  7:18         ` Thomas Huth
  2016-02-10  7:37           ` Samuel Thibault
  0 siblings, 1 reply; 49+ messages in thread
From: Thomas Huth @ 2016-02-10  7:18 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 09.02.2016 22:19, Samuel Thibault wrote:
> Thanks for your reviews so far!  I have integrated the rest of comments,
> the only remaining question for patches 1-3 is about srand() and rand().

I personally don't mind whether you use rand(), g_random_int_range() or
g_rand_int_range() here, but of course, the ..._range() functions seem
to fit more naturally here.
I just think that if you use rand() or g_random_int_range(), the rng
should be seeded from the main() function, not from the slirp code.

 Thomas

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

* Re: [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support
  2016-02-10  7:18         ` Thomas Huth
@ 2016-02-10  7:37           ` Samuel Thibault
  0 siblings, 0 replies; 49+ messages in thread
From: Samuel Thibault @ 2016-02-10  7:37 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 08:18:45 +0100, wrote:
> On 09.02.2016 22:19, Samuel Thibault wrote:
> > Thanks for your reviews so far!  I have integrated the rest of comments,
> > the only remaining question for patches 1-3 is about srand() and rand().
> 
> I personally don't mind whether you use rand(), g_random_int_range() or
> g_rand_int_range() here, but of course, the ..._range() functions seem
> to fit more naturally here.
> I just think that if you use rand() or g_random_int_range(), the rng
> should be seeded from the main() function, not from the slirp code.

Understood, but what do maintainers prefer?  I don't mind either way, I
just want to write what will be preferred.

Samuel

^ permalink raw reply	[flat|nested] 49+ 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; 49+ 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] 49+ messages in thread

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

On 08.02.2016 11:28, 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>
> ---
>  slirp/ip_input.c   |  2 +-
>  slirp/slirp.c      |  6 ++++--
>  slirp/slirp.h      |  5 +++--
>  slirp/tcp_input.c  | 52 ++++++++++++++++++++++++++++++++++++++++++++--------
>  slirp/tcp_output.c | 14 +++++++++++---
>  slirp/tcp_subr.c   | 37 +++++++++++++++++++++++++++++--------
>  slirp/tcp_timer.c  |  3 ++-
>  7 files changed, 94 insertions(+), 25 deletions(-)
...
> diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
> index 26b0c8b..0cc279b 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:
> +	    goto drop;
> +	}
>  
>  	/*
>  	 * 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:
> +	    goto drop;
> +	}
>  
>  	so = solookup(&slirp->tcp_last_so, &slirp->tcb, &lhost, &fhost);
>  
> @@ -389,8 +402,17 @@ findso:
>  	  so->lhost.ss = lhost;
>  	  so->fhost.ss = fhost;
>  
> -	  if ((so->so_iptos = tcp_tos(so)) == 0)
> +	  so->so_iptos = tcp_tos(so);
> +	  if (so->so_iptos == 0) {
> +	      switch (af) {
> +	      case AF_INET:
>  	    so->so_iptos = ((struct ip *)ti)->ip_tos;

I think you could also indent this here immediately ... it's only one
line, so indenting immediately should not hurt readability here.

> +	          break;
> +	      default:
> +	          goto drop;
> +	          break;
> +	      }
> +	  }
>  
>  	  tp = sototcpcb(so);
>  	  tp->t_state = TCPS_LISTEN;
> @@ -569,7 +591,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) {
> @@ -607,7 +630,7 @@ findso:
>  	    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);
> +			  TH_RST|TH_ACK, af);
>  	    } else {
>  	      if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
>  	      HTONL(ti->ti_seq);             /* restore tcp header */
> @@ -616,7 +639,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);
> +	      switch (af) {
> +	      case AF_INET:
>  	      *ip=save_ip;

Could also be indented immediately.

> +	          break;
> +	      default:
> +	          goto drop;
> +	      }
>  	      icmp_send_error(m, ICMP_UNREACH, code, 0, strerror(errno));
>  	    }
>              tcp_close(tp);
> @@ -1289,11 +1318,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);
> +		    TH_RST|TH_ACK, af);
>  	}
>  
>  	return;
> @@ -1484,7 +1513,14 @@ tcp_mss(struct tcpcb *tp, u_int offer)
>  	DEBUG_ARG("tp = %p", tp);
>  	DEBUG_ARG("offer = %d", offer);
>  
> +	switch (so->so_ffamily) {
> +	case AF_INET:
>  	mss = min(IF_MTU, IF_MRU) - sizeof(struct tcphdr) + sizeof(struct ip);

dito, indent immediately.

> +	    break;
> +	default:
> +	    break;
> +	}
> +
>  	if (offer)
>  		mss = min(mss, offer);
>  	mss = max(mss, 32);
> diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
> index 7fc6a87..62ab1e5 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:
> +	    goto out;

Hmm, this jumps to a "return (error)" statement ... but as far as I can
see, error has never been initialized in this case? So I think you
either should set the error variable explicitely here, or simply "return
1" immediately instead of doing the goto.

> +	}
>  
>  	if (error) {
>  out:

 Thomas

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

* Re: [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring Samuel Thibault
@ 2016-02-10  8:42   ` Thomas Huth
  2016-02-10  9:20     ` Samuel Thibault
  0 siblings, 1 reply; 49+ messages in thread
From: Thomas Huth @ 2016-02-10  8:42 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>
> 
> 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  | 99 +++++++++++++++++++++++++++---------------------------
>  slirp/tcp_output.c | 29 ++++++++--------
>  slirp/tcp_subr.c   | 50 +++++++++++++--------------
>  3 files changed, 89 insertions(+), 89 deletions(-)

Not sure, it's just an idea, but maybe it would even make sense to
re-indent the whole files in the QEMU coding style now? I mean, indent
with 4 spaces instead of tabs?

 Thomas

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

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

Thomas Huth, on Wed 10 Feb 2016 09:35:31 +0100, wrote:
> Hmm, this jumps to a "return (error)" statement ... but as far as I can
> see, error has never been initialized in this case?

Actually those places are unreachable (the address family can only be
INET at this point, and only INET or INET6 once tcpv6 is added). I'll
use g_assert_not_reached() instead.

Samuel

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

* Re: [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring
  2016-02-10  8:42   ` Thomas Huth
@ 2016-02-10  9:20     ` Samuel Thibault
  2016-02-11 17:56       ` Eric Blake
  0 siblings, 1 reply; 49+ messages in thread
From: Samuel Thibault @ 2016-02-10  9: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 09:42:04 +0100, wrote:
> On 08.02.2016 11:28, Samuel Thibault wrote:
> > Signed-off-by: Guillaume Subiron <maethor@subiron.org>
> > Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> > ---
> >  slirp/tcp_input.c  | 99 +++++++++++++++++++++++++++---------------------------
> >  slirp/tcp_output.c | 29 ++++++++--------
> >  slirp/tcp_subr.c   | 50 +++++++++++++--------------
> >  3 files changed, 89 insertions(+), 89 deletions(-)
> 
> Not sure, it's just an idea, but maybe it would even make sense to
> re-indent the whole files in the QEMU coding style now? I mean, indent
> with 4 spaces instead of tabs?

I'm fine with doing it. Maintainers, what do you think?

Samuel

^ permalink raw reply	[flat|nested] 49+ 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; 49+ 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] 49+ 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; 49+ 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] 49+ messages in thread

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

On 08.02.2016 11:28, 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 eb0df81..5840471 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,6 +258,11 @@ 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 *);
> +	save_ip = *ip;
> +	save_ip6 = *ip6;

Could you do the "save_ip = *ip" within the "case AF_INET" below, and
the "save_ip6 = *ip6" within the case AF_INET6 ? That would avoid to
copy bytes that are not required.

>  	switch (af) {
>  	case AF_INET:
>  	    if (iphlen > sizeof(struct ip)) {
> @@ -264,13 +271,6 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, unsigned short af)
>  	    }
>  	    /* 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 +295,35 @@ 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:
> +	    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:
>  	    goto drop;
>  	}
>  
> +	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:
>  	    goto drop;
>  	}
> @@ -409,7 +436,6 @@ findso:
>  	          so->so_iptos = ((struct ip *)ti)->ip_tos;
>  	          break;
>  	      default:
> -	          goto drop;
>  	          break;
>  	      }
>  	  }
> @@ -643,6 +669,9 @@ findso:
>  	      case AF_INET:
>  	          *ip = save_ip;
>  	          break;
> +	      case AF_INET6:
> +	          *ip6 = save_ip6;
> +	          break;
>  	      default:
>  	          goto drop;
>  	      }
> @@ -1518,7 +1547,12 @@ 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();
>  	    break;
>  	}
...

 Thomas

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

* Re: [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses
  2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses Samuel Thibault
  2016-02-08 22:12   ` Eric Blake
@ 2016-02-10 11:39   ` Thomas Huth
  2016-02-10 12:45     ` Samuel Thibault
  1 sibling, 1 reply; 49+ messages in thread
From: Thomas Huth @ 2016-02-10 11:39 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, Yang Hongyang, Guillaume Subiron

On 08.02.2016 11:28, 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/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::";

Site-local prefixes have already been deprecated (see rfc3879) ... would
it be feasible to use a ULA prefix instead (fd00::/8,
see rfc4193) ?

 Thomas

^ permalink raw reply	[flat|nested] 49+ 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; 49+ 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] 49+ messages in thread

* Re: [Qemu-devel] [PATCHv7 7/9] slirp: Handle IPv6 in TCP functions
  2016-02-10 10:47   ` Thomas Huth
@ 2016-02-10 12:30     ` Samuel Thibault
  2016-02-10 12:41       ` Thomas Huth
  0 siblings, 1 reply; 49+ messages in thread
From: Samuel Thibault @ 2016-02-10 12: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, Yang Hongyang, Guillaume Subiron

Thomas Huth, on Wed 10 Feb 2016 11:47:05 +0100, wrote:
> > +	ip = mtod(m, struct ip *);
> > +	ip6 = mtod(m, struct ip6 *);
> > +	save_ip = *ip;
> > +	save_ip6 = *ip6;
> 
> Could you do the "save_ip = *ip" within the "case AF_INET" below, and
> the "save_ip6 = *ip6" within the case AF_INET6 ? That would avoid to
> copy bytes that are not required.

The issue is that when save_ip is used later on in another switch/case,
the compiler will warn that save_ip may be used uninitialized, because
the compiler is not smart enough to realize that the two codes are under
the same conditions. It seems to happen that my current version of gcc
doesn't warn about save_ip, but it does warn about ip if I moved that
too for instance. So we can move the assignment indeed, but there will
probably be some compilers which will emit a warning here, I don't know
what we prefer.

Samuel

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

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

On 10.02.2016 13:30, Samuel Thibault wrote:
> Thomas Huth, on Wed 10 Feb 2016 11:47:05 +0100, wrote:
>>> +	ip = mtod(m, struct ip *);
>>> +	ip6 = mtod(m, struct ip6 *);
>>> +	save_ip = *ip;
>>> +	save_ip6 = *ip6;
>>
>> Could you do the "save_ip = *ip" within the "case AF_INET" below, and
>> the "save_ip6 = *ip6" within the case AF_INET6 ? That would avoid to
>> copy bytes that are not required.
> 
> The issue is that when save_ip is used later on in another switch/case,
> the compiler will warn that save_ip may be used uninitialized, because
> the compiler is not smart enough to realize that the two codes are under
> the same conditions. It seems to happen that my current version of gcc
> doesn't warn about save_ip, but it does warn about ip if I moved that
> too for instance. So we can move the assignment indeed, but there will
> probably be some compilers which will emit a warning here, I don't know
> what we prefer.

If current compilers only complain about the "ip = ..." statement, then
I'd suggest to give it a try to only move the "save_ip = ..." statements
into the switch cases (I think it's worth a try since this is the more
expensive operation). If that causes trouble later, we can still move
the statements back (or maybe fix the warnings by other means).

 Thomas

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

* Re: [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses
  2016-02-10 11:39   ` Thomas Huth
@ 2016-02-10 12:45     ` Samuel Thibault
  2016-02-10 13:08       ` Daniel P. Berrange
  0 siblings, 1 reply; 49+ messages in thread
From: Samuel Thibault @ 2016-02-10 12:45 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, Yang Hongyang, Guillaume Subiron

Thomas Huth, on Wed 10 Feb 2016 12:39:10 +0100, wrote:
> > +    if (!vprefix6) {
> > +        vprefix6 = "fec0::";
> 
> Site-local prefixes have already been deprecated (see rfc3879) ... would
> it be feasible to use a ULA prefix instead (fd00::/8,
> see rfc4193) ?

The question is which ULA. Ideally we'd take a random one at each qemu
startup, but then it's a pain for users to type IPs by hand, all the
more so when it changes at each qemu startup. Another way is to have the
same in all qemu instances, hardcoded in qemu, i.e. like

https://xkcd.com/221/

proposes. That's still a pain to type, even if it is always the same,
and can still (since it's the same for all qemu instances) pose some of
the problems raised by rfc3879. The rfc1918 addresses we use in qemu
for ipv4 have the same issues. That's why I considered that the issues
mentioned by rfc3879 would not be relevant to qemu, and be simpler to
just use fec0::, and let the user chose his public or ULA prefix if he
needs it.

Samuel

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

* Re: [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses
  2016-02-10 12:45     ` Samuel Thibault
@ 2016-02-10 13:08       ` Daniel P. Berrange
  2016-02-11 20:30         ` Thomas Huth
  0 siblings, 1 reply; 49+ messages in thread
From: Daniel P. Berrange @ 2016-02-10 13:08 UTC (permalink / raw)
  To: Samuel Thibault
  Cc: Thomas Huth, zhanghailiang, Li Zhijian, Stefan Hajnoczi,
	Jason Wang, qemu-devel, Vasiliy Tolstov, Dave Gilbert,
	Yann Bordenave, Gonglei, Jan Kiszka, Huangpeng, Yang Hongyang,
	Guillaume Subiron

On Wed, Feb 10, 2016 at 01:45:22PM +0100, Samuel Thibault wrote:
> Thomas Huth, on Wed 10 Feb 2016 12:39:10 +0100, wrote:
> > > +    if (!vprefix6) {
> > > +        vprefix6 = "fec0::";
> > 
> > Site-local prefixes have already been deprecated (see rfc3879) ... would
> > it be feasible to use a ULA prefix instead (fd00::/8,
> > see rfc4193) ?
> 
> The question is which ULA. Ideally we'd take a random one at each qemu
> startup, but then it's a pain for users to type IPs by hand, all the
> more so when it changes at each qemu startup. Another way is to have the
> same in all qemu instances, hardcoded in qemu, i.e. like
> 
> https://xkcd.com/221/
> 
> proposes. That's still a pain to type, even if it is always the same,
> and can still (since it's the same for all qemu instances) pose some of
> the problems raised by rfc3879. The rfc1918 addresses we use in qemu
> for ipv4 have the same issues. That's why I considered that the issues
> mentioned by rfc3879 would not be relevant to qemu, and be simpler to
> just use fec0::, and let the user chose his public or ULA prefix if he
> needs it.

I'm inclined to agree that fec0:: is a better bet for QEMU's default
usage, despite rfc3879. As you say it is no worse than what we have
with IPv4, and IMHO it is preferrable to using a fixed ULA since that
would be non-compliant with the RFC which requires randomness.

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|

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

* Re: [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring
  2016-02-10  9:20     ` Samuel Thibault
@ 2016-02-11 17:56       ` Eric Blake
  2016-02-11 18:15         ` Samuel Thibault
  0 siblings, 1 reply; 49+ messages in thread
From: Eric Blake @ 2016-02-11 17:56 UTC (permalink / raw)
  To: Samuel Thibault, Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, Dave Gilbert, Gonglei, Jan Kiszka,
	Huangpeng, Guillaume Subiron

[-- Attachment #1: Type: text/plain, Size: 1263 bytes --]

On 02/10/2016 02:20 AM, Samuel Thibault wrote:
> Thomas Huth, on Wed 10 Feb 2016 09:42:04 +0100, wrote:
>> On 08.02.2016 11:28, Samuel Thibault wrote:
>>> Signed-off-by: Guillaume Subiron <maethor@subiron.org>
>>> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
>>> ---
>>>  slirp/tcp_input.c  | 99 +++++++++++++++++++++++++++---------------------------
>>>  slirp/tcp_output.c | 29 ++++++++--------
>>>  slirp/tcp_subr.c   | 50 +++++++++++++--------------
>>>  3 files changed, 89 insertions(+), 89 deletions(-)
>>
>> Not sure, it's just an idea, but maybe it would even make sense to
>> re-indent the whole files in the QEMU coding style now? I mean, indent
>> with 4 spaces instead of tabs?
> 
> I'm fine with doing it. Maintainers, what do you think?

If done as part of the series, it's probably okay to do it as a
pre-requisite patch.  Don't mix it in with actual code changes, and we
don't do whole-sale reindenting except as part of a larger series
(because 'git blame' will point to whoever did the reindenting instead
of the original code, which doesn't make sense when reindenting is done
in isolation).

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

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

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

Eric Blake, on Thu 11 Feb 2016 10:56:30 -0700, wrote:
> On 02/10/2016 02:20 AM, Samuel Thibault wrote:
> > Thomas Huth, on Wed 10 Feb 2016 09:42:04 +0100, wrote:
> >> On 08.02.2016 11:28, Samuel Thibault wrote:
> >>> Signed-off-by: Guillaume Subiron <maethor@subiron.org>
> >>> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> >>> ---
> >>>  slirp/tcp_input.c  | 99 +++++++++++++++++++++++++++---------------------------
> >>>  slirp/tcp_output.c | 29 ++++++++--------
> >>>  slirp/tcp_subr.c   | 50 +++++++++++++--------------
> >>>  3 files changed, 89 insertions(+), 89 deletions(-)
> >>
> >> Not sure, it's just an idea, but maybe it would even make sense to
> >> re-indent the whole files in the QEMU coding style now? I mean, indent
> >> with 4 spaces instead of tabs?
> > 
> > I'm fine with doing it. Maintainers, what do you think?
> 
> If done as part of the series, it's probably okay to do it as a
> pre-requisite patch.

Well, it'd rather be a post-requisite, since the patch series needs to
reindent the files quite a bit (see above: almost two hundred lines
reindented.

> Don't mix it in with actual code changes,

Sure.

> and we don't do whole-sale reindenting except as part of a larger
> series (because 'git blame' will point to whoever did the reindenting
> instead of the original code, which doesn't make sense when
> reindenting is done in isolation).

Yep, I agree, that's why I prefer to ask. I'm here putting the number of
lines reindented by my patch vs the total number of lines. A complete
reindent would probably need to modify basically all lines of the files.

slirp/tcp_input.c 99/1496
slirp/tcp_output.c 29/493
slirp/tcp_subr.c 50/926

It seems quite small in the end, perhaps we shouldn't reindent
everything actually.

Samuel

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

* Re: [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses
  2016-02-10 13:08       ` Daniel P. Berrange
@ 2016-02-11 20:30         ` Thomas Huth
  0 siblings, 0 replies; 49+ messages in thread
From: Thomas Huth @ 2016-02-11 20:30 UTC (permalink / raw)
  To: Daniel P. Berrange, Samuel Thibault
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, Dave Gilbert, Yann Bordenave,
	Gonglei, Jan Kiszka, Huangpeng, Yang Hongyang, Guillaume Subiron

On 10.02.2016 14:08, Daniel P. Berrange wrote:
> On Wed, Feb 10, 2016 at 01:45:22PM +0100, Samuel Thibault wrote:
>> Thomas Huth, on Wed 10 Feb 2016 12:39:10 +0100, wrote:
>>>> +    if (!vprefix6) {
>>>> +        vprefix6 = "fec0::";
>>>
>>> Site-local prefixes have already been deprecated (see rfc3879) ... would
>>> it be feasible to use a ULA prefix instead (fd00::/8,
>>> see rfc4193) ?
>>
>> The question is which ULA. Ideally we'd take a random one at each qemu
>> startup, but then it's a pain for users to type IPs by hand, all the
>> more so when it changes at each qemu startup. Another way is to have the
>> same in all qemu instances, hardcoded in qemu, i.e. like
>>
>> https://xkcd.com/221/
>>
>> proposes. That's still a pain to type, even if it is always the same,
>> and can still (since it's the same for all qemu instances) pose some of
>> the problems raised by rfc3879. The rfc1918 addresses we use in qemu
>> for ipv4 have the same issues. That's why I considered that the issues
>> mentioned by rfc3879 would not be relevant to qemu, and be simpler to
>> just use fec0::, and let the user chose his public or ULA prefix if he
>> needs it.
> 
> I'm inclined to agree that fec0:: is a better bet for QEMU's default
> usage, despite rfc3879. As you say it is no worse than what we have
> with IPv4, and IMHO it is preferrable to using a fixed ULA since that
> would be non-compliant with the RFC which requires randomness.

Ok, then let's go with fec0:: first. We still can change it later if
necessary.

 Thomas

^ permalink raw reply	[flat|nested] 49+ 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; 49+ 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] 49+ 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; 49+ 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] 49+ 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; 49+ 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] 49+ 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; 49+ 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] 49+ 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; 49+ 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] 49+ 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
@ 2016-02-14 17:47 ` Samuel Thibault
  2016-02-19  0:36   ` Samuel Thibault
  2016-02-19 13:44   ` Thomas Huth
  0 siblings, 2 replies; 49+ 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] 49+ messages in thread

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

Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
2016-02-09 16:14   ` Thomas Huth
2016-02-09 16:31     ` Samuel Thibault
2016-02-09 19:32       ` Thomas Huth
2016-02-09 20:16         ` Samuel Thibault
2016-02-09 16:31     ` Eric Blake
2016-02-09 16:35       ` Samuel Thibault
2016-02-09 19:56     ` Samuel Thibault
2016-02-09 20:49       ` Thomas Huth
2016-02-09 20:31     ` Samuel Thibault
2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 2/9] slirp: Adding ICMPv6 error sending Samuel Thibault
2016-02-09 19:48   ` Thomas Huth
2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 3/9] slirp: Adding IPv6 UDP support Samuel Thibault
2016-02-09 20:44   ` Thomas Huth
2016-02-09 21:13     ` Samuel Thibault
2016-02-09 21:19       ` Samuel Thibault
2016-02-10  7:18         ` Thomas Huth
2016-02-10  7:37           ` 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
2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 5/9] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff Samuel Thibault
2016-02-10  8:35   ` Thomas Huth
2016-02-10  9:17     ` Samuel Thibault
2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 6/9] slirp: Reindent after refactoring Samuel Thibault
2016-02-10  8:42   ` Thomas Huth
2016-02-10  9:20     ` Samuel Thibault
2016-02-11 17:56       ` Eric Blake
2016-02-11 18:15         ` Samuel Thibault
2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 7/9] slirp: Handle IPv6 in TCP functions Samuel Thibault
2016-02-10 10:47   ` Thomas Huth
2016-02-10 12:30     ` Samuel Thibault
2016-02-10 12:41       ` Thomas Huth
2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 8/9] slirp: Adding IPv6 address for DNS relay Samuel Thibault
2016-02-08 10:28 ` [Qemu-devel] [PATCHv7 9/9] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses Samuel Thibault
2016-02-08 22:12   ` Eric Blake
2016-02-10 11:39   ` Thomas Huth
2016-02-10 12:45     ` Samuel Thibault
2016-02-10 13:08       ` Daniel P. Berrange
2016-02-11 20:30         ` Thomas Huth
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 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

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).