All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode
@ 2014-03-30 22:22 Samuel Thibault
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 01/18] slirp: goto bad in udp_input if sosendto fails Samuel Thibault
                   ` (17 more replies)
  0 siblings, 18 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:22 UTC (permalink / raw)
  To: qemu-devel; +Cc: Stefan Hajnoczi, Jan Kiszka, 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. We have made some refactoring to make current code compatible with
IPv6.

Patches 1 to 8 are refactoring of existing code and do not change the behavior,
9 adds a helper, and 10 to 18 add ipv6 support. Patches 3 and 16 are only
reindents of the resulting code, without code change.

Difference with version 3 is:
- reindentation has been moved into separate patches
- inet6 support in sockaddr_equal has been moved to the ndp support patch.
- update first qemu version for the options

Here is a summary of the patches:

Refactoring patches:

[PATCH 01/18] slirp: goto bad in udp_input if sosendto fails
[PATCH 02/18] slirp: Generalizing and neutralizing code before adding
[PATCH 03/18] slirp: Reindent after refactoring
[PATCH 04/18] slirp: Make Socket structure IPv6 compatible
[PATCH 05/18] slirp: Factorizing address translation
[PATCH 06/18] slirp: Factorizing and cleaning solookup()
[PATCH 07/18] slirp: Make udp_attach IPv6 compatible
[PATCH 08/18] slirp: Adding family argument to tcp_fconnect()

Adding helper:
[PATCH 09/18] qemu/timer.h : Adding function to second scale

Adding v6 support:
[PATCH 10/18] slirp: Adding IPv6, ICMPv6 Echo and NDP
[PATCH 11/18] slirp: Adding ICMPv6 error sending
[PATCH 12/18] slirp: Adding IPv6 UDP support
[PATCH 13/18] slirp: Factorizing tcpiphdr structure with an union
[PATCH 14/18] slirp: Generalizing and neutralizing various TCP
[PATCH 15/18] slirp: Reindent after refactoring
[PATCH 16/18] slirp: Handle IPv6 in TCP functions
[PATCH 17/18] slirp: Adding IPv6 address for DNS relay
[PATCH 18/18] qapi-schema, qemu-options & slirp: Adding Qemu options

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

* [Qemu-devel] [PATCH 01/18] slirp: goto bad in udp_input if sosendto fails
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
@ 2014-03-30 22:22 ` Samuel Thibault
  2014-05-07 22:15   ` [Qemu-devel] [PATCH, DoS] slirp (arp): do not special-case bogus IP addresses Samuel Thibault
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 02/18] slirp: Generalizing and neutralizing code before adding IPv6 stuff Samuel Thibault
                   ` (16 subsequent siblings)
  17 siblings, 1 reply; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

Before this patch, if sosendto fails, udp_input is executed as if the
packet was sent. This could cause memory leak.
This patch adds a goto bad to cut the execution of this function.

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
---
 slirp/udp.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/slirp/udp.c b/slirp/udp.c
index 8cc6cb6..fd2446a 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -218,6 +218,7 @@ udp_input(register struct mbuf *m, int 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));
+	  goto bad;
 	}
 
 	m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
-- 
1.9.0

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

* [Qemu-devel] [PATCH 02/18] slirp: Generalizing and neutralizing code before adding IPv6 stuff
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 01/18] slirp: goto bad in udp_input if sosendto fails Samuel Thibault
@ 2014-03-30 22:22 ` Samuel Thibault
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 03/18] slirp: Reindent after refactoring Samuel Thibault
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

Basically, this patch replaces "arp" by "resolution" every time "arp"
means "mac resolution" and not specifically ARP.

Some indentation problems are solved in functions that will be modified
in the next patches (ip_input…).

In if_encap, a switch is added to prepare for the IPv6 case. Some code
is factorized.

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/if.c    |  2 +-
 slirp/mbuf.c  |  2 +-
 slirp/mbuf.h  |  2 +-
 slirp/slirp.c | 24 ++++++++++++++++++++----
 slirp/slirp.h | 12 ++++++------
 5 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/slirp/if.c b/slirp/if.c
index fb7acf8..e36b9cb 100644
--- a/slirp/if.c
+++ b/slirp/if.c
@@ -193,7 +193,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/mbuf.c b/slirp/mbuf.c
index 4fefb04..92c429e 100644
--- a/slirp/mbuf.c
+++ b/slirp/mbuf.c
@@ -91,7 +91,7 @@ m_get(Slirp *slirp)
 	m->m_len = 0;
         m->m_nextpkt = NULL;
         m->m_prevpkt = NULL;
-        m->arp_requested = false;
+        m->resolution_requested = false;
         m->expiration_date = (uint64_t)-1;
 end_error:
 	DEBUG_ARG("m = %lx", (long )m);
diff --git a/slirp/mbuf.h b/slirp/mbuf.h
index b144f1c..38fedf4 100644
--- a/slirp/mbuf.h
+++ b/slirp/mbuf.h
@@ -79,7 +79,7 @@ struct mbuf {
 	int	m_len;			/* Amount of data in this mbuf */
 
 	Slirp *slirp;
-	bool	arp_requested;
+	bool	resolution_requested;
 	uint64_t expiration_date;
 	/* start of dynamic buffer area, must be last element */
 	union {
diff --git a/slirp/slirp.c b/slirp/slirp.c
index bad8dad..676c86d 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -778,12 +778,14 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
         return 1;
     }
 
+    switch (iph->ip_v) {
+    case IPVERSION:
     if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
         uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
         struct ethhdr *reh = (struct ethhdr *)arp_req;
         struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
 
-        if (!ifm->arp_requested) {
+        if (!ifm->resolution_requested) {
             /* If the client addr is not known, send an ARP request */
             memset(reh->h_dest, 0xff, ETH_ALEN);
             memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
@@ -809,22 +811,36 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
             rah->ar_tip = iph->ip_dst.s_addr;
             slirp->client_ipaddr = iph->ip_dst;
             slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
-            ifm->arp_requested = true;
+            ifm->resolution_requested = true;
 
             /* Expire request and drop outgoing packet after 1 second */
             ifm->expiration_date = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL;
         }
         return 0;
     } else {
-        memcpy(eh->h_dest, ethaddr, ETH_ALEN);
         memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
         /* XXX: not correct */
         memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
         eh->h_proto = htons(ETH_P_IP);
+        break;
+    }
+
+    default:
+        /* Do not assert while we don't manage IP6VERSION */
+        /* assert(0); */
+        break;
+    }
+
+        memcpy(eh->h_dest, ethaddr, ETH_ALEN);
+        DEBUG_ARGS((dfd, " src = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                    eh->h_source[0], eh->h_source[1], eh->h_source[2],
+                    eh->h_source[3], eh->h_source[4], eh->h_source[5]));
+        DEBUG_ARGS((dfd, " dst = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                    eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
+                    eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]));
         memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
         slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
         return 1;
-    }
 }
 
 /* Drop host forwarding rule, return 0 if found. */
diff --git a/slirp/slirp.h b/slirp/slirp.h
index e4a1bd4..cd9f2d0 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -136,6 +136,12 @@ void free(void *ptr);
 #include "qemu/queue.h"
 #include "qemu/sockets.h"
 
+#define ETH_ALEN 6
+#define ETH_HLEN 14
+
+#define ETH_P_IP  0x0800        /* Internet Protocol packet  */
+#define ETH_P_ARP 0x0806        /* Address Resolution packet */
+
 #include "libslirp.h"
 #include "ip.h"
 #include "tcp.h"
@@ -158,12 +164,6 @@ void free(void *ptr);
 #include "bootp.h"
 #include "tftp.h"
 
-#define ETH_ALEN 6
-#define ETH_HLEN 14
-
-#define ETH_P_IP  0x0800        /* Internet Protocol packet  */
-#define ETH_P_ARP 0x0806        /* Address Resolution packet */
-
 #define ARPOP_REQUEST 1         /* ARP request */
 #define ARPOP_REPLY   2         /* ARP reply   */
 
-- 
1.9.0

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

* [Qemu-devel] [PATCH 03/18] slirp: Reindent after refactoring
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 01/18] slirp: goto bad in udp_input if sosendto fails Samuel Thibault
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 02/18] slirp: Generalizing and neutralizing code before adding IPv6 stuff Samuel Thibault
@ 2014-03-30 22:22 ` Samuel Thibault
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 04/18] slirp: Make Socket structure IPv6 compatible Samuel Thibault
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

No code change.

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
 slirp/slirp.c | 107 +++++++++++++++++++++++++++++-----------------------------
 1 file changed, 54 insertions(+), 53 deletions(-)

diff --git a/slirp/slirp.c b/slirp/slirp.c
index 676c86d..bfc4832 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -780,50 +780,51 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
 
     switch (iph->ip_v) {
     case IPVERSION:
-    if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
-        uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
-        struct ethhdr *reh = (struct ethhdr *)arp_req;
-        struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
-
-        if (!ifm->resolution_requested) {
-            /* If the client addr is not known, send an ARP request */
-            memset(reh->h_dest, 0xff, ETH_ALEN);
-            memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
-            memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
-            reh->h_proto = htons(ETH_P_ARP);
-            rah->ar_hrd = htons(1);
-            rah->ar_pro = htons(ETH_P_IP);
-            rah->ar_hln = ETH_ALEN;
-            rah->ar_pln = 4;
-            rah->ar_op = htons(ARPOP_REQUEST);
-
-            /* source hw addr */
-            memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
-            memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
-
-            /* source IP */
-            rah->ar_sip = slirp->vhost_addr.s_addr;
-
-            /* target hw addr (none) */
-            memset(rah->ar_tha, 0, ETH_ALEN);
-
-            /* target IP */
-            rah->ar_tip = iph->ip_dst.s_addr;
-            slirp->client_ipaddr = iph->ip_dst;
-            slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
-            ifm->resolution_requested = true;
-
-            /* Expire request and drop outgoing packet after 1 second */
-            ifm->expiration_date = qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL;
+        if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
+            uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
+            struct ethhdr *reh = (struct ethhdr *)arp_req;
+            struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
+
+            if (!ifm->resolution_requested) {
+                /* If the client addr is not known, send an ARP request */
+                memset(reh->h_dest, 0xff, ETH_ALEN);
+                memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
+                memcpy(&reh->h_source[2], &slirp->vhost_addr, 4);
+                reh->h_proto = htons(ETH_P_ARP);
+                rah->ar_hrd = htons(1);
+                rah->ar_pro = htons(ETH_P_IP);
+                rah->ar_hln = ETH_ALEN;
+                rah->ar_pln = 4;
+                rah->ar_op = htons(ARPOP_REQUEST);
+
+                /* source hw addr */
+                memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
+                memcpy(&rah->ar_sha[2], &slirp->vhost_addr, 4);
+
+                /* source IP */
+                rah->ar_sip = slirp->vhost_addr.s_addr;
+
+                /* target hw addr (none) */
+                memset(rah->ar_tha, 0, ETH_ALEN);
+
+                /* target IP */
+                rah->ar_tip = iph->ip_dst.s_addr;
+                slirp->client_ipaddr = iph->ip_dst;
+                slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
+                ifm->resolution_requested = true;
+
+                /* Expire request and drop outgoing packet after 1 second */
+                ifm->expiration_date =
+                    qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL;
+            }
+            return 0;
+        } else {
+            memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
+            /* XXX: not correct */
+            memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
+            eh->h_proto = htons(ETH_P_IP);
+            break;
         }
-        return 0;
-    } else {
-        memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
-        /* XXX: not correct */
-        memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
-        eh->h_proto = htons(ETH_P_IP);
-        break;
-    }
 
     default:
         /* Do not assert while we don't manage IP6VERSION */
@@ -831,16 +832,16 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
         break;
     }
 
-        memcpy(eh->h_dest, ethaddr, ETH_ALEN);
-        DEBUG_ARGS((dfd, " src = %02x:%02x:%02x:%02x:%02x:%02x\n",
-                    eh->h_source[0], eh->h_source[1], eh->h_source[2],
-                    eh->h_source[3], eh->h_source[4], eh->h_source[5]));
-        DEBUG_ARGS((dfd, " dst = %02x:%02x:%02x:%02x:%02x:%02x\n",
-                    eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
-                    eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]));
-        memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
-        slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
-        return 1;
+    memcpy(eh->h_dest, ethaddr, ETH_ALEN);
+    DEBUG_ARGS((dfd, " src = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                eh->h_source[0], eh->h_source[1], eh->h_source[2],
+                eh->h_source[3], eh->h_source[4], eh->h_source[5]));
+    DEBUG_ARGS((dfd, " dst = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
+                eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]));
+    memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
+    slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
+    return 1;
 }
 
 /* Drop host forwarding rule, return 0 if found. */
-- 
1.9.0

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

* [Qemu-devel] [PATCH 04/18] slirp: Make Socket structure IPv6 compatible
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (2 preceding siblings ...)
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 03/18] slirp: Reindent after refactoring Samuel Thibault
@ 2014-03-30 22:22 ` Samuel Thibault
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 05/18] slirp: Factorizing address translation Samuel Thibault
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

This patch replaces foreign and local address/port couples in Socket
structure by 2 sockaddr_storage which can be casted in sockaddr_in or
sockaddr_in6.
Direct access to address and port is still possible thanks to some
\#define, so retrocompatibility of the existing code is assured.

The ss_family field of sockaddr_storage is declared after each socket
creation.

The whole structure is also saved/restored when a Qemu session is
saved/restored.

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
---
 slirp/ip_icmp.c   |  2 ++
 slirp/slirp.c     | 48 ++++++++++++++++++++++++++++++++++++++++--------
 slirp/socket.c    | 14 +++++++++++---
 slirp/socket.h    | 25 +++++++++++++++++++++----
 slirp/tcp_input.c |  2 ++
 slirp/tcp_subr.c  |  2 ++
 slirp/udp.c       |  4 ++++
 7 files changed, 82 insertions(+), 15 deletions(-)

diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
index 9f1cb08..7c364da 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -170,8 +170,10 @@ icmp_input(struct mbuf *m, int hlen)
 	goto end_error;
       }
       so->so_m = m;
+      so->so_ffamily = AF_INET;
       so->so_faddr = ip->ip_dst;
       so->so_fport = htons(7);
+      so->so_lfamily = AF_INET;
       so->so_laddr = ip->ip_src;
       so->so_lport = htons(9);
       so->so_iptos = ip->ip_tos;
diff --git a/slirp/slirp.c b/slirp/slirp.c
index bfc4832..53af9e7 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -1025,10 +1025,26 @@ static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf)
 static void slirp_socket_save(QEMUFile *f, struct socket *so)
 {
     qemu_put_be32(f, so->so_urgc);
-    qemu_put_be32(f, so->so_faddr.s_addr);
-    qemu_put_be32(f, so->so_laddr.s_addr);
-    qemu_put_be16(f, so->so_fport);
-    qemu_put_be16(f, so->so_lport);
+    qemu_put_be16(f, so->so_ffamily);
+    switch (so->so_ffamily) {
+    case AF_INET:
+        qemu_put_be32(f, so->so_faddr.s_addr);
+        qemu_put_be16(f, so->so_fport);
+        break;
+    default:
+        fprintf(stderr,
+                "so_ffamily unknown, unable to save so_faddr and so_fport\n");
+    }
+    qemu_put_be16(f, so->so_lfamily);
+    switch (so->so_lfamily) {
+    case AF_INET:
+        qemu_put_be32(f, so->so_laddr.s_addr);
+        qemu_put_be16(f, so->so_lport);
+        break;
+    default:
+        fprintf(stderr,
+                "so_ffamily unknown, unable to save so_laddr and so_lport\n");
+    }
     qemu_put_byte(f, so->so_iptos);
     qemu_put_byte(f, so->so_emu);
     qemu_put_byte(f, so->so_type);
@@ -1148,10 +1164,26 @@ static int slirp_socket_load(QEMUFile *f, struct socket *so)
         return -ENOMEM;
 
     so->so_urgc = qemu_get_be32(f);
-    so->so_faddr.s_addr = qemu_get_be32(f);
-    so->so_laddr.s_addr = qemu_get_be32(f);
-    so->so_fport = qemu_get_be16(f);
-    so->so_lport = qemu_get_be16(f);
+    so->so_ffamily = qemu_get_be16(f);
+    switch (so->so_ffamily) {
+    case AF_INET:
+        so->so_faddr.s_addr = qemu_get_be32(f);
+        so->so_fport = qemu_get_be16(f);
+        break;
+    default:
+        fprintf(stderr,
+                "so_ffamily unknown, unable to restore so_faddr and so_lport\n");
+    }
+    so->so_lfamily = qemu_get_be16(f);
+    switch (so->so_lfamily) {
+    case AF_INET:
+        so->so_laddr.s_addr = qemu_get_be32(f);
+        so->so_lport = qemu_get_be16(f);
+        break;
+    default:
+        fprintf(stderr,
+                "so_ffamily unknown, unable to restore so_laddr and so_lport\n");
+    }
     so->so_iptos = qemu_get_byte(f);
     so->so_emu = qemu_get_byte(f);
     so->so_type = qemu_get_byte(f);
diff --git a/slirp/socket.c b/slirp/socket.c
index 37ac5cf..e6723bc 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -437,8 +437,8 @@ sowrite(struct socket *so)
 void
 sorecvfrom(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);
 
 	DEBUG_CALL("sorecvfrom");
 	DEBUG_ARG("so = %lx", (long)so);
@@ -527,7 +527,13 @@ sorecvfrom(struct socket *so)
 	     * If this packet was destined for CTL_ADDR,
 	     * make it look like that's where it came from, done by udp_output
 	     */
-	    udp_output(so, m, &addr);
+	    switch (so->so_ffamily) {
+	    case AF_INET:
+	        udp_output(so, m, (struct sockaddr_in *) &addr);
+	        break;
+	    default:
+	        break;
+	    }
 	  } /* rx error */
 	} /* if ping packet */
 }
@@ -619,6 +625,7 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
 
 	so->so_state &= SS_PERSISTENT_MASK;
 	so->so_state |= (SS_FACCEPTCONN | flags);
+	so->so_lfamily = AF_INET;
 	so->so_lport = lport; /* Kept in network format */
 	so->so_laddr.s_addr = laddr; /* Ditto */
 
@@ -645,6 +652,7 @@ tcp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
 	qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
 
 	getsockname(s,(struct sockaddr *)&addr,&addrlen);
+	so->so_ffamily = AF_INET;
 	so->so_fport = addr.sin_port;
 	if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
 	   so->so_faddr = slirp->vhost_addr;
diff --git a/slirp/socket.h b/slirp/socket.h
index 57e0407..07f116d 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -31,10 +31,27 @@ struct socket {
   struct tcpiphdr *so_ti;	   /* Pointer to the original ti within
 				    * so_mconn, for non-blocking connections */
   int so_urgc;
-  struct in_addr so_faddr;	   /* foreign host table entry */
-  struct in_addr so_laddr;	   /* local host table entry */
-  uint16_t so_fport;		   /* foreign port */
-  uint16_t so_lport;		   /* local port */
+  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 */
   uint8_t	so_emu;		/* Is the socket emulated? */
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index f946db8..4b1a383 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -374,8 +374,10 @@ findso:
 	  sbreserve(&so->so_snd, TCP_SNDSPACE);
 	  sbreserve(&so->so_rcv, TCP_RCVSPACE);
 
+	  so->so_lfamily = AF_INET;
 	  so->so_laddr = ti->ti_src;
 	  so->so_lport = ti->ti_sport;
+	  so->so_ffamily = AF_INET;
 	  so->so_faddr = ti->ti_dst;
 	  so->so_fport = ti->ti_dport;
 
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index 7571c5a..f15da70 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -413,6 +413,7 @@ 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;
     }
@@ -430,6 +431,7 @@ void tcp_connect(struct socket *inso)
     qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
     socket_set_nodelay(s);
 
+    so->so_ffamily = AF_INET;
     so->so_fport = addr.sin_port;
     so->so_faddr = addr.sin_addr;
     /* Translate connections from localhost to the real hostname */
diff --git a/slirp/udp.c b/slirp/udp.c
index fd2446a..da1a793 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -190,6 +190,7 @@ udp_input(register struct mbuf *m, int iphlen)
 	  /*
 	   * Setup fields
 	   */
+	  so->so_lfamily = AF_INET;
 	  so->so_laddr = ip->ip_src;
 	  so->so_lport = uh->uh_sport;
 
@@ -202,6 +203,7 @@ udp_input(register struct mbuf *m, int iphlen)
 	   */
 	}
 
+        so->so_ffamily = AF_INET;
         so->so_faddr = ip->ip_dst; /* XXX */
         so->so_fport = uh->uh_dport; /* XXX */
 
@@ -376,6 +378,7 @@ udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
 	socket_set_fast_reuse(so->s);
 
 	getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
+	so->so_ffamily = AF_INET;
 	so->so_fport = addr.sin_port;
 	if (addr.sin_addr.s_addr == 0 ||
 	    addr.sin_addr.s_addr == loopback_addr.s_addr) {
@@ -383,6 +386,7 @@ udp_listen(Slirp *slirp, uint32_t haddr, u_int hport, uint32_t laddr,
 	} else {
 	   so->so_faddr = addr.sin_addr;
 	}
+	so->so_lfamily = AF_INET;
 	so->so_lport = lport;
 	so->so_laddr.s_addr = laddr;
 	if (flags != SS_FACCEPTONCE)
-- 
1.9.0

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

* [Qemu-devel] [PATCH 05/18] slirp: Factorizing address translation
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (3 preceding siblings ...)
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 04/18] slirp: Make Socket structure IPv6 compatible Samuel Thibault
@ 2014-03-30 22:22 ` Samuel Thibault
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 06/18] slirp: Factorizing and cleaning solookup() Samuel Thibault
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

This patch factorizes some duplicate code into a new function,
sotranslate_out(). This function perform the address translation when a
packet is transmitted to the host network. If the paquet is destinated
to the host, the loopback address is used, and if the paquet is
destinated to the virtual DNS, the real DNS address is used. This code
is just a copy of the existant, but factorized and ready to manage the
IPv6 case.

On the same model, the major part of udp_output() code is moved into a
new sotranslate_in(). This function is directly used in sorecvfrom(),
like sotranslate_out() in sosendto().
udp_output() becoming useless, it is removed and udp_output2() is
renamed into udp_output(). This adds consistency with the udp6_output()
function introduced by further patches.

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
---
 slirp/bootp.c    |  2 +-
 slirp/ip_icmp.c  | 19 +++---------
 slirp/socket.c   | 93 ++++++++++++++++++++++++++++++++++++++++++++------------
 slirp/socket.h   |  3 ++
 slirp/tcp_subr.c | 24 +++------------
 slirp/tftp.c     |  6 ++--
 slirp/udp.c      | 27 +---------------
 slirp/udp.h      |  3 +-
 8 files changed, 91 insertions(+), 86 deletions(-)

diff --git a/slirp/bootp.c b/slirp/bootp.c
index b7db9fa..03e2e42 100644
--- a/slirp/bootp.c
+++ b/slirp/bootp.c
@@ -319,7 +319,7 @@ static void bootp_reply(Slirp *slirp, const struct bootp_t *bp)
 
     m->m_len = sizeof(struct bootp_t) -
         sizeof(struct ip) - sizeof(struct udphdr);
-    udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+    udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
 }
 
 void bootp_input(struct mbuf *m)
diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
index 7c364da..663885f 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -157,7 +157,7 @@ icmp_input(struct mbuf *m, int hlen)
         goto freeit;
     } else {
       struct socket *so;
-      struct sockaddr_in addr;
+      struct sockaddr_storage addr;
       if ((so = socreate(slirp)) == NULL) goto freeit;
       if (icmp_send(so, m, hlen) == 0) {
         return;
@@ -181,20 +181,9 @@ icmp_input(struct mbuf *m, int hlen)
       so->so_state = SS_ISFCONNECTED;
 
       /* Send the packet */
-      addr.sin_family = AF_INET;
-      if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
-          slirp->vnetwork_addr.s_addr) {
-	/* It's an alias */
-	if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
-	  if (get_dns_addr(&addr.sin_addr) < 0)
-	    addr.sin_addr = loopback_addr;
-	} else {
-	  addr.sin_addr = loopback_addr;
-	}
-      } else {
-	addr.sin_addr = so->so_faddr;
-      }
-      addr.sin_port = so->so_fport;
+      addr = so->fhost.ss;
+      sotranslate_out(so, &addr);
+
       if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0,
 		(struct sockaddr *)&addr, sizeof(addr)) == -1) {
 	DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
diff --git a/slirp/socket.c b/slirp/socket.c
index e6723bc..c0c8bc1 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -438,6 +438,7 @@ void
 sorecvfrom(struct socket *so)
 {
 	struct sockaddr_storage addr;
+	struct sockaddr_storage saddr, daddr;
 	socklen_t addrlen = sizeof(struct sockaddr_storage);
 
 	DEBUG_CALL("sorecvfrom");
@@ -525,11 +526,17 @@ sorecvfrom(struct socket *so)
 
 	    /*
 	     * If this packet was destined for CTL_ADDR,
-	     * make it look like that's where it came from, done by udp_output
+	     * make it look like that's where it came from
 	     */
+	    saddr = addr;
+	    sotranslate_in(so, &saddr);
+	    daddr = so->lhost.ss;
+
 	    switch (so->so_ffamily) {
 	    case AF_INET:
-	        udp_output(so, m, (struct sockaddr_in *) &addr);
+	        udp_output(so, m, (struct sockaddr_in *) &saddr,
+	                   (struct sockaddr_in *) &daddr,
+	                   so->so_iptos);
 	        break;
 	    default:
 	        break;
@@ -544,33 +551,20 @@ sorecvfrom(struct socket *so)
 int
 sosendto(struct socket *so, struct mbuf *m)
 {
-	Slirp *slirp = so->slirp;
 	int ret;
-	struct sockaddr_in addr;
+	struct sockaddr_storage addr;
 
 	DEBUG_CALL("sosendto");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("m = %lx", (long)m);
 
-        addr.sin_family = AF_INET;
-	if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
-	    slirp->vnetwork_addr.s_addr) {
-	  /* It's an alias */
-	  if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
-	    if (get_dns_addr(&addr.sin_addr) < 0)
-	      addr.sin_addr = loopback_addr;
-	  } else {
-	    addr.sin_addr = loopback_addr;
-	  }
-	} else
-	  addr.sin_addr = so->so_faddr;
-	addr.sin_port = so->so_fport;
-
-	DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
+	addr = so->fhost.ss;
+	DEBUG_CALL(" sendto()ing)");
+	sotranslate_out(so, &addr);
 
 	/* Don't care what port we get */
 	ret = sendto(so->s, m->m_data, m->m_len, 0,
-		     (struct sockaddr *)&addr, sizeof (struct sockaddr));
+		     (struct sockaddr *)&addr, sizeof(addr));
 	if (ret < 0)
 		return -1;
 
@@ -726,3 +720,62 @@ sofwdrain(struct socket *so)
 	else
 		sofcantsendmore(so);
 }
+
+/*
+ * Translate addr in host addr when it is a virtual address
+ * :TODO:maethor:130314: Manage IPv6
+ */
+void sotranslate_out(struct socket *so, struct sockaddr_storage *addr)
+{
+    Slirp *slirp = so->slirp;
+    struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+
+    switch (addr->ss_family) {
+    case AF_INET:
+        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+                slirp->vnetwork_addr.s_addr) {
+            /* It's an alias */
+            if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
+                if (get_dns_addr(&sin->sin_addr) < 0) {
+                    sin->sin_addr = loopback_addr;
+                }
+            } else {
+                sin->sin_addr = loopback_addr;
+            }
+        }
+
+        DEBUG_MISC((dfd, " addr.sin_port=%d, "
+            "addr.sin_addr.s_addr=%.16s\n",
+            ntohs(sin->sin_port), inet_ntoa(sin->sin_addr)));
+        break;
+
+    default:
+        break;
+    }
+}
+
+/* :TODO:maethor:130314: IPv6 */
+void sotranslate_in(struct socket *so, struct sockaddr_storage *addr)
+{
+    Slirp *slirp = so->slirp;
+    struct sockaddr_in *sin = (struct sockaddr_in *)addr;
+
+    switch (addr->ss_family) {
+    case AF_INET:
+        if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
+            slirp->vnetwork_addr.s_addr) {
+            uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
+
+            if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
+                sin->sin_addr = slirp->vhost_addr;
+            } else if (sin->sin_addr.s_addr == loopback_addr.s_addr ||
+                       so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
+                sin->sin_addr = so->so_faddr;
+            }
+        }
+        break;
+
+    default:
+        break;
+    }
+}
diff --git a/slirp/socket.h b/slirp/socket.h
index 07f116d..50059be 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -111,4 +111,7 @@ struct iovec; /* For win32 */
 size_t sopreprbuf(struct socket *so, struct iovec *iov, int *np);
 int soreadbuf(struct socket *so, const char *buf, int size);
 
+void sotranslate_out(struct socket *, struct sockaddr_storage *);
+void sotranslate_in(struct socket *, struct sockaddr_storage *);
+
 #endif /* _SOCKET_H_ */
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index f15da70..4791c0c 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -326,7 +326,6 @@ tcp_sockclosed(struct tcpcb *tp)
  */
 int tcp_fconnect(struct socket *so)
 {
-  Slirp *slirp = so->slirp;
   int ret=0;
 
   DEBUG_CALL("tcp_fconnect");
@@ -334,30 +333,17 @@ int tcp_fconnect(struct socket *so)
 
   if( (ret = so->s = qemu_socket(AF_INET,SOCK_STREAM,0)) >= 0) {
     int opt, s=so->s;
-    struct sockaddr_in addr;
+    struct sockaddr_storage addr;
 
     qemu_set_nonblock(s);
     socket_set_fast_reuse(s);
     opt = 1;
     qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
 
-    addr.sin_family = AF_INET;
-    if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
-        slirp->vnetwork_addr.s_addr) {
-      /* It's an alias */
-      if (so->so_faddr.s_addr == slirp->vnameserver_addr.s_addr) {
-	if (get_dns_addr(&addr.sin_addr) < 0)
-	  addr.sin_addr = loopback_addr;
-      } else {
-	addr.sin_addr = loopback_addr;
-      }
-    } else
-      addr.sin_addr = so->so_faddr;
-    addr.sin_port = so->so_fport;
-
-    DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, "
-		"addr.sin_addr.s_addr=%.16s\n",
-		ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
+    addr = so->fhost.ss;
+    DEBUG_CALL(" connect()ing")
+    sotranslate_out(so, &addr);
+
     /* We don't care what port we get */
     ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
 
diff --git a/slirp/tftp.c b/slirp/tftp.c
index 1a79c45..dee201b 100644
--- a/slirp/tftp.c
+++ b/slirp/tftp.c
@@ -155,7 +155,7 @@ static int tftp_send_oack(struct tftp_session *spt,
 
     m->m_len = sizeof(struct tftp_t) - 514 + n -
         sizeof(struct ip) - sizeof(struct udphdr);
-    udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+    udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
 
     return 0;
 }
@@ -193,7 +193,7 @@ static void tftp_send_error(struct tftp_session *spt,
   m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
         sizeof(struct ip) - sizeof(struct udphdr);
 
-  udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+  udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
 
 out:
   tftp_session_terminate(spt);
@@ -243,7 +243,7 @@ static void tftp_send_next_block(struct tftp_session *spt,
   m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
         sizeof(struct ip) - sizeof(struct udphdr);
 
-  udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+  udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
 
   if (nobytes == 512) {
     tftp_session_update(spt);
diff --git a/slirp/udp.c b/slirp/udp.c
index da1a793..309f0a4 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -236,7 +236,7 @@ bad:
 	m_free(m);
 }
 
-int udp_output2(struct socket *so, struct mbuf *m,
+int udp_output(struct socket *so, struct mbuf *m,
                 struct sockaddr_in *saddr, struct sockaddr_in *daddr,
                 int iptos)
 {
@@ -287,31 +287,6 @@ int udp_output2(struct socket *so, struct mbuf *m,
 	return (error);
 }
 
-int udp_output(struct socket *so, struct mbuf *m,
-               struct sockaddr_in *addr)
-
-{
-    Slirp *slirp = so->slirp;
-    struct sockaddr_in saddr, daddr;
-
-    saddr = *addr;
-    if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
-        slirp->vnetwork_addr.s_addr) {
-        uint32_t inv_mask = ~slirp->vnetwork_mask.s_addr;
-
-        if ((so->so_faddr.s_addr & inv_mask) == inv_mask) {
-            saddr.sin_addr = slirp->vhost_addr;
-        } else if (addr->sin_addr.s_addr == loopback_addr.s_addr ||
-                   so->so_faddr.s_addr != slirp->vhost_addr.s_addr) {
-            saddr.sin_addr = so->so_faddr;
-        }
-    }
-    daddr.sin_addr = so->so_laddr;
-    daddr.sin_port = so->so_lport;
-
-    return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
-}
-
 int
 udp_attach(struct socket *so)
 {
diff --git a/slirp/udp.h b/slirp/udp.h
index 9bf31fe..a04b8ce 100644
--- a/slirp/udp.h
+++ b/slirp/udp.h
@@ -76,12 +76,11 @@ struct mbuf;
 void udp_init(Slirp *);
 void udp_cleanup(Slirp *);
 void udp_input(register struct mbuf *, int);
-int udp_output(struct socket *, struct mbuf *, struct sockaddr_in *);
 int udp_attach(struct socket *);
 void udp_detach(struct socket *);
 struct socket * udp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int,
                            int);
-int udp_output2(struct socket *so, struct mbuf *m,
+int udp_output(struct socket *so, struct mbuf *m,
                 struct sockaddr_in *saddr, struct sockaddr_in *daddr,
                 int iptos);
 #endif
-- 
1.9.0

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

* [Qemu-devel] [PATCH 06/18] slirp: Factorizing and cleaning solookup()
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (4 preceding siblings ...)
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 05/18] slirp: Factorizing address translation Samuel Thibault
@ 2014-03-30 22:22 ` Samuel Thibault
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 07/18] slirp: Make udp_attach IPv6 compatible Samuel Thibault
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

This patch makes solookup() compatible with varying address families. Also,
this function was only compatible with TCP. Having the socket list in
argument, it is now compatible with UDP too. Finally, some optimization
code is factorized inside the function (the function look at the last
returned result before browsing the complete socket list).

This also adds a sockaddr_equal() function to compare two
sockaddr_storage.

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
---
 slirp/socket.c    | 30 ++++++++++++++++--------------
 slirp/socket.h    | 23 ++++++++++++++++++++++-
 slirp/tcp_input.c | 27 +++++++++++----------------
 slirp/udp.c       | 25 ++++++-------------------
 4 files changed, 55 insertions(+), 50 deletions(-)

diff --git a/slirp/socket.c b/slirp/socket.c
index c0c8bc1..0e37a52 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -15,24 +15,26 @@
 static void sofcantrcvmore(struct socket *so);
 static void sofcantsendmore(struct socket *so);
 
-struct socket *
-solookup(struct socket *head, struct in_addr laddr, u_int lport,
-         struct in_addr faddr, u_int fport)
+struct socket *solookup(struct socket **last, struct socket *head,
+        struct sockaddr_storage *lhost, struct sockaddr_storage *fhost)
 {
-	struct socket *so;
+    struct socket *so = *last;
 
-	for (so = head->so_next; so != head; so = so->so_next) {
-		if (so->so_lport == lport &&
-		    so->so_laddr.s_addr == laddr.s_addr &&
-		    so->so_faddr.s_addr == faddr.s_addr &&
-		    so->so_fport == fport)
-		   break;
-	}
+    /* Optimisation */
+    if (sockaddr_equal(&(so->lhost.ss), lhost)
+            && (!fhost || sockaddr_equal(&(so->fhost.ss), fhost))) {
+        return so;
+    }
 
-	if (so == head)
-	   return (struct socket *)NULL;
-	return so;
+    for (so = head->so_next; so != head; so = so->so_next) {
+        if (sockaddr_equal(&(so->lhost.ss), lhost)
+                && (!fhost || sockaddr_equal(&(so->fhost.ss), fhost))) {
+            *last = so;
+            return so;
+        }
+    }
 
+    return (struct socket *)NULL;
 }
 
 /*
diff --git a/slirp/socket.h b/slirp/socket.h
index 50059be..5a673ae 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -93,7 +93,28 @@ struct socket {
 #define SS_HOSTFWD		0x1000	/* Socket describes host->guest forwarding */
 #define SS_INCOMING		0x2000	/* Connection was initiated by a host on the internet */
 
-struct socket * solookup(struct socket *, struct in_addr, u_int, struct in_addr, u_int);
+static inline int sockaddr_equal(struct sockaddr_storage *a,
+        struct sockaddr_storage *b)
+{
+    if (a->ss_family != b->ss_family) {
+        return 0;
+    } else {
+        switch (a->ss_family) {
+        case AF_INET:
+        {
+            struct sockaddr_in *a4 = (struct sockaddr_in *) a;
+            struct sockaddr_in *b4 = (struct sockaddr_in *) b;
+            return (a4->sin_addr.s_addr == b4->sin_addr.s_addr
+                    && a4->sin_port == b4->sin_port);
+        }
+        default:
+            assert(0);
+        }
+    }
+}
+
+struct socket *solookup(struct socket **, struct socket *,
+        struct sockaddr_storage *, struct sockaddr_storage *);
 struct socket * socreate(Slirp *);
 void sofree(struct socket *);
 int soread(struct socket *);
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index 4b1a383..1b9a0b1 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -227,6 +227,7 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
 	int iss = 0;
 	u_long tiwin;
 	int ret;
+	struct sockaddr_storage lhost, fhost;
     struct ex_list *ex_ptr;
     Slirp *slirp;
 
@@ -320,16 +321,14 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
 	 * Locate pcb for segment.
 	 */
 findso:
-	so = slirp->tcp_last_so;
-	if (so->so_fport != ti->ti_dport ||
-	    so->so_lport != ti->ti_sport ||
-	    so->so_laddr.s_addr != ti->ti_src.s_addr ||
-	    so->so_faddr.s_addr != ti->ti_dst.s_addr) {
-		so = solookup(&slirp->tcb, ti->ti_src, ti->ti_sport,
-			       ti->ti_dst, ti->ti_dport);
-		if (so)
-			slirp->tcp_last_so = so;
-	}
+	lhost.ss_family = AF_INET;
+	((struct sockaddr_in *)&lhost)->sin_addr = ti->ti_src;
+	((struct sockaddr_in *)&lhost)->sin_port = ti->ti_sport;
+	fhost.ss_family = AF_INET;
+	((struct sockaddr_in *)&fhost)->sin_addr = ti->ti_dst;
+	((struct sockaddr_in *)&fhost)->sin_port = ti->ti_dport;
+
+	so = solookup(&slirp->tcp_last_so, &slirp->tcb, &lhost, &fhost);
 
 	/*
 	 * If the state is CLOSED (i.e., TCB does not exist) then
@@ -374,12 +373,8 @@ findso:
 	  sbreserve(&so->so_snd, TCP_SNDSPACE);
 	  sbreserve(&so->so_rcv, TCP_RCVSPACE);
 
-	  so->so_lfamily = AF_INET;
-	  so->so_laddr = ti->ti_src;
-	  so->so_lport = ti->ti_sport;
-	  so->so_ffamily = AF_INET;
-	  so->so_faddr = ti->ti_dst;
-	  so->so_fport = ti->ti_dport;
+	  so->lhost.ss = lhost;
+	  so->fhost.ss = fhost;
 
 	  if ((so->so_iptos = tcp_tos(so)) == 0)
 	    so->so_iptos = ((struct ip *)ti)->ip_tos;
diff --git a/slirp/udp.c b/slirp/udp.c
index 309f0a4..94f104d 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -70,6 +70,7 @@ udp_input(register struct mbuf *m, int iphlen)
 	int len;
 	struct ip save_ip;
 	struct socket *so;
+	struct sockaddr_storage lhost;
 
 	DEBUG_CALL("udp_input");
 	DEBUG_ARG("m = %lx", (long)m);
@@ -151,25 +152,11 @@ udp_input(register struct mbuf *m, int iphlen)
 	/*
 	 * Locate pcb for datagram.
 	 */
-	so = slirp->udp_last_so;
-	if (so->so_lport != uh->uh_sport ||
-	    so->so_laddr.s_addr != ip->ip_src.s_addr) {
-		struct socket *tmp;
-
-		for (tmp = slirp->udb.so_next; tmp != &slirp->udb;
-		     tmp = tmp->so_next) {
-			if (tmp->so_lport == uh->uh_sport &&
-			    tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
-				so = tmp;
-				break;
-			}
-		}
-		if (tmp == &slirp->udb) {
-		  so = NULL;
-		} else {
-		  slirp->udp_last_so = so;
-		}
-	}
+	lhost.ss_family = AF_INET;
+	((struct sockaddr_in *)&lhost)->sin_addr = ip->ip_src;
+	((struct sockaddr_in *)&lhost)->sin_port = uh->uh_sport;
+
+	so = solookup(&slirp->udp_last_so, &slirp->udb, &lhost, NULL);
 
 	if (so == NULL) {
 	  /*
-- 
1.9.0

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

* [Qemu-devel] [PATCH 07/18] slirp: Make udp_attach IPv6 compatible
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (5 preceding siblings ...)
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 06/18] slirp: Factorizing and cleaning solookup() Samuel Thibault
@ 2014-03-30 22:22 ` Samuel Thibault
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 08/18] slirp: Adding family argument to tcp_fconnect() Samuel Thibault
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

A sa_family_t is now passed in argument to udp_attach instead of using a
hardcoded "AF_INET" to call qemu_socket().

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
---
 slirp/ip_icmp.c | 2 +-
 slirp/udp.c     | 7 ++++---
 slirp/udp.h     | 2 +-
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
index 663885f..382b5dd 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -162,7 +162,7 @@ icmp_input(struct mbuf *m, int hlen)
       if (icmp_send(so, m, hlen) == 0) {
         return;
       }
-      if(udp_attach(so) == -1) {
+      if (udp_attach(so, AF_INET) == -1) {
 	DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
 		    errno,strerror(errno)));
 	sofree(so);
diff --git a/slirp/udp.c b/slirp/udp.c
index 94f104d..d5be05f 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -167,7 +167,7 @@ udp_input(register struct mbuf *m, int iphlen)
 	  if (!so) {
 	      goto bad;
 	  }
-	  if(udp_attach(so) == -1) {
+	  if (udp_attach(so, AF_INET) == -1) {
 	    DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
 			errno,strerror(errno)));
 	    sofree(so);
@@ -275,9 +275,10 @@ int udp_output(struct socket *so, struct mbuf *m,
 }
 
 int
-udp_attach(struct socket *so)
+udp_attach(struct socket *so, sa_family_t af)
 {
-  if((so->s = qemu_socket(AF_INET,SOCK_DGRAM,0)) != -1) {
+  so->s = qemu_socket(af, SOCK_DGRAM, 0);
+  if (so->s != -1) {
     so->so_expire = curtime + SO_EXPIRE;
     insque(so, &so->slirp->udb);
   }
diff --git a/slirp/udp.h b/slirp/udp.h
index a04b8ce..15e73c1 100644
--- a/slirp/udp.h
+++ b/slirp/udp.h
@@ -76,7 +76,7 @@ struct mbuf;
 void udp_init(Slirp *);
 void udp_cleanup(Slirp *);
 void udp_input(register struct mbuf *, int);
-int udp_attach(struct socket *);
+int udp_attach(struct socket *, sa_family_t af);
 void udp_detach(struct socket *);
 struct socket * udp_listen(Slirp *, uint32_t, u_int, uint32_t, u_int,
                            int);
-- 
1.9.0

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

* [Qemu-devel] [PATCH 08/18] slirp: Adding family argument to tcp_fconnect()
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (6 preceding siblings ...)
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 07/18] slirp: Make udp_attach IPv6 compatible Samuel Thibault
@ 2014-03-30 22:22 ` Samuel Thibault
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 09/18] qemu/timer.h : Adding function to second scale Samuel Thibault
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:22 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

This patch simply adds a sa_family_t argument to remove the hardcoded
"AF_INET" in the call of qemu_socket().

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
---
 slirp/slirp.h     | 2 +-
 slirp/tcp_input.c | 3 ++-
 slirp/tcp_subr.c  | 5 +++--
 3 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/slirp/slirp.h b/slirp/slirp.h
index cd9f2d0..4b66739 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -334,7 +334,7 @@ void tcp_respond(struct tcpcb *, register struct tcpiphdr *, register struct mbu
 struct tcpcb * tcp_newtcpcb(struct socket *);
 struct tcpcb * tcp_close(register struct tcpcb *);
 void tcp_sockclosed(struct tcpcb *);
-int tcp_fconnect(struct socket *);
+int tcp_fconnect(struct socket *, sa_family_t af);
 void tcp_connect(struct socket *);
 int tcp_attach(struct socket *);
 uint8_t tcp_tos(struct socket *);
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index 1b9a0b1..4c72430 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -581,7 +581,8 @@ findso:
 	    goto cont_input;
 	  }
 
-	  if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
+	  if ((tcp_fconnect(so, so->so_ffamily) == -1)
+	     && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
 	    u_char code=ICMP_UNREACH_NET;
 	    DEBUG_MISC((dfd, " tcp fconnect errno = %d-%s\n",
 			errno,strerror(errno)));
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index 4791c0c..3558115 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -324,14 +324,15 @@ tcp_sockclosed(struct tcpcb *tp)
  * nonblocking.  Connect returns after the SYN is sent, and does
  * not wait for ACK+SYN.
  */
-int tcp_fconnect(struct socket *so)
+int tcp_fconnect(struct socket *so, sa_family_t af)
 {
   int ret=0;
 
   DEBUG_CALL("tcp_fconnect");
   DEBUG_ARG("so = %lx", (long )so);
 
-  if( (ret = so->s = qemu_socket(AF_INET,SOCK_STREAM,0)) >= 0) {
+  ret = so->s = qemu_socket(af, SOCK_STREAM, 0);
+  if (ret >= 0) {
     int opt, s=so->s;
     struct sockaddr_storage addr;
 
-- 
1.9.0

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

* [Qemu-devel] [PATCH 09/18] qemu/timer.h : Adding function to second scale
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (7 preceding siblings ...)
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 08/18] slirp: Adding family argument to tcp_fconnect() Samuel Thibault
@ 2014-03-30 22:23 ` Samuel Thibault
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 10/18] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

This patch adds SCALE_S, timer_new_s(), and qemu_clock_get_s in qemu/timer.h to
manage second-scale timers.

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
 include/qemu/timer.h | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index 7f9a074..b46601c 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -7,6 +7,7 @@
 
 /* timers */
 
+#define SCALE_S  1000000000
 #define SCALE_MS 1000000
 #define SCALE_US 1000
 #define SCALE_NS 1
@@ -81,6 +82,20 @@ extern QEMUTimerListGroup main_loop_tlg;
 int64_t qemu_clock_get_ns(QEMUClockType type);
 
 /**
+ * qemu_clock_get_s;
+ * @type: the clock type
+ *
+ * Get the second value of a clock with
+ * type @type
+ *
+ * Returns: the clock value in seconds
+ */
+static inline int64_t qemu_clock_get_s(QEMUClockType type)
+{
+    return qemu_clock_get_ns(type) / SCALE_S;
+}
+
+/**
  * qemu_clock_get_ms;
  * @type: the clock type
  *
@@ -514,6 +529,23 @@ static inline QEMUTimer *timer_new_ms(QEMUClockType type, QEMUTimerCB *cb,
 }
 
 /**
+ * timer_new_s:
+ * @clock: the clock to associate with the timer
+ * @callback: the callback to call when the timer expires
+ * @opaque: the opaque pointer to pass to the callback
+ *
+ * Create a new timer with second scale on the default timer list
+ * associated with the clock.
+ *
+ * Returns: a pointer to the newly created timer
+ */
+static inline QEMUTimer *timer_new_s(QEMUClockType type, QEMUTimerCB *cb,
+                                     void *opaque)
+{
+    return timer_new(type, SCALE_S, cb, opaque);
+}
+
+/**
  * timer_free:
  * @ts: the timer
  *
-- 
1.9.0

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

* [Qemu-devel] [PATCH 10/18] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (8 preceding siblings ...)
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 09/18] qemu/timer.h : Adding function to second scale Samuel Thibault
@ 2014-03-30 22:23 ` Samuel Thibault
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 11/18] slirp: Adding ICMPv6 error sending Samuel Thibault
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

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.

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/ip6.h         | 139 +++++++++++++++++++++
 slirp/ip6_icmp.c    | 349 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 slirp/ip6_icmp.h    | 248 +++++++++++++++++++++++++++++++++++++
 slirp/ip6_input.c   |  75 +++++++++++
 slirp/ip6_output.c  |  41 ++++++
 slirp/ndp_table.c   |  87 +++++++++++++
 slirp/slirp.c       |  47 +++++--
 slirp/slirp.h       |  35 ++++++
 slirp/socket.h      |   7 ++
 11 files changed, 1045 insertions(+), 10 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 6328660..f0a1398 100644
--- a/slirp/cksum.c
+++ b/slirp/cksum.c
@@ -137,3 +137,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/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..4538bfd
--- /dev/null
+++ b/slirp/ip6_icmp.c
@@ -0,0 +1,349 @@
+/*
+ * 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 <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_s(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
+    ndp_send_ra(slirp);
+}
+
+void icmp6_init(Slirp *slirp)
+{
+    srand(time(NULL));
+    slirp->ra_timer = timer_new_s(QEMU_CLOCK_VIRTUAL, ra_timer_handler, slirp);
+    timer_mod(slirp->ra_timer, qemu_clock_get_s(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");
+        fprintf(stderr,
+                "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");
+        fprintf(stderr,
+                "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 */
+            lprint("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..bd9d3d9
--- /dev/null
+++ b/slirp/ip6_icmp.h
@@ -0,0 +1,248 @@
+/*
+ * 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       600
+#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)
+#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 *);
+/* :TODO:maethor:130312: icmp6_error
+void icmp6_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
+                const char *message);
+*/
+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..9663c42
--- /dev/null
+++ b/slirp/ip6_input.c
@@ -0,0 +1,75 @@
+/*
+ * 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) {
+        /* :TODO:maethor:130307: icmp6_error */
+        /*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:
+        /* :TODO:maethor:130307: TCP */
+        tcp_input(m, hlen, (struct socket *)NULL);
+        break;
+    case IPPROTO_UDP:
+        /* :TODO:maethor:130312: 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 53af9e7..eea2fee 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,12 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
     slirp->vnetwork_addr = vnetwork;
     slirp->vnetwork_mask = vnetmask;
     slirp->vhost_addr = vhost;
+    /* :TODO:maethor:130311: Use a parameter passed to the function */
+    inet_pton(AF_INET6, "fec0::0", &slirp->vprefix_addr6);
+    /* :TODO:maethor:130311: Use a parameter passed to the function */
+    slirp->vprefix_len = 64;
+    /* :TODO:maethor:130311: Use a parameter passed to the function */
+    inet_pton(AF_INET6, "fec0::2", &slirp->vhost_addr6);
     if (vhostname) {
         pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
                 vhostname);
@@ -251,6 +258,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 +752,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_IP6:
         m = m_get(slirp);
         if (!m)
             return;
@@ -757,8 +766,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_IP6) {
+            ip6_input(m);
+        }
         break;
+
     default:
         break;
     }
@@ -773,6 +787,8 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
     struct ethhdr *eh = (struct ethhdr *)buf;
     uint8_t ethaddr[ETH_ALEN];
     const struct ip *iph = (const struct ip *)ifm->m_data;
+    const struct ip6 *ip6h = mtod(ifm, const struct ip6 *);
+            char addrstr[INET6_ADDRSTRLEN];
 
     if (ifm->m_len + ETH_HLEN > sizeof(buf)) {
         return 1;
@@ -817,18 +833,33 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
                 ifm->expiration_date =
                     qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL;
             }
+             return 0;
+         } else {
+             memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
+             /* XXX: not correct */
+             memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
+             eh->h_proto = htons(ETH_P_IP);
+             break;
+         }
+
+    case IP6VERSION:
+        inet_ntop(AF_INET6, &(ip6h->ip_dst), addrstr, INET6_ADDRSTRLEN);
+        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 {
-            memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
-            /* XXX: not correct */
-            memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
-            eh->h_proto = htons(ETH_P_IP);
-            break;
+            eh->h_proto = htons(ETH_P_IP6);
+            in6_compute_ethaddr(ip6h->ip_src, eh->h_source);
         }
+        break;
 
     default:
-        /* Do not assert while we don't manage IP6VERSION */
-        /* assert(0); */
+        assert(0);
         break;
     }
 
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 4b66739..d16400b 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -141,15 +141,18 @@ void free(void *ptr);
 
 #define ETH_P_IP  0x0800        /* Internet Protocol packet  */
 #define ETH_P_ARP 0x0806        /* Address Resolution packet */
+#define ETH_P_IP6 0x86DD        /* IPv6 packet               */
 
 #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"
@@ -201,6 +204,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;
@@ -211,6 +231,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;
 
@@ -259,6 +282,9 @@ struct Slirp {
     struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
 
     ArpTable arp_table;
+    NdpTable ndp_table;
+
+    QEMUTimer *ra_timer;
 
     void *opaque;
 };
@@ -303,6 +329,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 *);
@@ -318,6 +345,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 5a673ae..2cbd428 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -107,6 +107,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:
             assert(0);
         }
-- 
1.9.0

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

* [Qemu-devel] [PATCH 11/18] slirp: Adding ICMPv6 error sending
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (9 preceding siblings ...)
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 10/18] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
@ 2014-03-30 22:23 ` Samuel Thibault
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 12/18] slirp: Adding IPv6 UDP support Samuel Thibault
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Yann Bordenave, Jan Kiszka, Samuel Thibault,
	Guillaume Subiron

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>
---
 slirp/ip6_icmp.c  | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 slirp/ip6_icmp.h  | 10 ++++++++++
 slirp/ip6_input.c | 16 ++++++++-------
 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(+), 23 deletions(-)

diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c
index 4538bfd..8952bbc 100644
--- a/slirp/ip6_icmp.c
+++ b/slirp/ip6_icmp.c
@@ -64,6 +64,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:maethor:130317: 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:Meow:130316: Handle this case */
+        break;
+    default:
+        assert(0);
+        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 bd9d3d9..deae1a1 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
@@ -242,6 +251,7 @@ void icmp6_input(struct mbuf *);
 void icmp6_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
                 const char *message);
 */
+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 9663c42..af098a5 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,10 +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) {
-        /* :TODO:maethor:130307: icmp6_error */
-        /*icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");*/
+        icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS);
         goto bad;
     }
 
@@ -53,16 +57,14 @@ void ip6_input(struct mbuf *m)
      * Switch out to protocol's input routine.
      */
     switch (ip6->ip_nh) {
-#if 0
     case IPPROTO_TCP:
         /* :TODO:maethor:130307: TCP */
-        tcp_input(m, hlen, (struct socket *)NULL);
+        icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
         break;
     case IPPROTO_UDP:
         /* :TODO:maethor:130312: 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 382b5dd..c896574 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -37,7 +37,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,
@@ -100,7 +100,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);
     }
 
@@ -188,7 +188,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 */
@@ -234,7 +234,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;
@@ -242,7 +242,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 = %lx", (long )msrc);
   DEBUG_ARG("msrc_len = %d", msrc->m_len);
 
@@ -432,7 +432,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 880bdfd..1925cdc 100644
--- a/slirp/ip_input.c
+++ b/slirp/ip_input.c
@@ -131,9 +131,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;
 	}
 
 	/*
@@ -636,7 +636,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 0e37a52..f333fcf 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -462,7 +462,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! */
@@ -510,7 +510,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 4c72430..25929bd 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -599,7 +599,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 d5be05f..f53ee11 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -206,7 +206,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;
 	}
 
-- 
1.9.0

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

* [Qemu-devel] [PATCH 12/18] slirp: Adding IPv6 UDP support
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (10 preceding siblings ...)
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 11/18] slirp: Adding ICMPv6 error sending Samuel Thibault
@ 2014-03-30 22:23 ` Samuel Thibault
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 13/18] slirp: Factorizing tcpiphdr structure with an union Samuel Thibault
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

This patch adds udp6_input() and udp6_output().
It also adds the IPv6 case in sorecvfrom().
Finally, udp_input() is called by ip6_input().

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
---
 slirp/Makefile.objs |   2 +-
 slirp/ip6_input.c   |   3 +-
 slirp/socket.c      |   7 ++-
 slirp/udp.h         |   5 ++
 slirp/udp6.c        | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 162 insertions(+), 4 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 af098a5..3290af8 100644
--- a/slirp/ip6_input.c
+++ b/slirp/ip6_input.c
@@ -62,8 +62,7 @@ void ip6_input(struct mbuf *m)
         icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
         break;
     case IPPROTO_UDP:
-        /* :TODO:maethor:130312: 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 f333fcf..31bbb7e 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -540,8 +540,13 @@ sorecvfrom(struct socket *so)
 	                   (struct sockaddr_in *) &daddr,
 	                   so->so_iptos);
 	        break;
-	    default:
+	    case AF_INET6:
+	        udp6_output(so, m, (struct sockaddr_in6 *) &saddr,
+	                    (struct sockaddr_in6 *) &daddr);
 	        break;
+	    default:
+	       assert(0);
+	       break;
 	    }
 	  } /* rx error */
 	} /* if ping packet */
diff --git a/slirp/udp.h b/slirp/udp.h
index 15e73c1..8a4d9f5 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..3940959
--- /dev/null
+++ b/slirp/udp6.c
@@ -0,0 +1,149 @@
+/*
+ * 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_storage 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.ss_family = AF_INET6;
+    ((struct sockaddr_in6 *)&lhost)->sin6_addr = ip->ip_src;
+    ((struct sockaddr_in6 *)&lhost)->sin6_port = uh->uh_sport;
+
+    so = solookup(&slirp->udp_last_so, &slirp->udb, &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:maethor:130313: 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);
+}
-- 
1.9.0

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

* [Qemu-devel] [PATCH 13/18] slirp: Factorizing tcpiphdr structure with an union
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (11 preceding siblings ...)
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 12/18] slirp: Adding IPv6 UDP support Samuel Thibault
@ 2014-03-30 22:23 ` Samuel Thibault
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 14/18] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff Samuel Thibault
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

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 92c429e..87ee550 100644
--- a/slirp/mbuf.c
+++ b/slirp/mbuf.c
@@ -23,7 +23,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 eea2fee..33ed0cd 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -756,15 +756,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 31bbb7e..567f9bc 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -482,7 +482,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:
+	      assert(0);
+	      break;
+	  }
 
 	  /*
 	   * XXX Shouldn't FIONREAD packets destined for port 53,
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index 25929bd..dde89b6 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -254,11 +254,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 );
@@ -275,14 +270,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;
 	}
@@ -1466,7 +1475,7 @@ tcp_mss(struct tcpcb *tp, u_int offer)
 	DEBUG_ARG("tp = %lx", (long)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 8aa3d90..4726f00 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -447,15 +447,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 3558115..b052947 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -75,9 +75,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;
@@ -130,6 +131,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 {
 		/*
@@ -149,8 +151,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;
@@ -163,12 +165,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
-- 
1.9.0

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

* [Qemu-devel] [PATCH 14/18] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (12 preceding siblings ...)
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 13/18] slirp: Factorizing tcpiphdr structure with an union Samuel Thibault
@ 2014-03-30 22:23 ` Samuel Thibault
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 15/18] slirp: Reindent after refactoring Samuel Thibault
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

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.

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
---
 slirp/ip_input.c   |  2 +-
 slirp/slirp.c      |  6 ++++--
 slirp/slirp.h      |  4 ++--
 slirp/tcp_input.c  | 53 +++++++++++++++++++++++++++++++++++++++++++++--------
 slirp/tcp_output.c | 14 +++++++++++---
 slirp/tcp_subr.c   | 48 +++++++++++++++++++++++++++++++++---------------
 slirp/tcp_timer.c  |  3 ++-
 7 files changed, 98 insertions(+), 32 deletions(-)

diff --git a/slirp/ip_input.c b/slirp/ip_input.c
index 1925cdc..9aa8909 100644
--- a/slirp/ip_input.c
+++ b/slirp/ip_input.c
@@ -199,7 +199,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 33ed0cd..7f2ed70 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -576,7 +576,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);
@@ -625,7 +626,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 d16400b..6c06505 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -354,7 +354,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 *, sa_family_t af);
 int tcp_mss(register struct tcpcb *, u_int);
 
 /* tcp_output.c */
@@ -365,7 +365,7 @@ 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, sa_family_t);
 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 dde89b6..48b7fc6 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -213,7 +213,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, sa_family_t af)
 {
   	struct ip save_ip, *ip;
 	register struct tcpiphdr *ti;
@@ -254,6 +254,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 );
@@ -295,6 +297,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,
@@ -330,12 +337,18 @@ 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:
 	((struct sockaddr_in *)&lhost)->sin_addr = ti->ti_src;
 	((struct sockaddr_in *)&lhost)->sin_port = ti->ti_sport;
-	fhost.ss_family = AF_INET;
 	((struct sockaddr_in *)&fhost)->sin_addr = ti->ti_dst;
 	((struct sockaddr_in *)&fhost)->sin_port = ti->ti_dport;
+	    break;
+	default:
+	    goto drop;
+	}
 
 	so = solookup(&slirp->tcp_last_so, &slirp->tcb, &lhost, &fhost);
 
@@ -385,8 +398,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;
@@ -565,7 +587,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) {
@@ -598,7 +621,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 */
@@ -607,7 +630,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);
@@ -1280,11 +1309,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;
@@ -1475,7 +1504,15 @@ tcp_mss(struct tcpcb *tp, u_int offer)
 	DEBUG_ARG("tp = %lx", (long)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:
+	    /* :TODO:maethor:130319: ??? */
+	    break;
+	}
+
 	if (offer)
 		mss = min(mss, offer);
 	mss = max(mss, 32);
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index 4726f00..1f5417d 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -60,7 +60,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;
@@ -446,13 +447,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;
@@ -463,6 +466,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 b052947..a1f060b 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -77,12 +77,20 @@ 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:
+	    /* :TODO:maethor:130321: ? */
+	    break;
+	}
 
 	n->ti_seq = 0;
 	n->ti_ack = 0;
@@ -109,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, sa_family_t af)
 {
 	register int tlen;
 	int win = 0;
@@ -143,8 +151,15 @@ 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:
+		    /* :TODO:maethor:130321: ? */
+		    break;
+		}
 #undef xchg
 	}
 	ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen));
@@ -167,11 +182,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;
@@ -184,6 +203,12 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m,
 	}
 
 	(void) ip_output((struct socket *)0, m);
+	    break;
+
+	default:
+	    /* :TODO:maethor:130321: ? */
+	    break;
+	}
 }
 
 /*
@@ -387,8 +412,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;
 
@@ -413,9 +438,7 @@ 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;
     }
 
     tcp_mss(sototcpcb(so), 0);
@@ -431,15 +454,10 @@ void tcp_connect(struct socket *inso)
     qemu_setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(int));
     socket_set_nodelay(s);
 
-    so->so_ffamily = AF_INET;
-    so->so_fport = addr.sin_port;
-    so->so_faddr = addr.sin_addr;
+    addr.ss_family = inso->so_ffamily;
+    so->fhost.ss = addr;
     /* Translate connections from localhost to the real hostname */
-    if (so->so_faddr.s_addr == 0 ||
-        (so->so_faddr.s_addr & loopback_mask) ==
-        (loopback_addr.s_addr & loopback_mask)) {
-        so->so_faddr = slirp->vhost_addr;
-    }
+    sotranslate_in(so, &(so->fhost.ss));
 
     /* Close the accept() socket, set right state */
     if (inso->so_state & SS_FACCEPTONCE) {
diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c
index 6c5bb11..42c6e7e 100644
--- a/slirp/tcp_timer.c
+++ b/slirp/tcp_timer.c
@@ -277,7 +277,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;
-- 
1.9.0

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

* [Qemu-devel] [PATCH 15/18] slirp: Reindent after refactoring
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (13 preceding siblings ...)
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 14/18] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff Samuel Thibault
@ 2014-03-30 22:23 ` Samuel Thibault
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 16/18] slirp: Handle IPv6 in TCP functions Samuel Thibault
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

No code change.

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

diff --git a/slirp/slirp.h b/slirp/slirp.h
index 6c06505..3cdf984 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -365,7 +365,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, sa_family_t);
+void tcp_respond(struct tcpcb *, register struct tcpiphdr *,
+        register struct mbuf *, tcp_seq, tcp_seq, int, sa_family_t);
 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 48b7fc6..3409557 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -256,48 +256,48 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, sa_family_t 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;
@@ -341,10 +341,10 @@ findso:
 	fhost.ss_family = af;
 	switch (af) {
 	case AF_INET:
-	((struct sockaddr_in *)&lhost)->sin_addr = ti->ti_src;
-	((struct sockaddr_in *)&lhost)->sin_port = ti->ti_sport;
-	((struct sockaddr_in *)&fhost)->sin_addr = ti->ti_dst;
-	((struct sockaddr_in *)&fhost)->sin_port = ti->ti_dport;
+	    ((struct sockaddr_in *)&lhost)->sin_addr = ti->ti_src;
+	    ((struct sockaddr_in *)&lhost)->sin_port = ti->ti_sport;
+	    ((struct sockaddr_in *)&fhost)->sin_addr = ti->ti_dst;
+	    ((struct sockaddr_in *)&fhost)->sin_port = ti->ti_dport;
 	    break;
 	default:
 	    goto drop;
@@ -402,7 +402,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;
@@ -588,8 +588,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 */
@@ -632,7 +632,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;
@@ -1506,7 +1506,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:
 	    /* :TODO:maethor:130319: ??? */
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index 1f5417d..ce0d0e6 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -451,21 +451,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 a1f060b..ba4eb80 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -79,12 +79,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:
 		    /* :TODO:maethor:130321: ? */
@@ -186,23 +186,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:
-- 
1.9.0

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

* [Qemu-devel] [PATCH 16/18] slirp: Handle IPv6 in TCP functions
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (14 preceding siblings ...)
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 15/18] slirp: Reindent after refactoring Samuel Thibault
@ 2014-03-30 22:23 ` Samuel Thibault
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 17/18] slirp: Adding IPv6 address for DNS relay Samuel Thibault
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 18/18] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses Samuel Thibault
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

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  |  4 ++--
 slirp/tcp.h        |  2 ++
 slirp/tcp_input.c  | 58 +++++++++++++++++++++++++++++++++++++++++-------------
 slirp/tcp_output.c | 16 +++++++++++++++
 slirp/tcp_subr.c   | 36 +++++++++++++++++++++++++++++----
 slirp/tcpip.h      |  9 +++++++++
 6 files changed, 105 insertions(+), 20 deletions(-)

diff --git a/slirp/ip6_input.c b/slirp/ip6_input.c
index 3290af8..b03b795 100644
--- a/slirp/ip6_input.c
+++ b/slirp/ip6_input.c
@@ -58,8 +58,8 @@ void ip6_input(struct mbuf *m)
      */
     switch (ip6->ip_nh) {
     case IPPROTO_TCP:
-        /* :TODO:maethor:130307: 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 3409557..e5056f8 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -215,7 +215,8 @@ present:
 void
 tcp_input(struct mbuf *m, int iphlen, struct socket *inso, sa_family_t 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;
@@ -254,6 +255,11 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, sa_family_t 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)) {
@@ -262,13 +268,6 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, sa_family_t 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;
 
 	    /*
@@ -293,16 +292,35 @@ tcp_input(struct mbuf *m, int iphlen, struct socket *inso, sa_family_t 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
@@ -346,6 +364,12 @@ findso:
 	    ((struct sockaddr_in *)&fhost)->sin_addr = ti->ti_dst;
 	    ((struct sockaddr_in *)&fhost)->sin_port = ti->ti_dport;
 	    break;
+	case AF_INET6:
+	    ((struct sockaddr_in6 *)&lhost)->sin6_addr = ti->ti_src6;
+	    ((struct sockaddr_in6 *)&lhost)->sin6_port = ti->ti_sport;
+	    ((struct sockaddr_in6 *)&fhost)->sin6_addr = ti->ti_dst6;
+	    ((struct sockaddr_in6 *)&fhost)->sin6_port = ti->ti_dport;
+	    break;
 	default:
 	    goto drop;
 	}
@@ -405,7 +429,6 @@ findso:
 	          so->so_iptos = ((struct ip *)ti)->ip_tos;
 	          break;
 	      default:
-	          goto drop;
 	          break;
 	      }
 	  }
@@ -634,6 +657,9 @@ findso:
 	      case AF_INET:
 	          *ip = save_ip;
 	          break;
+	      case AF_INET6:
+	          *ip6 = save_ip6;
+	          break;
 	      default:
 	          goto drop;
 	      }
@@ -1509,8 +1535,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:
-	    /* :TODO:maethor:130319: ??? */
+	    assert(0);
 	    break;
 	}
 
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index ce0d0e6..64742a2 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -62,6 +62,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;
@@ -467,6 +468,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 ba4eb80..6c087e3 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -87,8 +87,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:
-	    /* :TODO:maethor:130321: ? */
+	    assert(0);
 	    break;
 	}
 
@@ -156,8 +165,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:
-		    /* :TODO:maethor:130321: ? */
+		    assert(0);
 		    break;
 		}
 #undef xchg
@@ -183,6 +196,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:
@@ -205,8 +219,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:
-	    /* :TODO:maethor:130321: ? */
+	    assert(0);
 	    break;
 	}
 }
@@ -227,7 +255,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
-- 
1.9.0

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

* [Qemu-devel] [PATCH 17/18] slirp: Adding IPv6 address for DNS relay
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (15 preceding siblings ...)
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 16/18] slirp: Handle IPv6 in TCP functions Samuel Thibault
@ 2014-03-30 22:23 ` Samuel Thibault
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 18/18] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses Samuel Thibault
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Jan Kiszka, Samuel Thibault, Guillaume Subiron

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

Signed-off-by: Guillaume Subiron <maethor@subiron.org>
---
 slirp/ip6.h    |  5 ++++-
 slirp/slirp.c  |  2 ++
 slirp/slirp.h  |  1 +
 slirp/socket.c | 26 ++++++++++++++++++++++++--
 4 files changed, 31 insertions(+), 3 deletions(-)

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 7f2ed70..ce3a111 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -236,6 +236,8 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
     slirp->bootp_filename = g_strdup(bootfile);
     slirp->vdhcp_startaddr = vdhcp_start;
     slirp->vnameserver_addr = vnameserver;
+    /* :TODO:maethor:130311: Use a parameter passed to the function */
+    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 3cdf984..57fe17e 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -236,6 +236,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 567f9bc..a9b3957 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -741,12 +741,12 @@ sofwdrain(struct socket *so)
 
 /*
  * Translate addr in host addr when it is a virtual address
- * :TODO:maethor:130314: Manage IPv6
  */
 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,16 +767,29 @@ 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;
     }
 }
 
-/* :TODO:maethor:130314: IPv6 */
 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:
@@ -793,6 +806,15 @@ 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;
+            }
+        }
+
     default:
         break;
     }
-- 
1.9.0

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

* [Qemu-devel] [PATCH 18/18] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses
  2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
                   ` (16 preceding siblings ...)
  2014-03-30 22:23 ` [Qemu-devel] [PATCH 17/18] slirp: Adding IPv6 address for DNS relay Samuel Thibault
@ 2014-03-30 22:23 ` Samuel Thibault
  17 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-03-30 22:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Stefan Hajnoczi, Yann Bordenave, Jan Kiszka, Samuel Thibault,
	Guillaume Subiron

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        | 30 ++++++++++++++++++++++++++++++
 net/slirp.c      | 46 ++++++++++++++++++++++++++++++++++++++++------
 qapi-schema.json | 40 ++++++++++++++++++++++++++--------------
 qemu-options.hx  | 18 ++++++++++++++++--
 slirp/libslirp.h |  8 +++++---
 slirp/slirp.c    | 20 +++++++++-----------
 6 files changed, 126 insertions(+), 36 deletions(-)

diff --git a/net/net.c b/net/net.c
index 2c3af20..e62e9fb 100644
--- a/net/net.c
+++ b/net/net.c
@@ -817,6 +817,36 @@ 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);
+                qemu_opt_set_number(opts, "ip6-prefixlen", 64);
+            } else {
+                /* User-specified prefix length.  */
+                int len;
+                char *end;
+
+                qemu_opt_set(opts, "ip6-prefix", buf);
+                len = strtol(ip6_net, &end, 10);
+
+                if (*end != '\0') {
+                    error_set(errp, QERR_INVALID_PARAMETER_VALUE,
+                              "ip6-prefix", "a number");
+                } else {
+                    qemu_opt_set_number(opts, "ip6-prefixlen", len);
+                }
+            }
+            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 124e953..a3142f0 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -134,17 +134,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
@@ -212,6 +218,24 @@ 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;
     }
@@ -220,6 +244,12 @@ 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;
     }
@@ -242,8 +272,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) {
@@ -750,8 +782,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 7cfb5e5..6487d27 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2906,6 +2906,14 @@
 # @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
 #             to the guest
 #
+# @ip6-prefix: #optional IPv6 network prefix (since 2.1)
+#
+# @ip6-prefixlen: #optional IPv6 network prefix length (since 2.1)
+#
+# @ip6-host: #optional guest-visible IPv6 address of the host (since 2.1)
+#
+# @ip6-dns: #optional guest-visible IPv6 address of the virtual nameserver (since 2.1)
+#
 # @smb: #optional root directory of the built-in SMB server
 #
 # @smbserver: #optional IP address of the built-in SMB server
@@ -2919,20 +2927,24 @@
 ##
 { 'type': '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 56e5fdf..6ad2eb4 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1355,8 +1355,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
     "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
     "                create a new Network Interface Card and connect it to VLAN 'n'\n"
 #ifdef CONFIG_SLIRP
-    "-net user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,restrict=on|off]\n"
-    "         [,hostname=host][,dhcpstart=addr][,dns=addr][,dnssearch=domain][,tftp=dir]\n"
+    "-net user[,vlan=n][,name=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"
@@ -1474,6 +1475,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
@@ -1491,6 +1500,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 ce3a111..48e39f2 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,12 +224,9 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
     slirp->vnetwork_addr = vnetwork;
     slirp->vnetwork_mask = vnetmask;
     slirp->vhost_addr = vhost;
-    /* :TODO:maethor:130311: Use a parameter passed to the function */
-    inet_pton(AF_INET6, "fec0::0", &slirp->vprefix_addr6);
-    /* :TODO:maethor:130311: Use a parameter passed to the function */
-    slirp->vprefix_len = 64;
-    /* :TODO:maethor:130311: Use a parameter passed to the function */
-    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);
@@ -236,8 +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;
-    /* :TODO:maethor:130311: Use a parameter passed to the function */
-    inet_pton(AF_INET6, "fec0::3", &slirp->vnameserver_addr6);
+    slirp->vnameserver_addr6 = vnameserver6;
 
     if (vdnssearch) {
         translate_dnssearch(slirp, vdnssearch);
-- 
1.9.0

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

* [Qemu-devel] [PATCH, DoS] slirp (arp): do not special-case bogus IP addresses
  2014-03-30 22:22 ` [Qemu-devel] [PATCH 01/18] slirp: goto bad in udp_input if sosendto fails Samuel Thibault
@ 2014-05-07 22:15   ` Samuel Thibault
  2014-05-08  6:10     ` Edgar E. Iglesias
  2014-05-14  1:13     ` [Qemu-devel] [PATCHv2, " Samuel Thibault
  0 siblings, 2 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-05-07 22:15 UTC (permalink / raw)
  To: qemu-devel

Do not special-case addresses with zero host part, as we do not
necessarily know how big it is, and the guest can fake them anyway.

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

This is particularly bad actually, one can for instance simply do this
inside a Linux guest

ip addr add 192.0.0.0/1 dev eth0

and crash qemu (thus a DoS) by just emitting a packet (thus from
192.0.0.0), getting:

qemu-system-x86_64: /usr/src/qemu/slirp/arp_table.c:77: arp_table_search: Assertion `(ip_addr & __bswap_32 (~(0xfU << 28))) != 0' failed.

so it should probably go to all stable maintained versions.

 arp_table.c |    8 --------
 1 file changed, 8 deletions(-)

diff --git a/slirp/arp_table.c b/slirp/arp_table.c
index ecdb0ba..243cbbc 100644
--- a/slirp/arp_table.c
+++ b/slirp/arp_table.c
@@ -37,11 +37,6 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
                 ethaddr[0], ethaddr[1], ethaddr[2],
                 ethaddr[3], ethaddr[4], ethaddr[5]));
 
-    /* Check 0.0.0.0/8 invalid source-only addresses */
-    if ((ip_addr & htonl(~(0xfU << 28))) == 0) {
-        return;
-    }
-
     if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
         /* Do not register broadcast addresses */
         return;
@@ -73,9 +68,6 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
     DEBUG_CALL("arp_table_search");
     DEBUG_ARG("ip = 0x%x", ip_addr);
 
-    /* Check 0.0.0.0/8 invalid source-only addresses */
-    assert((ip_addr & htonl(~(0xfU << 28))) != 0);
-
     /* If broadcast address */
     if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
         /* return Ethernet broadcast address */

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

* Re: [Qemu-devel] [PATCH, DoS] slirp (arp): do not special-case bogus IP addresses
  2014-05-07 22:15   ` [Qemu-devel] [PATCH, DoS] slirp (arp): do not special-case bogus IP addresses Samuel Thibault
@ 2014-05-08  6:10     ` Edgar E. Iglesias
  2014-05-08  6:50       ` Samuel Thibault
  2014-05-14  1:13     ` [Qemu-devel] [PATCHv2, " Samuel Thibault
  1 sibling, 1 reply; 39+ messages in thread
From: Edgar E. Iglesias @ 2014-05-08  6:10 UTC (permalink / raw)
  To: Samuel Thibault; +Cc: qemu-devel

On Thu, May 08, 2014 at 12:15:09AM +0200, Samuel Thibault wrote:
> Do not special-case addresses with zero host part, as we do not
> necessarily know how big it is, and the guest can fake them anyway.


Hi Samuel,

The search part looks OK to me but when adding to the arp table, don't
you at least want to avoid adding mappings for 0.0.0.0/32? to avoid
for ex garps to pollute the cache with invalid entries?

Cheers,
Edgar



> 
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
> 
> This is particularly bad actually, one can for instance simply do this
> inside a Linux guest
> 
> ip addr add 192.0.0.0/1 dev eth0
> 
> and crash qemu (thus a DoS) by just emitting a packet (thus from
> 192.0.0.0), getting:
> 
> qemu-system-x86_64: /usr/src/qemu/slirp/arp_table.c:77: arp_table_search: Assertion `(ip_addr & __bswap_32 (~(0xfU << 28))) != 0' failed.
> 
> so it should probably go to all stable maintained versions.
> 
>  arp_table.c |    8 --------
>  1 file changed, 8 deletions(-)
> 
> diff --git a/slirp/arp_table.c b/slirp/arp_table.c
> index ecdb0ba..243cbbc 100644
> --- a/slirp/arp_table.c
> +++ b/slirp/arp_table.c
> @@ -37,11 +37,6 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
>                  ethaddr[0], ethaddr[1], ethaddr[2],
>                  ethaddr[3], ethaddr[4], ethaddr[5]));
>  
> -    /* Check 0.0.0.0/8 invalid source-only addresses */
> -    if ((ip_addr & htonl(~(0xfU << 28))) == 0) {
> -        return;
> -    }
> -
>      if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>          /* Do not register broadcast addresses */
>          return;
> @@ -73,9 +68,6 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
>      DEBUG_CALL("arp_table_search");
>      DEBUG_ARG("ip = 0x%x", ip_addr);
>  
> -    /* Check 0.0.0.0/8 invalid source-only addresses */
> -    assert((ip_addr & htonl(~(0xfU << 28))) != 0);
> -
>      /* If broadcast address */
>      if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>          /* return Ethernet broadcast address */
> 

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

* Re: [Qemu-devel] [PATCH, DoS] slirp (arp): do not special-case bogus IP addresses
  2014-05-08  6:10     ` Edgar E. Iglesias
@ 2014-05-08  6:50       ` Samuel Thibault
  2014-05-08  6:59         ` Edgar E. Iglesias
  0 siblings, 1 reply; 39+ messages in thread
From: Samuel Thibault @ 2014-05-08  6:50 UTC (permalink / raw)
  To: Edgar E. Iglesias; +Cc: qemu-devel

Edgar E. Iglesias, le Thu 08 May 2014 06:10:18 +0000, a écrit :
> The search part looks OK to me but when adding to the arp table, don't
> you at least want to avoid adding mappings for 0.0.0.0/32?

I don't see the gain, actually.  It would mean burning some CPU all the
time just to save a small potential memory loss and CPU burning in the
rare case when the guest behaves oddly.

> to avoid for ex garps to pollute the cache with invalid entries?

Only one entry will be created and updated by garps. The guest already
has a lot of ways to pollute the cache :)

samuel

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

* Re: [Qemu-devel] [PATCH, DoS] slirp (arp): do not special-case bogus IP addresses
  2014-05-08  6:50       ` Samuel Thibault
@ 2014-05-08  6:59         ` Edgar E. Iglesias
  2014-05-13 22:15           ` Samuel Thibault
  0 siblings, 1 reply; 39+ messages in thread
From: Edgar E. Iglesias @ 2014-05-08  6:59 UTC (permalink / raw)
  To: Samuel Thibault; +Cc: qemu-devel

On Thu, May 08, 2014 at 08:50:33AM +0200, Samuel Thibault wrote:
> Edgar E. Iglesias, le Thu 08 May 2014 06:10:18 +0000, a écrit :
> > The search part looks OK to me but when adding to the arp table, don't
> > you at least want to avoid adding mappings for 0.0.0.0/32?
> 
> I don't see the gain, actually.  It would mean burning some CPU all the
> time just to save a small potential memory loss and CPU burning in the
> rare case when the guest behaves oddly.
> 
> > to avoid for ex garps to pollute the cache with invalid entries?
> 
> Only one entry will be created and updated by garps. The guest already
> has a lot of ways to pollute the cache :)

Hi,

I was under the impression that entries for 0.0.0.0 are strictly
invalid (not about performance). I might be wrong though.

Cheers,
Edgar

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

* Re: [Qemu-devel] [PATCH, DoS] slirp (arp): do not special-case bogus IP addresses
  2014-05-08  6:59         ` Edgar E. Iglesias
@ 2014-05-13 22:15           ` Samuel Thibault
  2014-05-14  0:30             ` Edgar E. Iglesias
  0 siblings, 1 reply; 39+ messages in thread
From: Samuel Thibault @ 2014-05-13 22:15 UTC (permalink / raw)
  To: Edgar E. Iglesias; +Cc: qemu-devel

Edgar E. Iglesias, le Thu 08 May 2014 06:59:22 +0000, a écrit :
> On Thu, May 08, 2014 at 08:50:33AM +0200, Samuel Thibault wrote:
> > Edgar E. Iglesias, le Thu 08 May 2014 06:10:18 +0000, a écrit :
> > > The search part looks OK to me but when adding to the arp table, don't
> > > you at least want to avoid adding mappings for 0.0.0.0/32?
> > 
> > I don't see the gain, actually.  It would mean burning some CPU all the
> > time just to save a small potential memory loss and CPU burning in the
> > rare case when the guest behaves oddly.
> > 
> > > to avoid for ex garps to pollute the cache with invalid entries?
> > 
> > Only one entry will be created and updated by garps. The guest already
> > has a lot of ways to pollute the cache :)
> 
> I was under the impression that entries for 0.0.0.0 are strictly
> invalid (not about performance). I might be wrong though.

I'd tend to think that, but what should be done? I don't think we want
an assert failure :)

At best I could think of using the patch below, which avoids registering
anything for 0.0.0.0, and use a broadcast to answer a guest which
would have used 0.0.0.0 as a source for whatever reason.  I don't find
anything else reasonable.  What would be preferred?

Samuel

diff --git a/slirp/arp_table.c b/slirp/arp_table.c
index ecdb0ba..d160cfc 100644
--- a/slirp/arp_table.c
+++ b/slirp/arp_table.c
@@ -37,12 +37,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
                 ethaddr[0], ethaddr[1], ethaddr[2],
                 ethaddr[3], ethaddr[4], ethaddr[5]));
 
-    /* Check 0.0.0.0/8 invalid source-only addresses */
-    if ((ip_addr & htonl(~(0xfU << 28))) == 0) {
-        return;
-    }
-
-    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
+    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
         /* Do not register broadcast addresses */
         return;
     }
@@ -73,11 +68,8 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
     DEBUG_CALL("arp_table_search");
     DEBUG_ARG("ip = 0x%x", ip_addr);
 
-    /* Check 0.0.0.0/8 invalid source-only addresses */
-    assert((ip_addr & htonl(~(0xfU << 28))) != 0);
-
     /* If broadcast address */
-    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
+    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
         /* return Ethernet broadcast address */
         memset(out_ethaddr, 0xff, ETH_ALEN);
         return 1;

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

* Re: [Qemu-devel] [PATCH, DoS] slirp (arp): do not special-case bogus IP addresses
  2014-05-13 22:15           ` Samuel Thibault
@ 2014-05-14  0:30             ` Edgar E. Iglesias
  2014-05-14  0:44               ` Samuel Thibault
  0 siblings, 1 reply; 39+ messages in thread
From: Edgar E. Iglesias @ 2014-05-14  0:30 UTC (permalink / raw)
  To: Samuel Thibault; +Cc: qemu-devel

On Wed, May 14, 2014 at 12:15:47AM +0200, Samuel Thibault wrote:
> Edgar E. Iglesias, le Thu 08 May 2014 06:59:22 +0000, a écrit :
> > On Thu, May 08, 2014 at 08:50:33AM +0200, Samuel Thibault wrote:
> > > Edgar E. Iglesias, le Thu 08 May 2014 06:10:18 +0000, a écrit :
> > > > The search part looks OK to me but when adding to the arp table, don't
> > > > you at least want to avoid adding mappings for 0.0.0.0/32?
> > > 
> > > I don't see the gain, actually.  It would mean burning some CPU all the
> > > time just to save a small potential memory loss and CPU burning in the
> > > rare case when the guest behaves oddly.
> > > 
> > > > to avoid for ex garps to pollute the cache with invalid entries?
> > > 
> > > Only one entry will be created and updated by garps. The guest already
> > > has a lot of ways to pollute the cache :)
> > 
> > I was under the impression that entries for 0.0.0.0 are strictly
> > invalid (not about performance). I might be wrong though.
> 
> I'd tend to think that, but what should be done? I don't think we want
> an assert failure :)
> 

Right, I didn't mean that the assert should stay.

> At best I could think of using the patch below, which avoids registering
> anything for 0.0.0.0, and use a broadcast to answer a guest which
> would have used 0.0.0.0 as a source for whatever reason.  I don't find
> anything else reasonable.  What would be preferred?

Specs are not super clear on this but rfc1700 says that 0.0.0.0 is a source only address.
http://www.rfc-editor.org/rfc/rfc1700.txt Page 3
http://tools.ietf.org/html/draft-iana-special-ipv4-04 Page 1

What I was trying to suggest was a mix between your two versions.
Removing the assert in table_search and avoid adding 0.0.0.0/32 to the cache
in table_add. We might need to complement with something that drops datagrams
destined to 0.0.0.0 in upper layers so we dont keep trying, not sure.
Does something like that make sense?

Cheers,
Edgar


> 
> Samuel
> 
> diff --git a/slirp/arp_table.c b/slirp/arp_table.c
> index ecdb0ba..d160cfc 100644
> --- a/slirp/arp_table.c
> +++ b/slirp/arp_table.c
> @@ -37,12 +37,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
>                  ethaddr[0], ethaddr[1], ethaddr[2],
>                  ethaddr[3], ethaddr[4], ethaddr[5]));
>  
> -    /* Check 0.0.0.0/8 invalid source-only addresses */
> -    if ((ip_addr & htonl(~(0xfU << 28))) == 0) {
> -        return;
> -    }
> -
> -    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
> +    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>          /* Do not register broadcast addresses */
>          return;
>      }
> @@ -73,11 +68,8 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
>      DEBUG_CALL("arp_table_search");
>      DEBUG_ARG("ip = 0x%x", ip_addr);
>  
> -    /* Check 0.0.0.0/8 invalid source-only addresses */
> -    assert((ip_addr & htonl(~(0xfU << 28))) != 0);
> -
>      /* If broadcast address */
> -    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
> +    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>          /* return Ethernet broadcast address */
>          memset(out_ethaddr, 0xff, ETH_ALEN);
>          return 1;

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

* Re: [Qemu-devel] [PATCH, DoS] slirp (arp): do not special-case bogus IP addresses
  2014-05-14  0:30             ` Edgar E. Iglesias
@ 2014-05-14  0:44               ` Samuel Thibault
  2014-05-14  0:54                 ` Edgar E. Iglesias
  0 siblings, 1 reply; 39+ messages in thread
From: Samuel Thibault @ 2014-05-14  0:44 UTC (permalink / raw)
  To: Edgar E. Iglesias; +Cc: qemu-devel

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

Edgar E. Iglesias, le Wed 14 May 2014 00:30:09 +0000, a écrit :
> > At best I could think of using the patch below, which avoids registering
> > anything for 0.0.0.0, and use a broadcast to answer a guest which
> > would have used 0.0.0.0 as a source for whatever reason.  I don't find
> > anything else reasonable.  What would be preferred?
> 
> Specs are not super clear on this but rfc1700 says that 0.0.0.0 is a source only address.

I agree.

> What I was trying to suggest was a mix between your two versions.
> Removing the assert in table_search and avoid adding 0.0.0.0/32 to the cache
> in table_add. We might need to complement with something that drops datagrams
> destined to 0.0.0.0 in upper layers so we dont keep trying, not sure.
> Does something like that make sense?

So that would be this.

Samuel


Do not special-case addresses with zero host part, as we do not
necessarily know how big it is, and the guest can fake them anyway.
Silently avoiding having 0.0.0.0 as a destination, however.

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

diff --git a/slirp/arp_table.c b/slirp/arp_table.c
index ecdb0ba..bcaeb44 100644
--- a/slirp/arp_table.c
+++ b/slirp/arp_table.c
@@ -37,12 +37,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
                 ethaddr[0], ethaddr[1], ethaddr[2],
                 ethaddr[3], ethaddr[4], ethaddr[5]));
 
-    /* Check 0.0.0.0/8 invalid source-only addresses */
-    if ((ip_addr & htonl(~(0xfU << 28))) == 0) {
-        return;
-    }
-
-    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
+    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
         /* Do not register broadcast addresses */
         return;
     }
@@ -73,9 +68,6 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
     DEBUG_CALL("arp_table_search");
     DEBUG_ARG("ip = 0x%x", ip_addr);
 
-    /* Check 0.0.0.0/8 invalid source-only addresses */
-    assert((ip_addr & htonl(~(0xfU << 28))) != 0);
-
     /* If broadcast address */
     if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
         /* return Ethernet broadcast address */
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 3fb48a4..2f189e0 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -778,6 +778,11 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
         return 1;
     }
 
+    if (!iph->ip_dst.s_addr) {
+        /* 0.0.0.0 can not be a source address, something went wrong, avoid
+         * making it worse */
+        return 1;
+    }
     if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
         uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
         struct ethhdr *reh = (struct ethhdr *)arp_req;

[-- Attachment #2: patch --]
[-- Type: text/plain, Size: 1647 bytes --]

diff --git a/slirp/arp_table.c b/slirp/arp_table.c
index ecdb0ba..bcaeb44 100644
--- a/slirp/arp_table.c
+++ b/slirp/arp_table.c
@@ -37,12 +37,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
                 ethaddr[0], ethaddr[1], ethaddr[2],
                 ethaddr[3], ethaddr[4], ethaddr[5]));
 
-    /* Check 0.0.0.0/8 invalid source-only addresses */
-    if ((ip_addr & htonl(~(0xfU << 28))) == 0) {
-        return;
-    }
-
-    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
+    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
         /* Do not register broadcast addresses */
         return;
     }
@@ -73,9 +68,6 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
     DEBUG_CALL("arp_table_search");
     DEBUG_ARG("ip = 0x%x", ip_addr);
 
-    /* Check 0.0.0.0/8 invalid source-only addresses */
-    assert((ip_addr & htonl(~(0xfU << 28))) != 0);
-
     /* If broadcast address */
     if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
         /* return Ethernet broadcast address */
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 3fb48a4..2f189e0 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -778,6 +778,11 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
         return 1;
     }
 
+    if (!iph->ip_dst.s_addr) {
+        /* 0.0.0.0 can not a a source address, something went wrong, avoid
+         * making it it worse */
+        return 1;
+    }
     if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
         uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
         struct ethhdr *reh = (struct ethhdr *)arp_req;

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

* Re: [Qemu-devel] [PATCH, DoS] slirp (arp): do not special-case bogus IP addresses
  2014-05-14  0:44               ` Samuel Thibault
@ 2014-05-14  0:54                 ` Edgar E. Iglesias
  2014-05-14  1:11                   ` Samuel Thibault
  0 siblings, 1 reply; 39+ messages in thread
From: Edgar E. Iglesias @ 2014-05-14  0:54 UTC (permalink / raw)
  To: Samuel Thibault; +Cc: qemu-devel

On Wed, May 14, 2014 at 02:44:20AM +0200, Samuel Thibault wrote:
> Edgar E. Iglesias, le Wed 14 May 2014 00:30:09 +0000, a écrit :
> > > At best I could think of using the patch below, which avoids registering
> > > anything for 0.0.0.0, and use a broadcast to answer a guest which
> > > would have used 0.0.0.0 as a source for whatever reason.  I don't find
> > > anything else reasonable.  What would be preferred?
> > 
> > Specs are not super clear on this but rfc1700 says that 0.0.0.0 is a source only address.
> 
> I agree.
> 
> > What I was trying to suggest was a mix between your two versions.
> > Removing the assert in table_search and avoid adding 0.0.0.0/32 to the cache
> > in table_add. We might need to complement with something that drops datagrams
> > destined to 0.0.0.0 in upper layers so we dont keep trying, not sure.
> > Does something like that make sense?
> 
> So that would be this.
> 
> Samuel


This looks good to me. Minor nit, the comment in if_encap should say
"0.0.0.0 can not be a destination address..."

Cheers,
Edgar

> 
> 
> Do not special-case addresses with zero host part, as we do not
> necessarily know how big it is, and the guest can fake them anyway.
> Silently avoiding having 0.0.0.0 as a destination, however.
> 
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
> ---
> 
> diff --git a/slirp/arp_table.c b/slirp/arp_table.c
> index ecdb0ba..bcaeb44 100644
> --- a/slirp/arp_table.c
> +++ b/slirp/arp_table.c
> @@ -37,12 +37,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
>                  ethaddr[0], ethaddr[1], ethaddr[2],
>                  ethaddr[3], ethaddr[4], ethaddr[5]));
>  
> -    /* Check 0.0.0.0/8 invalid source-only addresses */
> -    if ((ip_addr & htonl(~(0xfU << 28))) == 0) {
> -        return;
> -    }
> -
> -    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
> +    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>          /* Do not register broadcast addresses */
>          return;
>      }
> @@ -73,9 +68,6 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
>      DEBUG_CALL("arp_table_search");
>      DEBUG_ARG("ip = 0x%x", ip_addr);
>  
> -    /* Check 0.0.0.0/8 invalid source-only addresses */
> -    assert((ip_addr & htonl(~(0xfU << 28))) != 0);
> -
>      /* If broadcast address */
>      if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>          /* return Ethernet broadcast address */
> diff --git a/slirp/slirp.c b/slirp/slirp.c
> index 3fb48a4..2f189e0 100644
> --- a/slirp/slirp.c
> +++ b/slirp/slirp.c
> @@ -778,6 +778,11 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
>          return 1;
>      }
>  
> +    if (!iph->ip_dst.s_addr) {
> +        /* 0.0.0.0 can not be a source address, something went wrong, avoid
> +         * making it worse */
> +        return 1;
> +    }
>      if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
>          uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
>          struct ethhdr *reh = (struct ethhdr *)arp_req;

> diff --git a/slirp/arp_table.c b/slirp/arp_table.c
> index ecdb0ba..bcaeb44 100644
> --- a/slirp/arp_table.c
> +++ b/slirp/arp_table.c
> @@ -37,12 +37,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
>                  ethaddr[0], ethaddr[1], ethaddr[2],
>                  ethaddr[3], ethaddr[4], ethaddr[5]));
>  
> -    /* Check 0.0.0.0/8 invalid source-only addresses */
> -    if ((ip_addr & htonl(~(0xfU << 28))) == 0) {
> -        return;
> -    }
> -
> -    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
> +    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>          /* Do not register broadcast addresses */
>          return;
>      }
> @@ -73,9 +68,6 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
>      DEBUG_CALL("arp_table_search");
>      DEBUG_ARG("ip = 0x%x", ip_addr);
>  
> -    /* Check 0.0.0.0/8 invalid source-only addresses */
> -    assert((ip_addr & htonl(~(0xfU << 28))) != 0);
> -
>      /* If broadcast address */
>      if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>          /* return Ethernet broadcast address */
> diff --git a/slirp/slirp.c b/slirp/slirp.c
> index 3fb48a4..2f189e0 100644
> --- a/slirp/slirp.c
> +++ b/slirp/slirp.c
> @@ -778,6 +778,11 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
>          return 1;
>      }
>  
> +    if (!iph->ip_dst.s_addr) {
> +        /* 0.0.0.0 can not a a source address, something went wrong, avoid
> +         * making it it worse */
> +        return 1;
> +    }
>      if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
>          uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
>          struct ethhdr *reh = (struct ethhdr *)arp_req;

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

* Re: [Qemu-devel] [PATCH, DoS] slirp (arp): do not special-case bogus IP addresses
  2014-05-14  0:54                 ` Edgar E. Iglesias
@ 2014-05-14  1:11                   ` Samuel Thibault
  0 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-05-14  1:11 UTC (permalink / raw)
  To: Edgar E. Iglesias; +Cc: qemu-devel

Edgar E. Iglesias, le Wed 14 May 2014 00:54:50 +0000, a écrit :
> Minor nit, the comment in if_encap should say
> "0.0.0.0 can not be a destination address..."

D'oh :)

Samuel

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

* [Qemu-devel] [PATCHv2, DoS] slirp (arp): do not special-case bogus IP addresses
  2014-05-07 22:15   ` [Qemu-devel] [PATCH, DoS] slirp (arp): do not special-case bogus IP addresses Samuel Thibault
  2014-05-08  6:10     ` Edgar E. Iglesias
@ 2014-05-14  1:13     ` Samuel Thibault
  2014-05-14  1:22       ` Edgar E. Iglesias
  2014-06-09  0:01       ` Edgar E. Iglesias
  1 sibling, 2 replies; 39+ messages in thread
From: Samuel Thibault @ 2014-05-14  1:13 UTC (permalink / raw)
  To: qemu-devel

Do not special-case addresses with zero host part, as we do not
necessarily know how big it is, and the guest can fake them anyway.
Silently avoid having 0.0.0.0 as a destination, however.

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

This is particularly bad actually, one can for instance simply do this
inside a Linux guest

ip addr add 192.0.0.0/1 dev eth0

and crash qemu (thus a DoS) by just emitting a packet (thus from
192.0.0.0), getting:

qemu-system-x86_64: /usr/src/qemu/slirp/arp_table.c:77: arp_table_search: Assertion `(ip_addr & __bswap_32 (~(0xfU << 28))) != 0' failed.

so it should probably go to all stable maintained versions.

diff --git a/slirp/arp_table.c b/slirp/arp_table.c
index ecdb0ba..bcaeb44 100644
--- a/slirp/arp_table.c
+++ b/slirp/arp_table.c
@@ -37,12 +37,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
                 ethaddr[0], ethaddr[1], ethaddr[2],
                 ethaddr[3], ethaddr[4], ethaddr[5]));
 
-    /* Check 0.0.0.0/8 invalid source-only addresses */
-    if ((ip_addr & htonl(~(0xfU << 28))) == 0) {
-        return;
-    }
-
-    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
+    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
         /* Do not register broadcast addresses */
         return;
     }
@@ -73,9 +68,6 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
     DEBUG_CALL("arp_table_search");
     DEBUG_ARG("ip = 0x%x", ip_addr);
 
-    /* Check 0.0.0.0/8 invalid source-only addresses */
-    assert((ip_addr & htonl(~(0xfU << 28))) != 0);
-
     /* If broadcast address */
     if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
         /* return Ethernet broadcast address */
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 3fb48a4..00f4eb5 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -778,6 +778,11 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
         return 1;
     }
 
+    if (iph->ip_dst.s_addr == 0) {
+        /* 0.0.0.0 can not be a destination address, something went wrong,
+         * avoid making it worse */
+        return 1;
+    }
     if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
         uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
         struct ethhdr *reh = (struct ethhdr *)arp_req;

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

* Re: [Qemu-devel] [PATCHv2, DoS] slirp (arp): do not special-case bogus IP addresses
  2014-05-14  1:13     ` [Qemu-devel] [PATCHv2, " Samuel Thibault
@ 2014-05-14  1:22       ` Edgar E. Iglesias
       [not found]         ` <20140527231002.GB3396@toto>
  2014-06-09  0:01       ` Edgar E. Iglesias
  1 sibling, 1 reply; 39+ messages in thread
From: Edgar E. Iglesias @ 2014-05-14  1:22 UTC (permalink / raw)
  To: Samuel Thibault; +Cc: jan.kiszka, qemu-devel

On Wed, May 14, 2014 at 03:13:09AM +0200, Samuel Thibault wrote:
> Do not special-case addresses with zero host part, as we do not
> necessarily know how big it is, and the guest can fake them anyway.
> Silently avoid having 0.0.0.0 as a destination, however.
> 
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>

> ---
> 
> This is particularly bad actually, one can for instance simply do this
> inside a Linux guest
> 
> ip addr add 192.0.0.0/1 dev eth0
> 
> and crash qemu (thus a DoS) by just emitting a packet (thus from
> 192.0.0.0), getting:
> 
> qemu-system-x86_64: /usr/src/qemu/slirp/arp_table.c:77: arp_table_search: Assertion `(ip_addr & __bswap_32 (~(0xfU << 28))) != 0' failed.
> 
> so it should probably go to all stable maintained versions.
> 
> diff --git a/slirp/arp_table.c b/slirp/arp_table.c
> index ecdb0ba..bcaeb44 100644
> --- a/slirp/arp_table.c
> +++ b/slirp/arp_table.c
> @@ -37,12 +37,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
>                  ethaddr[0], ethaddr[1], ethaddr[2],
>                  ethaddr[3], ethaddr[4], ethaddr[5]));
>  
> -    /* Check 0.0.0.0/8 invalid source-only addresses */
> -    if ((ip_addr & htonl(~(0xfU << 28))) == 0) {
> -        return;
> -    }
> -
> -    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
> +    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>          /* Do not register broadcast addresses */
>          return;
>      }
> @@ -73,9 +68,6 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
>      DEBUG_CALL("arp_table_search");
>      DEBUG_ARG("ip = 0x%x", ip_addr);
>  
> -    /* Check 0.0.0.0/8 invalid source-only addresses */
> -    assert((ip_addr & htonl(~(0xfU << 28))) != 0);
> -
>      /* If broadcast address */
>      if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>          /* return Ethernet broadcast address */
> diff --git a/slirp/slirp.c b/slirp/slirp.c
> index 3fb48a4..00f4eb5 100644
> --- a/slirp/slirp.c
> +++ b/slirp/slirp.c
> @@ -778,6 +778,11 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
>          return 1;
>      }
>  
> +    if (iph->ip_dst.s_addr == 0) {
> +        /* 0.0.0.0 can not be a destination address, something went wrong,
> +         * avoid making it worse */
> +        return 1;
> +    }
>      if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
>          uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
>          struct ethhdr *reh = (struct ethhdr *)arp_req;
> 

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

* Re: [Qemu-devel] [PATCHv2, DoS] slirp (arp): do not special-case bogus IP addresses
  2014-05-14  1:13     ` [Qemu-devel] [PATCHv2, " Samuel Thibault
  2014-05-14  1:22       ` Edgar E. Iglesias
@ 2014-06-09  0:01       ` Edgar E. Iglesias
  1 sibling, 0 replies; 39+ messages in thread
From: Edgar E. Iglesias @ 2014-06-09  0:01 UTC (permalink / raw)
  To: Samuel Thibault; +Cc: qemu-devel

On Wed, May 14, 2014 at 03:13:09AM +0200, Samuel Thibault wrote:
> Do not special-case addresses with zero host part, as we do not
> necessarily know how big it is, and the guest can fake them anyway.
> Silently avoid having 0.0.0.0 as a destination, however.
> 
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

I've pushed this to master, thanks.

Edgar



> ---
> 
> This is particularly bad actually, one can for instance simply do this
> inside a Linux guest
> 
> ip addr add 192.0.0.0/1 dev eth0
> 
> and crash qemu (thus a DoS) by just emitting a packet (thus from
> 192.0.0.0), getting:
> 
> qemu-system-x86_64: /usr/src/qemu/slirp/arp_table.c:77: arp_table_search: Assertion `(ip_addr & __bswap_32 (~(0xfU << 28))) != 0' failed.
> 
> so it should probably go to all stable maintained versions.
> 
> diff --git a/slirp/arp_table.c b/slirp/arp_table.c
> index ecdb0ba..bcaeb44 100644
> --- a/slirp/arp_table.c
> +++ b/slirp/arp_table.c
> @@ -37,12 +37,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
>                  ethaddr[0], ethaddr[1], ethaddr[2],
>                  ethaddr[3], ethaddr[4], ethaddr[5]));
>  
> -    /* Check 0.0.0.0/8 invalid source-only addresses */
> -    if ((ip_addr & htonl(~(0xfU << 28))) == 0) {
> -        return;
> -    }
> -
> -    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
> +    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>          /* Do not register broadcast addresses */
>          return;
>      }
> @@ -73,9 +68,6 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
>      DEBUG_CALL("arp_table_search");
>      DEBUG_ARG("ip = 0x%x", ip_addr);
>  
> -    /* Check 0.0.0.0/8 invalid source-only addresses */
> -    assert((ip_addr & htonl(~(0xfU << 28))) != 0);
> -
>      /* If broadcast address */
>      if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>          /* return Ethernet broadcast address */
> diff --git a/slirp/slirp.c b/slirp/slirp.c
> index 3fb48a4..00f4eb5 100644
> --- a/slirp/slirp.c
> +++ b/slirp/slirp.c
> @@ -778,6 +778,11 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
>          return 1;
>      }
>  
> +    if (iph->ip_dst.s_addr == 0) {
> +        /* 0.0.0.0 can not be a destination address, something went wrong,
> +         * avoid making it worse */
> +        return 1;
> +    }
>      if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
>          uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
>          struct ethhdr *reh = (struct ethhdr *)arp_req;
> 

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

* Re: [Qemu-devel] [PATCHv2, DoS] slirp (arp): do not special-case bogus IP addresses
       [not found]         ` <20140527231002.GB3396@toto>
@ 2014-06-12  5:48           ` Jan Kiszka
  0 siblings, 0 replies; 39+ messages in thread
From: Jan Kiszka @ 2014-06-12  5:48 UTC (permalink / raw)
  To: Edgar E. Iglesias, Samuel Thibault; +Cc: qemu-devel

On 2014-05-28 01:10, Edgar E. Iglesias wrote:
> On Wed, May 14, 2014 at 01:22:25AM +0000, Edgar E. Iglesias wrote:
>> On Wed, May 14, 2014 at 03:13:09AM +0200, Samuel Thibault wrote:
>>> Do not special-case addresses with zero host part, as we do not
>>> necessarily know how big it is, and the guest can fake them anyway.
>>> Silently avoid having 0.0.0.0 as a destination, however.
>>>
>>> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
>>
>> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
> 
> Ping

Thanks for merging!

Jan

> 
> 
> 
>>
>>> ---
>>>
>>> This is particularly bad actually, one can for instance simply do this
>>> inside a Linux guest
>>>
>>> ip addr add 192.0.0.0/1 dev eth0
>>>
>>> and crash qemu (thus a DoS) by just emitting a packet (thus from
>>> 192.0.0.0), getting:
>>>
>>> qemu-system-x86_64: /usr/src/qemu/slirp/arp_table.c:77: arp_table_search: Assertion `(ip_addr & __bswap_32 (~(0xfU << 28))) != 0' failed.
>>>
>>> so it should probably go to all stable maintained versions.
>>>
>>> diff --git a/slirp/arp_table.c b/slirp/arp_table.c
>>> index ecdb0ba..bcaeb44 100644
>>> --- a/slirp/arp_table.c
>>> +++ b/slirp/arp_table.c
>>> @@ -37,12 +37,7 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t ethaddr[ETH_ALEN])
>>>                  ethaddr[0], ethaddr[1], ethaddr[2],
>>>                  ethaddr[3], ethaddr[4], ethaddr[5]));
>>>  
>>> -    /* Check 0.0.0.0/8 invalid source-only addresses */
>>> -    if ((ip_addr & htonl(~(0xfU << 28))) == 0) {
>>> -        return;
>>> -    }
>>> -
>>> -    if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>>> +    if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>>>          /* Do not register broadcast addresses */
>>>          return;
>>>      }
>>> @@ -73,9 +68,6 @@ bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
>>>      DEBUG_CALL("arp_table_search");
>>>      DEBUG_ARG("ip = 0x%x", ip_addr);
>>>  
>>> -    /* Check 0.0.0.0/8 invalid source-only addresses */
>>> -    assert((ip_addr & htonl(~(0xfU << 28))) != 0);
>>> -
>>>      /* If broadcast address */
>>>      if (ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
>>>          /* return Ethernet broadcast address */
>>> diff --git a/slirp/slirp.c b/slirp/slirp.c
>>> index 3fb48a4..00f4eb5 100644
>>> --- a/slirp/slirp.c
>>> +++ b/slirp/slirp.c
>>> @@ -778,6 +778,11 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
>>>          return 1;
>>>      }
>>>  
>>> +    if (iph->ip_dst.s_addr == 0) {
>>> +        /* 0.0.0.0 can not be a destination address, something went wrong,
>>> +         * avoid making it worse */
>>> +        return 1;
>>> +    }
>>>      if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
>>>          uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
>>>          struct ethhdr *reh = (struct ethhdr *)arp_req;
>>>

-- 
Siemens AG, Corporate Technology, CT RTC ITP SES-DE
Corporate Competence Center Embedded Linux

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

* Re: [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode
  2015-12-01 21:28 ` Thomas Huth
@ 2015-12-01 22:41   ` Samuel Thibault
  0 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2015-12-01 22:41 UTC (permalink / raw)
  To: Thomas Huth
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, peter.huangpeng, Gonglei (Arei),
	Stefan Hajnoczi, J. Kiszka, Yang Hongyang, Dave Gilbert

Thomas Huth, on Tue 01 Dec 2015 22:28:10 +0100, wrote:
> Are you still planning to rebase the patches again to current master and
> repost them, so we could maybe get this in for QEMU 2.6 ?

If we can get this reviewed, yes, sure!

> If you put me on CC:, I can try to review the series if you like (if I
> got the older mails right, this was the main problem in the past, that
> nobody reviewed?).

That was the issue, yes.

I can do that in the coming weeks.

Samuel

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

* Re: [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode
  2015-07-28 22:57 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
  2015-07-29  7:39 ` Jan Kiszka
@ 2015-12-01 21:28 ` Thomas Huth
  2015-12-01 22:41   ` Samuel Thibault
  1 sibling, 1 reply; 39+ messages in thread
From: Thomas Huth @ 2015-12-01 21:28 UTC (permalink / raw)
  To: Samuel Thibault, zhanghailiang
  Cc: Li Zhijian, Stefan Hajnoczi, Jason Wang, qemu-devel,
	Vasiliy Tolstov, peter.huangpeng, Gonglei (Arei),
	Stefan Hajnoczi, J. Kiszka, Yang Hongyang, Dave Gilbert


 Hi Samuel,

On 29/07/15 00:57, Samuel Thibault wrote:
> Samuel Thibault, le Wed 29 Jul 2015 00:13:57 +0200, a écrit :
> 
> This is another respin of IPv6 in Qemu -net user mode.
> 
> These patches add ICMPv6, NDP, and make UDP and TCP compatible with
> IPv6. We have made some refactoring to make current code compatible with
> IPv6.

FWIW, I've wanted to test IPv6 boot support in SLOF (the firmware of the
ppc64 pseries machine) today, so I've tried your patches and after
adapting the TFTP code in slirp to be able to deal with IPv6, too, I was
indeed able to load a file in the guest by using TFTP over IPv6. So
thank you, your patch series was very helpful for me today already!

Are you still planning to rebase the patches again to current master and
repost them, so we could maybe get this in for QEMU 2.6 ? If you put me
on CC:, I can try to review the series if you like (if I got the older
mails right, this was the main problem in the past, that nobody reviewed?).

 Cheers,
  Thomas

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

* Re: [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode
  2015-07-29  7:58     ` Jan Kiszka
@ 2015-07-29  9:45       ` Samuel Thibault
  0 siblings, 0 replies; 39+ messages in thread
From: Samuel Thibault @ 2015-07-29  9:45 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, peter.huangpeng, Gonglei (Arei),
	Stefan Hajnoczi, Yang Hongyang, Dave Gilbert

Jan Kiszka, le Wed 29 Jul 2015 09:58:36 +0200, a écrit :
> On 2015-07-29 09:47, Samuel Thibault wrote:
> > Ok. Two of the patches are however from a different author, I haven't
> > found how to specify different From addresses with git send-email.
> 
> This knowledge is buried in scripts here, but IIRC it should suffice
> having recorded authorship correctly in git.

Ok.

> >> Also, some are signed-off by you, others not. As a maintainer, you
> >> should sign all of them. Or is there a particular reason (not yet
> >> reviewed etc.)?
> > 
> > The reason was just that I hadn't touched those patches at all, but I
> > reviewed them all.
> 
> If you touch a patch and it's just trivial, add a simple changelog like
> 
> Signed-off-by: Author ....
> [Samuel: fix minor style issue etc.]
> Signed-off-by: You

Well, I have to say I really don't remember what I changed myself, since
that was more than 2 years ago already.  I'd have to go through the
whole git log to find the information.

> If you change the patch significantly, rather remove the authors
> signed-off and ask to provide it again for the modified version.

He had reviewed the changes, and was OK with them.

I have put the series on http://dept-info.labri.fr/~thibault/qemu-ipv6
in the tosubmit branch.

Samuel

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

* Re: [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode
  2015-07-29  7:47   ` Samuel Thibault
@ 2015-07-29  7:58     ` Jan Kiszka
  2015-07-29  9:45       ` Samuel Thibault
  0 siblings, 1 reply; 39+ messages in thread
From: Jan Kiszka @ 2015-07-29  7:58 UTC (permalink / raw)
  To: Samuel Thibault
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, peter.huangpeng, Gonglei (Arei),
	Stefan Hajnoczi, Yang Hongyang, Dave Gilbert

On 2015-07-29 09:47, Samuel Thibault wrote:
> Jan Kiszka, le Wed 29 Jul 2015 09:39:06 +0200, a écrit :
>> Make sure to add the proper From: of the actual author.
> 
> Ok. Two of the patches are however from a different author, I haven't
> found how to specify different From addresses with git send-email.

This knowledge is buried in scripts here, but IIRC it should suffice
having recorded authorship correctly in git.

> 
>> Also, some are signed-off by you, others not. As a maintainer, you
>> should sign all of them. Or is there a particular reason (not yet
>> reviewed etc.)?
> 
> The reason was just that I hadn't touched those patches at all, but I
> reviewed them all.

If you touch a patch and it's just trivial, add a simple changelog like

Signed-off-by: Author ....
[Samuel: fix minor style issue etc.]
Signed-off-by: You

If you change the patch significantly, rather remove the authors
signed-off and ask to provide it again for the modified version.

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SES-DE
Corporate Competence Center Embedded Linux

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

* Re: [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode
  2015-07-29  7:39 ` Jan Kiszka
@ 2015-07-29  7:47   ` Samuel Thibault
  2015-07-29  7:58     ` Jan Kiszka
  0 siblings, 1 reply; 39+ messages in thread
From: Samuel Thibault @ 2015-07-29  7:47 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: zhanghailiang, Li Zhijian, Stefan Hajnoczi, Jason Wang,
	qemu-devel, Vasiliy Tolstov, peter.huangpeng, Gonglei (Arei),
	Stefan Hajnoczi, Yang Hongyang, Dave Gilbert

Jan Kiszka, le Wed 29 Jul 2015 09:39:06 +0200, a écrit :
> Make sure to add the proper From: of the actual author.

Ok. Two of the patches are however from a different author, I haven't
found how to specify different From addresses with git send-email.

> Also, some are signed-off by you, others not. As a maintainer, you
> should sign all of them. Or is there a particular reason (not yet
> reviewed etc.)?

The reason was just that I hadn't touched those patches at all, but I
reviewed them all.

Samuel

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

* Re: [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode
  2015-07-28 22:57 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
@ 2015-07-29  7:39 ` Jan Kiszka
  2015-07-29  7:47   ` Samuel Thibault
  2015-12-01 21:28 ` Thomas Huth
  1 sibling, 1 reply; 39+ messages in thread
From: Jan Kiszka @ 2015-07-29  7:39 UTC (permalink / raw)
  To: Samuel Thibault, zhanghailiang
  Cc: Li Zhijian, Stefan Hajnoczi, Jason Wang, peter.huangpeng,
	Vasiliy Tolstov, qemu-devel, Gonglei (Arei),
	Stefan Hajnoczi, Yang Hongyang, Dave Gilbert

On 2015-07-29 00:57, Samuel Thibault wrote:
> Samuel Thibault, le Wed 29 Jul 2015 00:13:57 +0200, a écrit :
>> I can rebase the patch series over the current master and submit again
>> the patches.
> 
> Here it is:
> 
> 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. We have made some refactoring to make current code compatible with
> IPv6.
> 
> Patches 1 to 8 are refactoring of existing code and do not change the behavior,
> 9 adds a helper, and 10 to 18 add ipv6 support. Patches 3 and 16 are only
> reindents of the resulting code, without code change.
> 
> Difference with version 3 is:
> - fix address translation for incoming connection on port forwarding
> - incorporate fix 01f7cec for CVE-2014-3640.
> - reindentation has been moved into separate patches
> - inet6 support in sockaddr_equal has been moved to the ndp support patch
> - update first qemu version for the options
> 
> Here is a summary of the patches:
> 
> Refactoring patches:
> 
> [PATCH 01/18] slirp: goto bad in udp_input if sosendto fails
> [PATCH 02/18] slirp: Generalizing and neutralizing code before adding
> [PATCH 03/18] slirp: Reindent after refactoring
> [PATCH 04/18] slirp: Make Socket structure IPv6 compatible
> [PATCH 05/18] slirp: Factorizing address translation
> [PATCH 06/18] slirp: Factorizing and cleaning solookup()
> [PATCH 07/18] slirp: Make udp_attach IPv6 compatible
> [PATCH 08/18] slirp: Adding family argument to tcp_fconnect()
> 
> Adding helper:
> [PATCH 09/18] qemu/timer.h : Adding function to second scale
> 
> Adding v6 support:
> [PATCH 10/18] slirp: Adding IPv6, ICMPv6 Echo and NDP
> [PATCH 11/18] slirp: Adding ICMPv6 error sending
> [PATCH 12/18] slirp: Adding IPv6 UDP support
> [PATCH 13/18] slirp: Factorizing tcpiphdr structure with an union
> [PATCH 14/18] slirp: Generalizing and neutralizing various TCP
> [PATCH 15/18] slirp: Reindent after refactoring
> [PATCH 16/18] slirp: Handle IPv6 in TCP functions
> [PATCH 17/18] slirp: Adding IPv6 address for DNS relay
> [PATCH 18/18] qapi-schema, qemu-options & slirp: Adding Qemu options
> 

Make sure to add the proper From: of the actual author. Also, some are
signed-off by you, others not. As a maintainer, you should sign all of
them. Or is there a particular reason (not yet reviewed etc.)?

Jan

-- 
Siemens AG, Corporate Technology, CT RTC ITP SES-DE
Corporate Competence Center Embedded Linux

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

* [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode
@ 2015-07-28 22:57 Samuel Thibault
  2015-07-29  7:39 ` Jan Kiszka
  2015-12-01 21:28 ` Thomas Huth
  0 siblings, 2 replies; 39+ messages in thread
From: Samuel Thibault @ 2015-07-28 22:57 UTC (permalink / raw)
  To: zhanghailiang
  Cc: Li Zhijian, Stefan Hajnoczi, Jason Wang, qemu-devel,
	Vasiliy Tolstov, peter.huangpeng, Gonglei (Arei),
	Stefan Hajnoczi, J. Kiszka, Yang Hongyang, Dave Gilbert

Samuel Thibault, le Wed 29 Jul 2015 00:13:57 +0200, a écrit :
> I can rebase the patch series over the current master and submit again
> the patches.

Here it is:

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. We have made some refactoring to make current code compatible with
IPv6.

Patches 1 to 8 are refactoring of existing code and do not change the behavior,
9 adds a helper, and 10 to 18 add ipv6 support. Patches 3 and 16 are only
reindents of the resulting code, without code change.

Difference with version 3 is:
- fix address translation for incoming connection on port forwarding
- incorporate fix 01f7cec for CVE-2014-3640.
- reindentation has been moved into separate patches
- inet6 support in sockaddr_equal has been moved to the ndp support patch
- update first qemu version for the options

Here is a summary of the patches:

Refactoring patches:

[PATCH 01/18] slirp: goto bad in udp_input if sosendto fails
[PATCH 02/18] slirp: Generalizing and neutralizing code before adding
[PATCH 03/18] slirp: Reindent after refactoring
[PATCH 04/18] slirp: Make Socket structure IPv6 compatible
[PATCH 05/18] slirp: Factorizing address translation
[PATCH 06/18] slirp: Factorizing and cleaning solookup()
[PATCH 07/18] slirp: Make udp_attach IPv6 compatible
[PATCH 08/18] slirp: Adding family argument to tcp_fconnect()

Adding helper:
[PATCH 09/18] qemu/timer.h : Adding function to second scale

Adding v6 support:
[PATCH 10/18] slirp: Adding IPv6, ICMPv6 Echo and NDP
[PATCH 11/18] slirp: Adding ICMPv6 error sending
[PATCH 12/18] slirp: Adding IPv6 UDP support
[PATCH 13/18] slirp: Factorizing tcpiphdr structure with an union
[PATCH 14/18] slirp: Generalizing and neutralizing various TCP
[PATCH 15/18] slirp: Reindent after refactoring
[PATCH 16/18] slirp: Handle IPv6 in TCP functions
[PATCH 17/18] slirp: Adding IPv6 address for DNS relay
[PATCH 18/18] qapi-schema, qemu-options & slirp: Adding Qemu options

Samuel

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

end of thread, other threads:[~2015-12-01 22:41 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-30 22:22 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
2014-03-30 22:22 ` [Qemu-devel] [PATCH 01/18] slirp: goto bad in udp_input if sosendto fails Samuel Thibault
2014-05-07 22:15   ` [Qemu-devel] [PATCH, DoS] slirp (arp): do not special-case bogus IP addresses Samuel Thibault
2014-05-08  6:10     ` Edgar E. Iglesias
2014-05-08  6:50       ` Samuel Thibault
2014-05-08  6:59         ` Edgar E. Iglesias
2014-05-13 22:15           ` Samuel Thibault
2014-05-14  0:30             ` Edgar E. Iglesias
2014-05-14  0:44               ` Samuel Thibault
2014-05-14  0:54                 ` Edgar E. Iglesias
2014-05-14  1:11                   ` Samuel Thibault
2014-05-14  1:13     ` [Qemu-devel] [PATCHv2, " Samuel Thibault
2014-05-14  1:22       ` Edgar E. Iglesias
     [not found]         ` <20140527231002.GB3396@toto>
2014-06-12  5:48           ` Jan Kiszka
2014-06-09  0:01       ` Edgar E. Iglesias
2014-03-30 22:22 ` [Qemu-devel] [PATCH 02/18] slirp: Generalizing and neutralizing code before adding IPv6 stuff Samuel Thibault
2014-03-30 22:22 ` [Qemu-devel] [PATCH 03/18] slirp: Reindent after refactoring Samuel Thibault
2014-03-30 22:22 ` [Qemu-devel] [PATCH 04/18] slirp: Make Socket structure IPv6 compatible Samuel Thibault
2014-03-30 22:22 ` [Qemu-devel] [PATCH 05/18] slirp: Factorizing address translation Samuel Thibault
2014-03-30 22:22 ` [Qemu-devel] [PATCH 06/18] slirp: Factorizing and cleaning solookup() Samuel Thibault
2014-03-30 22:22 ` [Qemu-devel] [PATCH 07/18] slirp: Make udp_attach IPv6 compatible Samuel Thibault
2014-03-30 22:22 ` [Qemu-devel] [PATCH 08/18] slirp: Adding family argument to tcp_fconnect() Samuel Thibault
2014-03-30 22:23 ` [Qemu-devel] [PATCH 09/18] qemu/timer.h : Adding function to second scale Samuel Thibault
2014-03-30 22:23 ` [Qemu-devel] [PATCH 10/18] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration Samuel Thibault
2014-03-30 22:23 ` [Qemu-devel] [PATCH 11/18] slirp: Adding ICMPv6 error sending Samuel Thibault
2014-03-30 22:23 ` [Qemu-devel] [PATCH 12/18] slirp: Adding IPv6 UDP support Samuel Thibault
2014-03-30 22:23 ` [Qemu-devel] [PATCH 13/18] slirp: Factorizing tcpiphdr structure with an union Samuel Thibault
2014-03-30 22:23 ` [Qemu-devel] [PATCH 14/18] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff Samuel Thibault
2014-03-30 22:23 ` [Qemu-devel] [PATCH 15/18] slirp: Reindent after refactoring Samuel Thibault
2014-03-30 22:23 ` [Qemu-devel] [PATCH 16/18] slirp: Handle IPv6 in TCP functions Samuel Thibault
2014-03-30 22:23 ` [Qemu-devel] [PATCH 17/18] slirp: Adding IPv6 address for DNS relay Samuel Thibault
2014-03-30 22:23 ` [Qemu-devel] [PATCH 18/18] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses Samuel Thibault
2015-07-28 22:57 [Qemu-devel] [PATCHv4 00/18] slirp: Adding IPv6 support to Qemu -net user mode Samuel Thibault
2015-07-29  7:39 ` Jan Kiszka
2015-07-29  7:47   ` Samuel Thibault
2015-07-29  7:58     ` Jan Kiszka
2015-07-29  9:45       ` Samuel Thibault
2015-12-01 21:28 ` Thomas Huth
2015-12-01 22:41   ` Samuel Thibault

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.