Skip to contentSkip to conversation

slirp: Adding IPv6 support to Qemu -net user mode

PATCH Superseded Samuel Thibault 7 participants 78 messages Oct 20, 2013 – Jul 11, 2014 1 message not in the archive Networking

v1 of 4 Superseded Latest is v4 →

lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

#1 lore raw

cover slirp: Adding IPv6 support to Qemu -net user mode

We have developed 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.

Some patches, like 2 and 13, can be reviewed using "interdiff -w /dev/null patchfile"
to get rid of the indentation.

[PATCH 01/16] slirp: goto bad in udp_input if sosendto fails [PATCH 02/16] slirp: Generalizing and neutralizing code before adding [PATCH 03/16] qemu/timer.h : Adding function to second scale [PATCH 04/16] slirp: Adding IPv6, ICMPv6 Echo and NDP [PATCH 05/16] slirp: Adding ICMPv6 error sending
[PATCH 06/16] slirp: Make Socket structure IPv6 compatible [PATCH 07/16] slirp: Factorizing address translation [PATCH 08/16] slirp: Factorizing and cleaning solookup() [PATCH 09/16] slirp: Make udp_attach IPv6 compatible [PATCH 10/16] slirp: Adding IPv6 UDP support
[PATCH 11/16] slirp: Adding family argument to tcp_fconnect() [PATCH 12/16] slirp: Factorizing tcpiphdr structure with an union [PATCH 13/16] slirp: Generalizing and neutralizing various TCP [PATCH 14/16] slirp: Handle IPv6 in TCP functions
[PATCH 15/16] slirp: Adding IPv6 address for DNS relay [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options

#2 lore raw

PATCH 1/16 slirp: goto bad in udp_input if sosendto fails

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.

---
 slirp/udp.c | 1 +
 1 file changed, 1 insertion(+)
slirp/udp.c +1 -0
index 8cc6cb6..fd2446a 100644
@@ -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 */
Signature · 1 line
1.8.4.rc3
#3 lore raw

PATCH 2/16 slirp: Generalizing and neutralizing code before adding IPv6 stuff

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

---
 slirp/if.c    |   2 +-
 slirp/mbuf.c  |   2 +-
 slirp/mbuf.h  |   2 +-
 slirp/slirp.c | 107 ++++++++++++++++++++++++++++++++++------------------------
 slirp/slirp.h |  12 +++----
 5 files changed, 71 insertions(+), 54 deletions(-)
slirp/if.c +1 -1
index 87ca8a5..c138ff4 100644
@@ -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;
         }
 
slirp/mbuf.c +1 -1
index 4fefb04..92c429e 100644
@@ -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);
slirp/mbuf.h +1 -1
index b144f1c..38fedf4 100644
@@ -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 {
slirp/slirp.c +62 -45

115 lines not on this page · raw message

slirp/slirp.h +6 -6
index e4a1bd4..cd9f2d0 100644
@@ -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   */
 
Signature · 1 line
1.8.4.rc3
#4 lore raw

PATCH 3/16 qemu/timer.h : Adding function to second scale

In reply to Samuel Thibault

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

---
 include/qemu/timer.h | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
include/qemu/timer.h +32 -0
index b58903b..f71553d 100644
@@ -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
  *
@@ -508,6 +523,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
  *
Signature · 1 line
1.8.4.rc3
#5 lore raw

PATCH 4/16 slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration

In reply to Samuel Thibault

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.

---
 slirp/Makefile.objs |   4 +-
 slirp/cksum.c       |  23 ++++
 slirp/ip6.h         | 139 +++++++++++++++++++++
 slirp/ip6_icmp.c    | 350 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 slirp/ip6_icmp.h    | 247 ++++++++++++++++++++++++++++++++++++
 slirp/ip6_input.c   |  75 +++++++++++
 slirp/ip6_output.c  |  41 ++++++
 slirp/ndp_table.c   |  87 +++++++++++++
 slirp/slirp.c       |  47 +++++--
 slirp/slirp.h       |  33 +++++
 10 files changed, 1036 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
slirp/Makefile.objs +2 -2
index 2daa9dc..2dfe8e0 100644
@@ -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
slirp/cksum.c +23 -0
index 6328660..f0a1398 100644
@@ -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;
+}
slirp/ip6.h new file +139 -0

139 lines not on this page · raw message

slirp/ip6_icmp.c new file +350 -0

350 lines not on this page · raw message

slirp/ip6_icmp.h new file +247 -0

247 lines not on this page · raw message

slirp/ip6_input.c new file +75 -0

75 lines not on this page · raw message

slirp/ip6_output.c new file +41 -0

41 lines not on this page · raw message

slirp/ndp_table.c new file +87 -0

87 lines not on this page · raw message

slirp/slirp.c +39 -8

95 lines not on this page · raw message

slirp/slirp.h +33 -0
index cd9f2d0..0d1e14d 100644
@@ -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,7 @@ struct Slirp {
     struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
 
     ArpTable arp_table;
+    NdpTable ndp_table;
 
     void *opaque;
 };
@@ -303,6 +327,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 +343,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);
Signature · 1 line
1.8.4.rc3
#6 lore raw

Re: [Qemu-devel] [PATCH 04/16] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration

Il 20/10/2013 15:56, Samuel Thibault ha scritto:

Quoted 6 lines
slirp/ip6_icmp.c new file +6 -0
+#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/ip6_icmp.c line 32

Quoted 10 lines
slirp/ip6_icmp.c new file +10 -0
+    timer_mod(ra_timer, qemu_clock_get_s(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
+    ndp_send_ra((Slirp *)opaque);
+}
+
+void icmp6_init(Slirp *slirp)
+{
+    srand(time(NULL));
+    ra_timer = timer_new_s(QEMU_CLOCK_VIRTUAL, ra_timer_handler, slirp);
+    timer_mod(ra_timer, qemu_clock_get_s(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
+}

Should the granularity of the timer really be seconds? Or should you use the existing milli/nanosecond interface and scale the interval, so that you really get a uniformly distributed random value, even for very small MaxRtrAdvInterval (e.g. for min=3, max=4 you won't get any other value than 3 or 4, which is not really uniformly distributed).

Paolo

#7 lore raw

Re: [Qemu-devel] [PATCH 04/16] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration

Quoted 4 lines · Paolo Bonzini, le Wed 23 Oct 2013 08:51:21 +0100, a écrit :
Quoted 4 lines
slirp/ip6_icmp.c new file +4 -0
+void icmp6_init(Slirp *slirp)
+{
+    srand(time(NULL));
+    ra_timer = timer_new_s(QEMU_CLOCK_VIRTUAL, ra_timer_handler, slirp);
Quoted 8 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+    timer_mod(ra_timer, qemu_clock_get_s(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
+}

Should the granularity of the timer really be seconds? Or should you use the existing milli/nanosecond interface and scale the interval, so that you really get a uniformly distributed random value, even for very small MaxRtrAdvInterval (e.g. for min=3, max=4 you won't get any other value than 3 or 4, which is not really uniformly distributed).

I don't think we need to care about fine granularity. We are not going to run more than one RA anyway.

Actually, the RFC itself says that when the max value is less than 9, the default for the min value would be equal to the max value, i.e. the delay being always just the same.

Samuel

#8 lore raw

PATCH 5/16 slirp: Adding ICMPv6 error sending

In reply to Samuel Thibault

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.

---
 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(-)
slirp/ip6_icmp.c +60 -0
index 32de0ba..706e430 100644
@@ -65,6 +65,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
  */
slirp/ip6_icmp.h +10 -0
index 2b21c84..7779964 100644
@@ -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
@@ -241,6 +250,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);
 
slirp/ip6_input.c +9 -7
index 9663c42..af098a5 100644
@@ -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;
slirp/ip_icmp.c +6 -6
index 9f1cb08..1808976 100644
@@ -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);
     }
 
@@ -197,7 +197,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 */
@@ -243,7 +243,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;
@@ -251,7 +251,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);
 
@@ -441,7 +441,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! */
slirp/ip_icmp.h +2 -2
index be4426b..846761d 100644
@@ -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);
slirp/ip_input.c +4 -4
index 880bdfd..1925cdc 100644
@@ -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);
 }
slirp/socket.c +2 -2
index 37ac5cf..e87c70e 100644
@@ -459,7 +459,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! */
@@ -507,7 +507,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 {
 	  /*
slirp/tcp_input.c +1 -1
index f946db8..ba31461 100644
@@ -601,7 +601,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);
slirp/udp.c +2 -1
index fd2446a..2bead1c 100644
@@ -217,7 +217,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;
 	}
 
Signature · 1 line
1.8.4.rc3
#9 lore raw

PATCH 6/16 slirp: Make Socket structure IPv6 compatible

In reply to Samuel Thibault

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.

---
 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(-)
slirp/ip_icmp.c +2 -0
index 1808976..768ea4a 100644
@@ -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;
slirp/slirp.c +40 -8

60 lines not on this page · raw message

slirp/socket.c +11 -3
index e87c70e..2f166fb 100644
@@ -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;
slirp/socket.h +21 -4
index 57e0407..07f116d 100644
@@ -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? */
slirp/tcp_input.c +2 -0
index ba31461..70ef376 100644
@@ -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;
 
slirp/tcp_subr.c +2 -0
index 7571c5a..f15da70 100644
@@ -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 */
slirp/udp.c +4 -0
index 2bead1c..a3dc3e7 100644
@@ -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 */
 
@@ -377,6 +379,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) {
@@ -384,6 +387,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)
Signature · 1 line
1.8.4.rc3
#10 lore raw

PATCH 7/16 slirp: Factorizing address translation

In reply to Samuel Thibault

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.

---
 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(-)
slirp/bootp.c +1 -1
index b7db9fa..03e2e42 100644
@@ -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)
slirp/ip_icmp.c +4 -15
index 768ea4a..8787aae 100644
@@ -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",
slirp/socket.c +73 -20

126 lines not on this page · raw message

slirp/socket.h +3 -0
index 07f116d..50059be 100644
@@ -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_ */
slirp/tcp_subr.c +5 -19
index f15da70..4791c0c 100644
@@ -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));
 
slirp/tftp.c +3 -3
index 1a79c45..dee201b 100644
@@ -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);
slirp/udp.c +1 -26
index a3dc3e7..bab1c60 100644
@@ -237,7 +237,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)
 {
@@ -288,31 +288,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)
 {
slirp/udp.h +1 -2
index 9bf31fe..a04b8ce 100644
@@ -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
Signature · 1 line
1.8.4.rc3
#11 lore raw

PATCH 8/16 slirp: Factorizing and cleaning solookup()

In reply to Samuel Thibault

This patch makes solookup() compatible with all address family. 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.

---
 slirp/socket.c    | 30 ++++++++++++++++--------------
 slirp/socket.h    | 30 +++++++++++++++++++++++++++++-
 slirp/tcp_input.c | 27 +++++++++++----------------
 slirp/udp.c       | 25 ++++++-------------------
 4 files changed, 62 insertions(+), 50 deletions(-)
slirp/socket.c +16 -14
index 375281c..f333fcf 100644
@@ -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;
 }
 
 /*
slirp/socket.h +29 -1
index 50059be..ad509b9 100644
@@ -93,7 +93,35 @@ 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);
+        }
+        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:
+            return 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 *);
slirp/tcp_input.c +11 -16
index 70ef376..f7a8d49 100644
@@ -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;
slirp/udp.c +6 -19
index bab1c60..7e0f1b2 100644
@@ -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) {
 	  /*
Signature · 1 line
1.8.4.rc3
#12 lore raw

PATCH 9/16 slirp: Make udp_attach IPv6 compatible

In reply to Samuel Thibault

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

---
 slirp/ip_icmp.c | 2 +-
 slirp/udp.c     | 7 ++++---
 slirp/udp.h     | 2 +-
 3 files changed, 6 insertions(+), 5 deletions(-)
slirp/ip_icmp.c +1 -1
index 8787aae..c896574 100644
@@ -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);
slirp/udp.c +4 -3
index 7e0f1b2..f53ee11 100644
@@ -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);
@@ -276,9 +276,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);
   }
slirp/udp.h +1 -1
index a04b8ce..15e73c1 100644
@@ -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);
Signature · 1 line
1.8.4.rc3
#13 lore raw

PATCH 10/16 slirp: Adding IPv6 UDP support

In reply to Samuel Thibault

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

---
 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
slirp/Makefile.objs +1 -1
index 2dfe8e0..faa32b6 100644
@@ -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
slirp/ip6_input.c +1 -2
index af098a5..3290af8 100644
@@ -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);
slirp/socket.c +6 -1
index f333fcf..31bbb7e 100644
@@ -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 */
slirp/udp.h +5 -0
index 15e73c1..8a4d9f5 100644
@@ -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
slirp/udp6.c new file +149 -0

149 lines not on this page · raw message

Signature · 1 line
1.8.4.rc3
#14 lore raw

PATCH 11/16 slirp: Adding family argument to tcp_fconnect()

In reply to Samuel Thibault

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

---
 slirp/slirp.h     | 2 +-
 slirp/tcp_input.c | 3 ++-
 slirp/tcp_subr.c  | 5 +++--
 3 files changed, 6 insertions(+), 4 deletions(-)
slirp/slirp.h +1 -1
index 0d1e14d..aa44055 100644
@@ -367,7 +367,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 *);
slirp/tcp_input.c +2 -1
index f7a8d49..25929bd 100644
@@ -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)));
slirp/tcp_subr.c +3 -2
index 4791c0c..3558115 100644
@@ -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;
 
Signature · 1 line
1.8.4.rc3
#15 lore raw

PATCH 12/16 slirp: Factorizing tcpiphdr structure with an union

In reply to Samuel Thibault

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)

---
 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(-)
slirp/if.h +2 -2
index 3327023..c7a5c57 100644
@@ -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
slirp/mbuf.c +2 -1
index 92c429e..87ee550 100644
@@ -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)
slirp/slirp.c +8 -7
index 2caddcd..d0b8c79 100644
@@ -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);
slirp/socket.c +12 -1
index 31bbb7e..567f9bc 100644
@@ -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,
slirp/tcp_input.c +20 -11
index 25929bd..dde89b6 100644
@@ -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);
slirp/tcp_output.c +13 -5
index 8aa3d90..4726f00 100644
@@ -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);
slirp/tcp_subr.c +22 -9
index 3558115..b052947 100644
@@ -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);
 }
slirp/tcpip.h +23 -8
index 7974ce3..d9b5d70 100644
@@ -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
Signature · 1 line
1.8.4.rc3
#16 lore raw

PATCH 13/16 slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff

In reply to Samuel Thibault

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.

---
 slirp/ip_input.c   |   2 +-
 slirp/slirp.c      |   6 ++-
 slirp/slirp.h      |   5 +-
 slirp/tcp_input.c  | 142 +++++++++++++++++++++++++++++++++--------------------
 slirp/tcp_output.c |  43 +++++++++-------
 slirp/tcp_subr.c   |  94 +++++++++++++++++++++--------------
 slirp/tcp_timer.c  |   3 +-
 7 files changed, 181 insertions(+), 114 deletions(-)
slirp/ip_input.c +1 -1
index 1925cdc..9aa8909 100644
@@ -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);
slirp/slirp.c +4 -2
index d0b8c79..0f6f006 100644
@@ -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
             }
slirp/slirp.h +3 -2
index aa44055..b6e805e 100644
@@ -352,7 +352,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 */
@@ -363,7 +363,8 @@ void tcp_setpersist(register struct tcpcb *);
 void tcp_init(Slirp *);
 void tcp_cleanup(Slirp *);
 void tcp_template(struct tcpcb *);
-void tcp_respond(struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int);
+void tcp_respond(struct tcpcb *, register struct tcpiphdr *,
+        register struct mbuf *, tcp_seq, tcp_seq, int, sa_family_t);
 struct tcpcb * tcp_newtcpcb(struct socket *);
 struct tcpcb * tcp_close(register struct tcpcb *);
 void tcp_sockclosed(struct tcpcb *);
slirp/tcp_input.c +90 -52

203 lines not on this page · raw message

slirp/tcp_output.c +25 -18

55 lines not on this page · raw message

slirp/tcp_subr.c +56 -38

138 lines not on this page · raw message

slirp/tcp_timer.c +2 -1
index 6c5bb11..42c6e7e 100644
@@ -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;
Signature · 1 line
1.8.4.rc3
#17 lore raw

PATCH 14/16 slirp: Handle IPv6 in TCP functions

In reply to Samuel Thibault

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

---
 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(-)
slirp/ip6_input.c +2 -2
index 3290af8..b03b795 100644
@@ -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);
slirp/tcp.h +2 -0
index 2e2b403..61befcd 100644
@@ -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 */
slirp/tcp_input.c +44 -14

113 lines not on this page · raw message

slirp/tcp_output.c +16 -0
index ce0d0e6..64742a2 100644
@@ -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;
 	}
slirp/tcp_subr.c +32 -4
index ba4eb80..6c087e3 100644
@@ -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;
slirp/tcpip.h +9 -0
index d9b5d70..4a2987f 100644
@@ -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
Signature · 1 line
1.8.4.rc3
#18 lore raw

PATCH 15/16 slirp: Adding IPv6 address for DNS relay

In reply to Samuel Thibault

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.

---
 slirp/ip6.h    |  5 ++++-
 slirp/slirp.c  |  2 ++
 slirp/slirp.h  |  1 +
 slirp/socket.c | 26 ++++++++++++++++++++++++--
 4 files changed, 31 insertions(+), 3 deletions(-)
slirp/ip6.h +4 -1
index 16124ec..b88456d 100644
@@ -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))
slirp/slirp.c +2 -0
index 0f6f006..695e8a6 100644
@@ -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, "fc00::2", &slirp->vnameserver_addr6);
 
     if (vdnssearch) {
         translate_dnssearch(slirp, vdnssearch);
slirp/slirp.h +1 -0
index b6e805e..0688ea7 100644
@@ -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];
slirp/socket.c +24 -2
index 567f9bc..a9b3957 100644
@@ -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;
     }
Signature · 1 line
1.8.4.rc3
#19 lore raw

PATCH 16/16 qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

In reply to Samuel Thibault

This patchs 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 fc00::1, fc00::, /64 and fc00::2.

---
 net/slirp.c      | 56 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 qapi-schema.json | 37 +++++++++++++++++++++++--------------
 qemu-options.hx  |  5 +++--
 slirp/libslirp.h |  8 +++++---
 slirp/slirp.c    | 20 +++++++++-----------
 5 files changed, 88 insertions(+), 38 deletions(-)
net/slirp.c +48 -8
index 124e953..68f4aa9 100644
@@ -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, 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 */
+    /* default settings according to historic slirp and updated for IPv6 */
     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;
+    uint8_t ip6_prefix_len = 64;
+    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
@@ -156,6 +162,11 @@ static int net_slirp_init(NetClientState *peer, const char *model,
     char *end;
     struct slirp_config_str *config;
 
+    /* IPv6 defaults initialisations */
+    inet_pton(AF_INET6, "fc00::0", &ip6_prefix);
+    inet_pton(AF_INET6, "fc00::1", &ip6_host);
+    inet_pton(AF_INET6, "fc00::2", &ip6_dns);
+
     if (!tftp_export) {
         tftp_export = legacy_tftp_prefix;
     }
@@ -228,6 +239,32 @@ static int net_slirp_init(NetClientState *peer, const char *model,
         return -1;
     }
 
+    if (vprefix6) {
+        if (get_str_sep(buf, sizeof(buf), &vprefix6, '/') < 0) {
+            if (!inet_pton(AF_INET6, vprefix6, &ip6_prefix)) {
+                return -1;
+            }
+        } else {
+            if (!inet_pton(AF_INET6, buf, &ip6_prefix)) {
+                return -1;
+            }
+            shift = strtol(vprefix6, &end, 10);
+            if (*end != '\0' || (shift > 0 && shift < 129)) {
+                ip6_prefix_len = shift;
+            } else {
+                return -1;
+            }
+        }
+    }
+
+    if (vhost6 && !inet_pton(AF_INET6, vhost6, &ip6_host)) {
+        return -1;
+    }
+
+    if (vnameserver6 && !inet_pton(AF_INET6, vnameserver6, &ip6_dns)) {
+        return -1;
+    }
+
 #ifndef _WIN32
     if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
         return -1;
@@ -242,8 +279,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, ip6_prefix_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,9 +789,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->smbserver, dnssearch);
+                         user->host, user->ip6_prefix, user->ip6_host,
+                         user->hostname, user->tftp, user->bootfile,
+                         user->dhcpstart, user->dns, user->ip6_dns,
+                         user->smb, user->smbserver, dnssearch);
 
     while (slirp_configs) {
         config = slirp_configs;
qapi-schema.json +23 -14
index 60f3fd1..16a34c5 100644
@@ -2807,6 +2807,12 @@
 # @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
 #             to the guest
 #
+# @ip6_prefix: #optional IPv6 network prefix
+#
+# @ip6_host: guest-visible IPv6 address of the host
+#
+# @ip6_dns: guest-visible IPv6 address of the virtual nameserver
+#
 # @smb: #optional root directory of the built-in SMB server
 #
 # @smbserver: #optional IP address of the built-in SMB server
@@ -2820,20 +2826,23 @@
 ##
 { '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_host':        'str',
+    '*ip6_dns':         'str',
+    '*smb':             'str',
+    '*smbserver':       'str',
+    '*hostfwd':         ['String'],
+    '*guestfwd':        ['String'] } }
 
 ##
 # @NetdevTapOptions
qemu-options.hx +3 -2
index 5dc8b75..eb3a19f 100644
@@ -1357,8 +1357,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_prefix=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"
slirp/libslirp.h +5 -3
index 5bdcbd5..c4b25c9 100644
@@ -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);
 
slirp/slirp.c +9 -11
index 695e8a6..48e39f2 100644
@@ -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, "fc00::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, "fc00::1", &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, "fc00::2", &slirp->vnameserver_addr6);
+    slirp->vnameserver_addr6 = vnameserver6;
 
     if (vdnssearch) {
         translate_dnssearch(slirp, vdnssearch);
Signature · 1 line
1.8.4.rc3
#20 lore raw

Re: [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Quoted 8 lines · Samuel Thibault

This patchs 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 fc00::1, fc00::, /64 and fc00::2.

---

Just focusing on interface for now...

qapi-schema.json line 2810

Quoted 6 lines

+++ b/qapi-schema.json

qapi-schema.json +1 -0
@@ -2807,6 +2807,12 @@
 # @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
 #             to the guest
 #
+# @ip6_prefix: #optional IPv6 network prefix

Please mention '(since 1.8)' for each new field. Also, this command doesn't have any '_', so your new field names should be named with '-', as in @ip6-prefix

qapi-schema.json line 2828

Quoted 12 lines
qapi-schema.json +6 -0
+#
+# @ip6_host: guest-visible IPv6 address of the host
+#
+# @ip6_dns: guest-visible IPv6 address of the virtual nameserver
+#
 # @smb: #optional root directory of the built-in SMB server
 #
 # @smbserver: #optional IP address of the built-in SMB server
@@ -2820,20 +2826,23 @@
 ##
 
+    '*ip6_prefix':      'str',

Why is this a str instead of an integer?

qapi-schema.json line 2841

Quoted 2 lines
qapi-schema.json +2 -0
+    '*ip6_host':        'str',
+    '*ip6_dns':         'str',

These look okay (other than the - vs _ issue)

Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
#21 lore raw

Re: [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Hello,

Quoted 3 lines · Eric Blake, le Mon 21 Oct 2013 22:04:23 +0100, a écrit :
Quoted 1 line

+ '*ip6_prefix': 'str',

Why is this a str instead of an integer?

prefix would be e.g. fc00::1/64.

Samuel

#22 lore raw

Re: [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Quoted 8 lines · Samuel Thibault

Hello,

Quoted 3 lines · Eric Blake, le Mon 21 Oct 2013 22:04:23 +0100, a écrit :
Quoted 1 line

+ '*ip6_prefix': 'str',

Why is this a str instead of an integer?

prefix would be e.g. fc00::1/64.

That requires me to post-parse it. Would it be smarter to represent this as two elements, one for the "fc00::1" string, and another for the 64 width, so that I don't have to post-parse?

Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
#23 lore raw

Re: [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Hello,

Quoted 11 lines · Eric Blake, le Tue 22 Oct 2013 11:27:27 +0100, a écrit :
Quoted 6 lines · Samuel Thibault
Quoted 3 lines · Eric Blake, le Mon 21 Oct 2013 22:04:23 +0100, a écrit :
Quoted 1 line

+ '*ip6_prefix': 'str',

Why is this a str instead of an integer?

prefix would be e.g. fc00::1/64.

That requires me to post-parse it. Would it be smarter to represent this as two elements, one for the "fc00::1" string, and another for the 64 width, so that I don't have to post-parse?

It makes sense, yes, the syntax would be [ip6-prefix=net[/netsize]] . I just don't know how to express that in qapi :)

Samuel

#24 lore raw

Re: [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Quoted 9 lines · Samuel Thibault

Hello,

Quoted 6 lines · Eric Blake, le Tue 22 Oct 2013 11:27:27 +0100, a écrit :
Quoted 5 lines · Samuel Thibault
Quoted 3 lines · Eric Blake, le Mon 21 Oct 2013 22:04:23 +0100, a écrit :
Quoted 1 line

+ '*ip6_prefix': 'str',

Why is this a str instead of an integer?

Quoted 8 lines
Quoted 5 lines
Quoted 1 line

prefix would be e.g. fc00::1/64.

That requires me to post-parse it. Would it be smarter to represent this as two elements, one for the "fc00::1" string, and another for the 64 width, so that I don't have to post-parse?

It makes sense, yes, the syntax would be [ip6-prefix=net[/netsize]] . I just don't know how to express that in qapi :)

'*ip6_net':'str', '*ip6_netsize':'int'

passed on the wire as:

"ip6_net":"fc00::1", "ip6_netsize":64

Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
#25 lore raw

Re: [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Quoted 16 lines · Eric Blake, le Tue 22 Oct 2013 11:33:52 +0100, a écrit :
Quoted 15 lines · Samuel Thibault

Hello,

Quoted 11 lines · Eric Blake, le Tue 22 Oct 2013 11:27:27 +0100, a écrit :
Quoted 6 lines · Samuel Thibault
Quoted 3 lines · Eric Blake, le Mon 21 Oct 2013 22:04:23 +0100, a écrit :
Quoted 1 line

+ '*ip6_prefix': 'str',

Why is this a str instead of an integer?

prefix would be e.g. fc00::1/64.

That requires me to post-parse it. Would it be smarter to represent this as two elements, one for the "fc00::1" string, and another for the 64 width, so that I don't have to post-parse?

Quoted 8 lines
Quoted 2 lines

It makes sense, yes, the syntax would be [ip6-prefix=net[/netsize]] . I just don't know how to express that in qapi :)

'*ip6_net':'str', '*ip6_netsize':'int'

passed on the wire as:

"ip6_net":"fc00::1", "ip6_netsize":64

Err, so that means that the user would have to pass "ip6-net=fc00::1,ip6_netsize=64"? This would look awkward, compared to the ipv4 situation, which is a mere "net=10.0.2.2/24".

Samuel

#26 lore raw

Re: [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Quoted 5 lines · Samuel Thibault
Quoted 5 lines
Quoted 2 lines

It makes sense, yes, the syntax would be [ip6-prefix=net[/netsize]] . I just don't know how to express that in qapi :)

'*ip6_net':'str', '*ip6_netsize':'int'

Quoted 7 lines
Quoted 3 lines

passed on the wire as:

"ip6_net":"fc00::1", "ip6_netsize":64

Err, so that means that the user would have to pass "ip6-net=fc00::1,ip6_netsize=64"? This would look awkward, compared to the ipv4 situation, which is a mere "net=10.0.2.2/24".

Err, yes. QMP is machine-parseable. HMP can let the user abbreviate to net=10.0.2.2/24, but QMP should not require reparsing. So what if it's longer, it's easier for machines to manipulate if it's already broken into parts. Trust me - I wouldn't be asking you to split it into two fields unless I thought that libvirt would much rather send it to you as two fields.

Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
#27 lore raw

Re: [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Quoted 15 lines · Eric Blake
Quoted 5 lines · Samuel Thibault
Quoted 5 lines
Quoted 2 lines

It makes sense, yes, the syntax would be [ip6-prefix=net[/netsize]] . I just don't know how to express that in qapi :)

'*ip6_net':'str', '*ip6_netsize':'int'

Quoted 7 lines
Quoted 3 lines

passed on the wire as:

"ip6_net":"fc00::1", "ip6_netsize":64

Err, so that means that the user would have to pass "ip6-net=fc00::1,ip6_netsize=64"? This would look awkward, compared to the ipv4 situation, which is a mere "net=10.0.2.2/24".

Quoted 6 lines

Err, yes. QMP is machine-parseable. HMP can let the user abbreviate to net=10.0.2.2/24, but QMP should not require reparsing. So what if it's longer, it's easier for machines to manipulate if it's already broken into parts. Trust me - I wouldn't be asking you to split it into two fields unless I thought that libvirt would much rather send it to you as two fields.

The command line, just like HMP, can use shorthand for convenience. I guess you do have a point about consistency of ipv4's @net requiring post-processing, but that doesn't mean we have to repeat the mistake for IPv6.

Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
#28 lore raw

Re: [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Quoted 4 lines · Eric Blake, le Tue 22 Oct 2013 11:52:11 +0100, a écrit :
Quoted 1 line · Eric Blake

HMP can let the user abbreviate to net=10.0.2.2/24,

The command line, just like HMP, can use shorthand for convenience.

How are these usually defined? A quick search didn't provide me an example.

Samuel

#29 lore raw

Re: [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Quoted 8 lines · Samuel Thibault
Quoted 4 lines · Eric Blake, le Tue 22 Oct 2013 11:52:11 +0100, a écrit :
Quoted 1 line · Eric Blake

HMP can let the user abbreviate to net=10.0.2.2/24,

The command line, just like HMP, can use shorthand for convenience.

How are these usually defined? A quick search didn't provide me an example.

Hmm, I'm not actually sure myself. I know Keven recently added some code in his blockdev parsing that aliased old commands to re-inject themselves back into a QDict in the preferred spelling, before passing the QDict on down to the final client that handles the options; maybe he has some better ideas on creating a command line shorthand while still keeping QMP fully-structured.

Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
#30 lore raw

Re: [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

I see. So it would be something like this?

commit 1807466d691f281f430fbf8c0bbff6bf8073247d

Author: Samuel Thibault <[email protected]>
Date:   Tue Oct 22 21:11:46 2013 +0200

qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

This patchs 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 fc00::2, fc00::, /64 and fc00::3.

net/net.c +30 -0
index c330c9a..0833aba 100644
@@ -809,6 +809,36 @@ int net_client_init(QemuOpts *opts, int is_netdev, Error **errp)
     int ret = -1;
 
     {
+        /* Parse convenience option format ip6-net=fc00::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);
net/slirp.c +40 -6

85 lines not on this page · raw message

qapi-schema.json +26 -14
index 60f3fd1..fa1b793 100644
@@ -2807,6 +2807,14 @@
 # @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
 #             to the guest
 #
+# @ip6-prefix: #optional IPv6 network prefix (since 1.8)
+#
+# @ip6-prefixlen: #optional IPv6 network prefix length (since 1.8)
+#
+# @ip6-host: #optional guest-visible IPv6 address of the host (since 1.8)
+#
+# @ip6-dns: #optional guest-visible IPv6 address of the virtual nameserver (since 1.8)
+#
 # @smb: #optional root directory of the built-in SMB server
 #
 # @smbserver: #optional IP address of the built-in SMB server
@@ -2820,20 +2828,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
qemu-options.hx +16 -2
index 5dc8b75..00161e0 100644
@@ -1357,8 +1357,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"
@@ -1467,6 +1468,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 fc00::/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
@@ -1484,6 +1493,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
slirp/libslirp.h +5 -3
index 5bdcbd5..c4b25c9 100644
@@ -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);
 
slirp/slirp.c +9 -11
index 35c2665..48e39f2 100644
@@ -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, "fc00::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, "fc00::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, "fc00::3", &slirp->vnameserver_addr6);
+    slirp->vnameserver_addr6 = vnameserver6;
 
     if (vdnssearch) {
         translate_dnssearch(slirp, vdnssearch);
#31 lore raw

Re: [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Quoted 8 lines · Samuel Thibault

I see. So it would be something like this?

commit 1807466d691f281f430fbf8c0bbff6bf8073247d

Author: Samuel Thibault <[email protected]>
Date:   Tue Oct 22 21:11:46 2013 +0200

qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Quoted 8 lines

This patchs 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 fc00::2, fc00::, /64 and fc00::3.

Yes, this looks better from the interface point of view (I didn't closely review the code though, as I'm not a slirp expert).

Quoted 35 lines

{ 'type': 'NetdevUserOptions',
'data': {

qapi-schema.json +18 -14
-    '*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'] } }
Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
#32 lore raw

v2 cover slirp: Adding IPv6 support to Qemu -net user mode

In reply to Samuel Thibault

Hello,

This is a 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.

Some patches, like 2 and 13, can be reviewed using "interdiff -w /dev/null patchfile"
to get rid of the indentation.

Differences with version 1 are:

- the encoding of the option to specify the configured network: this is still -net ip6-net=addr/len in the user interface, but decomposed as ip6-prefix and ip6-prefixlen in the QAPI.
- the RA timer has been made per-slirp instead of global.
- the default host IPs have been made fc00::2 and fc00::3, coherent with the IPv4 case.

[PATCH 01/16] slirp: goto bad in udp_input if sosendto fails [PATCH 02/16] slirp: Generalizing and neutralizing code before adding [PATCH 03/16] qemu/timer.h : Adding function to second scale [PATCH 04/16] slirp: Adding IPv6, ICMPv6 Echo and NDP [PATCH 05/16] slirp: Adding ICMPv6 error sending
[PATCH 06/16] slirp: Make Socket structure IPv6 compatible [PATCH 07/16] slirp: Factorizing address translation [PATCH 08/16] slirp: Factorizing and cleaning solookup() [PATCH 09/16] slirp: Make udp_attach IPv6 compatible [PATCH 10/16] slirp: Adding IPv6 UDP support
[PATCH 11/16] slirp: Adding family argument to tcp_fconnect() [PATCH 12/16] slirp: Factorizing tcpiphdr structure with an union [PATCH 13/16] slirp: Generalizing and neutralizing various TCP [PATCH 14/16] slirp: Handle IPv6 in TCP functions
[PATCH 15/16] slirp: Adding IPv6 address for DNS relay [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options

#33 lore raw

PATCH 1/16 slirp: goto bad in udp_input if sosendto fails

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.

---
 slirp/udp.c | 1 +
 1 file changed, 1 insertion(+)
slirp/udp.c +1 -0
index 8cc6cb6..fd2446a 100644
@@ -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 */
Signature · 1 line
1.8.4.2
#34 lore raw

PATCH 2/16 slirp: Generalizing and neutralizing code before adding IPv6 stuff

In reply to Samuel Thibault

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

---
 slirp/if.c    |   2 +-
 slirp/mbuf.c  |   2 +-
 slirp/mbuf.h  |   2 +-
 slirp/slirp.c | 107 ++++++++++++++++++++++++++++++++++------------------------
 slirp/slirp.h |  12 +++----
 5 files changed, 71 insertions(+), 54 deletions(-)
slirp/if.c +1 -1
index fb7acf8..e36b9cb 100644
@@ -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;
         }
 
slirp/mbuf.c +1 -1
index 4fefb04..92c429e 100644
@@ -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);
slirp/mbuf.h +1 -1
index b144f1c..38fedf4 100644
@@ -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 {
slirp/slirp.c +62 -45

115 lines not on this page · raw message

slirp/slirp.h +6 -6
index e4a1bd4..cd9f2d0 100644
@@ -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   */
 
Signature · 1 line
1.8.4.2
#35 lore raw

PATCH 3/16 qemu/timer.h : Adding function to second scale

In reply to Samuel Thibault

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

---
 include/qemu/timer.h | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
include/qemu/timer.h +32 -0
index 5afcffc..7376c0a 100644
@@ -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
  *
Signature · 1 line
1.8.4.2
#36 lore raw

PATCH 4/16 slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration

In reply to Samuel Thibault

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.

---
 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 ++++++
 10 files changed, 1038 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
slirp/Makefile.objs +2 -2
index 2daa9dc..2dfe8e0 100644
@@ -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
slirp/cksum.c +23 -0
index 6328660..f0a1398 100644
@@ -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;
+}
slirp/ip6.h new file +139 -0

139 lines not on this page · raw message

slirp/ip6_icmp.c new file +349 -0

349 lines not on this page · raw message

slirp/ip6_icmp.h new file +248 -0

248 lines not on this page · raw message

slirp/ip6_input.c new file +75 -0

75 lines not on this page · raw message

slirp/ip6_output.c new file +41 -0

41 lines not on this page · raw message

slirp/ndp_table.c new file +87 -0

87 lines not on this page · raw message

slirp/slirp.c +39 -8

95 lines not on this page · raw message

slirp/slirp.h +35 -0
index cd9f2d0..ec9cbed 100644
@@ -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);
Signature · 1 line
1.8.4.2
#37 lore raw

PATCH 5/16 slirp: Adding ICMPv6 error sending

In reply to Samuel Thibault

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.

---
 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(-)
slirp/ip6_icmp.c +60 -0
index 4538bfd..8952bbc 100644
@@ -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
  */
slirp/ip6_icmp.h +10 -0
index bd9d3d9..deae1a1 100644
@@ -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);
 
slirp/ip6_input.c +9 -7
index 9663c42..af098a5 100644
@@ -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;
slirp/ip_icmp.c +6 -6
index 9f1cb08..1808976 100644
@@ -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);
     }
 
@@ -197,7 +197,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 */
@@ -243,7 +243,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;
@@ -251,7 +251,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);
 
@@ -441,7 +441,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! */
slirp/ip_icmp.h +2 -2
index be4426b..846761d 100644
@@ -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);
slirp/ip_input.c +4 -4
index 880bdfd..1925cdc 100644
@@ -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);
 }
slirp/socket.c +2 -2
index 37ac5cf..e87c70e 100644
@@ -459,7 +459,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! */
@@ -507,7 +507,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 {
 	  /*
slirp/tcp_input.c +1 -1
index f946db8..ba31461 100644
@@ -601,7 +601,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);
slirp/udp.c +2 -1
index fd2446a..2bead1c 100644
@@ -217,7 +217,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;
 	}
 
Signature · 1 line
1.8.4.2
#38 lore raw

PATCH 6/16 slirp: Make Socket structure IPv6 compatible

In reply to Samuel Thibault

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.

---
 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(-)
slirp/ip_icmp.c +2 -0
index 1808976..768ea4a 100644
@@ -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;
slirp/slirp.c +40 -8

60 lines not on this page · raw message

slirp/socket.c +11 -3
index e87c70e..2f166fb 100644
@@ -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;
slirp/socket.h +21 -4
index 57e0407..07f116d 100644
@@ -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? */
slirp/tcp_input.c +2 -0
index ba31461..70ef376 100644
@@ -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;
 
slirp/tcp_subr.c +2 -0
index 7571c5a..f15da70 100644
@@ -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 */
slirp/udp.c +4 -0
index 2bead1c..a3dc3e7 100644
@@ -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 */
 
@@ -377,6 +379,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) {
@@ -384,6 +387,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)
Signature · 1 line
1.8.4.2
#39 lore raw

PATCH 7/16 slirp: Factorizing address translation

In reply to Samuel Thibault

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.

---
 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(-)
slirp/bootp.c +1 -1
index b7db9fa..03e2e42 100644
@@ -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)
slirp/ip_icmp.c +4 -15
index 768ea4a..8787aae 100644
@@ -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",
slirp/socket.c +73 -20

126 lines not on this page · raw message

slirp/socket.h +3 -0
index 07f116d..50059be 100644
@@ -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_ */
slirp/tcp_subr.c +5 -19
index f15da70..4791c0c 100644
@@ -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));
 
slirp/tftp.c +3 -3
index 1a79c45..dee201b 100644
@@ -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);
slirp/udp.c +1 -26
index a3dc3e7..bab1c60 100644
@@ -237,7 +237,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)
 {
@@ -288,31 +288,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)
 {
slirp/udp.h +1 -2
index 9bf31fe..a04b8ce 100644
@@ -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
Signature · 1 line
1.8.4.2
#40 lore raw

PATCH 8/16 slirp: Factorizing and cleaning solookup()

In reply to Samuel Thibault

This patch makes solookup() compatible with all address family. 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.

---
 slirp/socket.c    | 30 ++++++++++++++++--------------
 slirp/socket.h    | 30 +++++++++++++++++++++++++++++-
 slirp/tcp_input.c | 27 +++++++++++----------------
 slirp/udp.c       | 25 ++++++-------------------
 4 files changed, 62 insertions(+), 50 deletions(-)
slirp/socket.c +16 -14
index 375281c..f333fcf 100644
@@ -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;
 }
 
 /*
slirp/socket.h +29 -1
index 50059be..ad509b9 100644
@@ -93,7 +93,35 @@ 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);
+        }
+        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:
+            return 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 *);
slirp/tcp_input.c +11 -16
index 70ef376..f7a8d49 100644
@@ -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;
slirp/udp.c +6 -19
index bab1c60..7e0f1b2 100644
@@ -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) {
 	  /*
Signature · 1 line
1.8.4.2
#41 lore raw

PATCH 9/16 slirp: Make udp_attach IPv6 compatible

In reply to Samuel Thibault

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

---
 slirp/ip_icmp.c | 2 +-
 slirp/udp.c     | 7 ++++---
 slirp/udp.h     | 2 +-
 3 files changed, 6 insertions(+), 5 deletions(-)
slirp/ip_icmp.c +1 -1
index 8787aae..c896574 100644
@@ -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);
slirp/udp.c +4 -3
index 7e0f1b2..f53ee11 100644
@@ -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);
@@ -276,9 +276,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);
   }
slirp/udp.h +1 -1
index a04b8ce..15e73c1 100644
@@ -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);
Signature · 1 line
1.8.4.2
#42 lore raw

PATCH 10/16 slirp: Adding IPv6 UDP support

In reply to Samuel Thibault

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

---
 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
slirp/Makefile.objs +1 -1
index 2dfe8e0..faa32b6 100644
@@ -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
slirp/ip6_input.c +1 -2
index af098a5..3290af8 100644
@@ -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);
slirp/socket.c +6 -1
index f333fcf..31bbb7e 100644
@@ -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 */
slirp/udp.h +5 -0
index 15e73c1..8a4d9f5 100644
@@ -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
slirp/udp6.c new file +149 -0

149 lines not on this page · raw message

Signature · 1 line
1.8.4.2
#43 lore raw

PATCH 11/16 slirp: Adding family argument to tcp_fconnect()

In reply to Samuel Thibault

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

---
 slirp/slirp.h     | 2 +-
 slirp/tcp_input.c | 3 ++-
 slirp/tcp_subr.c  | 5 +++--
 3 files changed, 6 insertions(+), 4 deletions(-)
slirp/slirp.h +1 -1
index ec9cbed..d16400b 100644
@@ -369,7 +369,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 *);
slirp/tcp_input.c +2 -1
index f7a8d49..25929bd 100644
@@ -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)));
slirp/tcp_subr.c +3 -2
index 4791c0c..3558115 100644
@@ -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;
 
Signature · 1 line
1.8.4.2
#44 lore raw

PATCH 12/16 slirp: Factorizing tcpiphdr structure with an union

In reply to Samuel Thibault

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)

---
 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(-)
slirp/if.h +2 -2
index 3327023..c7a5c57 100644
@@ -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
slirp/mbuf.c +2 -1
index 92c429e..87ee550 100644
@@ -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)
slirp/slirp.c +8 -7
index a78fa72..79025cd 100644
@@ -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);
slirp/socket.c +12 -1
index 31bbb7e..567f9bc 100644
@@ -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,
slirp/tcp_input.c +20 -11
index 25929bd..dde89b6 100644
@@ -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);
slirp/tcp_output.c +13 -5
index 8aa3d90..4726f00 100644
@@ -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);
slirp/tcp_subr.c +22 -9
index 3558115..b052947 100644
@@ -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);
 }
slirp/tcpip.h +23 -8
index 7974ce3..d9b5d70 100644
@@ -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
Signature · 1 line
1.8.4.2
#45 lore raw

PATCH 13/16 slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff

In reply to Samuel Thibault

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.

---
 slirp/ip_input.c   |   2 +-
 slirp/slirp.c      |   6 ++-
 slirp/slirp.h      |   5 +-
 slirp/tcp_input.c  | 142 +++++++++++++++++++++++++++++++++--------------------
 slirp/tcp_output.c |  43 +++++++++-------
 slirp/tcp_subr.c   |  94 +++++++++++++++++++++--------------
 slirp/tcp_timer.c  |   3 +-
 7 files changed, 181 insertions(+), 114 deletions(-)
slirp/ip_input.c +1 -1
index 1925cdc..9aa8909 100644
@@ -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);
slirp/slirp.c +4 -2
index 79025cd..9bee487 100644
@@ -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
             }
slirp/slirp.h +3 -2
index d16400b..3cdf984 100644
@@ -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,8 @@ void tcp_setpersist(register struct tcpcb *);
 void tcp_init(Slirp *);
 void tcp_cleanup(Slirp *);
 void tcp_template(struct tcpcb *);
-void tcp_respond(struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int);
+void tcp_respond(struct tcpcb *, register struct tcpiphdr *,
+        register struct mbuf *, tcp_seq, tcp_seq, int, sa_family_t);
 struct tcpcb * tcp_newtcpcb(struct socket *);
 struct tcpcb * tcp_close(register struct tcpcb *);
 void tcp_sockclosed(struct tcpcb *);
slirp/tcp_input.c +90 -52

203 lines not on this page · raw message

slirp/tcp_output.c +25 -18

55 lines not on this page · raw message

slirp/tcp_subr.c +56 -38

138 lines not on this page · raw message

slirp/tcp_timer.c +2 -1
index 6c5bb11..42c6e7e 100644
@@ -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;
Signature · 1 line
1.8.4.2
#46 lore raw

PATCH 14/16 slirp: Handle IPv6 in TCP functions

In reply to Samuel Thibault

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

---
 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(-)
slirp/ip6_input.c +2 -2
index 3290af8..b03b795 100644
@@ -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);
slirp/tcp.h +2 -0
index 2e2b403..61befcd 100644
@@ -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 */
slirp/tcp_input.c +44 -14

113 lines not on this page · raw message

slirp/tcp_output.c +16 -0
index ce0d0e6..64742a2 100644
@@ -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;
 	}
slirp/tcp_subr.c +32 -4
index ba4eb80..6c087e3 100644
@@ -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;
slirp/tcpip.h +9 -0
index d9b5d70..4a2987f 100644
@@ -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
Signature · 1 line
1.8.4.2
#47 lore raw

PATCH 15/16 slirp: Adding IPv6 address for DNS relay

In reply to Samuel Thibault

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.

---
 slirp/ip6.h    |  5 ++++-
 slirp/slirp.c  |  2 ++
 slirp/slirp.h  |  1 +
 slirp/socket.c | 26 ++++++++++++++++++++++++--
 4 files changed, 31 insertions(+), 3 deletions(-)
slirp/ip6.h +4 -1
index 16124ec..b88456d 100644
@@ -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))
slirp/slirp.c +2 -0
index 9bee487..35c2665 100644
@@ -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, "fc00::3", &slirp->vnameserver_addr6);
 
     if (vdnssearch) {
         translate_dnssearch(slirp, vdnssearch);
slirp/slirp.h +1 -0
index 3cdf984..57fe17e 100644
@@ -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];
slirp/socket.c +24 -2
index 567f9bc..a9b3957 100644
@@ -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;
     }
Signature · 1 line
1.8.4.2
#48 lore raw

PATCH 16/16 qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

In reply to Samuel Thibault

This patchs 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 fc00::2, fc00::, /64 and fc00::3.

---
 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(-)
net/net.c +30 -0
index 0a88e68..6c48b71 100644
@@ -814,6 +814,36 @@ int net_client_init(QemuOpts *opts, int is_netdev, Error **errp)
     int ret = -1;
 
     {
+        /* Parse convenience option format ip6-net=fc00::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);
net/slirp.c +40 -6

85 lines not on this page · raw message

qapi-schema.json +26 -14
index 76c98a7..f4090f2 100644
@@ -2831,6 +2831,14 @@
 # @dnssearch: #optional list of DNS suffixes to search, passed as DHCP option
 #             to the guest
 #
+# @ip6-prefix: #optional IPv6 network prefix (since 1.8)
+#
+# @ip6-prefixlen: #optional IPv6 network prefix length (since 1.8)
+#
+# @ip6-host: #optional guest-visible IPv6 address of the host (since 1.8)
+#
+# @ip6-dns: #optional guest-visible IPv6 address of the virtual nameserver (since 1.8)
+#
 # @smb: #optional root directory of the built-in SMB server
 #
 # @smbserver: #optional IP address of the built-in SMB server
@@ -2844,20 +2852,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
qemu-options.hx +16 -2
index 5dc8b75..00161e0 100644
@@ -1357,8 +1357,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"
@@ -1467,6 +1468,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 fc00::/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
@@ -1484,6 +1493,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
slirp/libslirp.h +5 -3
index 5bdcbd5..c4b25c9 100644
@@ -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);
 
slirp/slirp.c +9 -11
index 35c2665..48e39f2 100644
@@ -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, "fc00::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, "fc00::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, "fc00::3", &slirp->vnameserver_addr6);
+    slirp->vnameserver_addr6 = vnameserver6;
 
     if (vdnssearch) {
         translate_dnssearch(slirp, vdnssearch);
Signature · 1 line
1.8.4.2
#49 lore raw

v3 cover slirp: Adding IPv6 support to Qemu -net user mode

In reply to Samuel Thibault

Hello,

This is a 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.

Some patches, like 2 and 13, can be reviewed using "interdiff -w /dev/null patchfile"
to get rid of the indentation.

Difference with version 2 is:
- The default IP range has been made fec0::/64 instead of fc00::/64

#50 lore raw

PATCH 1/16 slirp: goto bad in udp_input if sosendto fails

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.

---
 slirp/udp.c | 1 +
 1 file changed, 1 insertion(+)
slirp/udp.c +1 -0
index 8cc6cb6..fd2446a 100644
@@ -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 */
Signature · 1 line
1.8.5.3
#51 lore raw

PATCH 1/1 slirp: goto bad in udp_input if sosendto fails

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.

---
 slirp/udp.c | 1 +
 1 file changed, 1 insertion(+)
slirp/udp.c +1 -0
index 8cc6cb6..fd2446a 100644
@@ -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 */
#52 lore raw

Re: [Qemu-devel] [PATCH] slirp: goto bad in udp_input if sosendto fails

Quoted 2 lines · Samuel Thibault

Before this patch, if sosendto fails, udp_input is executed as if the packet was sent. This could cause memory leak.

Cannot follow yet how this could leak (not saying I fully got what it should NOT leak - nasty code). Can you elaborate on the before/after?

Jan

Quoted 20 lines

This patch adds a goto bad to cut the execution of this function.

---
 slirp/udp.c | 1 +
 1 file changed, 1 insertion(+)
slirp/udp.c +1 -0
index 8cc6cb6..fd2446a 100644
@@ -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 */
Signature · 2 lines
Siemens AG, Corporate Technology, CT RTC ITP SES-DE
Corporate Competence Center Embedded Linux
#53 lore raw

Re: [Qemu-devel] [PATCH] slirp: goto bad in udp_input if sosendto fails

Quoted 6 lines · Jan Kiszka, le Thu 12 Jun 2014 07:47:25 +0200, a écrit :
Quoted 2 lines · Samuel Thibault

Before this patch, if sosendto fails, udp_input is executed as if the packet was sent. This could cause memory leak.

Cannot follow yet how this could leak (not saying I fully got what it should NOT leak - nasty code). Can you elaborate on the before/after?

I haven't worked on the patch, but can comment a bit.

I'm not sure it's actually a memory leak, but the "before" situation is quite confusing actually :)

Before, m->m_len += iphlen and m->m_data -= iphlen would be done twice in the end, thus leaving m in an odd state. At any rate, letting udp_input put m into so->so_m does not make any sense: so->so_m is used by icmp_receive/sorecvfrom to know where to send back any errors from the outside for a packet that we have emitted. Here, since we haven't actually emitted the packet, there is not much sense in using it, and any error that we may get later would rather be related to the previous packet, not the one we haven't emitted.

Samuel

#54 lore raw

PATCH 1/1 slirp: goto bad in udp_input if sosendto fails

In reply to Samuel Thibault

Before this patch, if sosendto fails, udp_input is executed as if the packet was sent, recording the packet for icmp errors, which does not makes sense since the packet was not actually sent, errors would be related to a previous packet.

This patch adds a goto bad to cut the execution of this function.

---
 slirp/udp.c | 1 +
 1 file changed, 1 insertion(+)
slirp/udp.c +1 -0
index 8cc6cb6..fd2446a 100644
@@ -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 */
#55 lore raw

PATCH 2/16 slirp: Generalizing and neutralizing code before adding IPv6 stuff

In reply to Samuel Thibault

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

---
 slirp/if.c    |   2 +-
 slirp/mbuf.c  |   2 +-
 slirp/mbuf.h  |   2 +-
 slirp/slirp.c | 107 ++++++++++++++++++++++++++++++++++------------------------
 slirp/slirp.h |  12 +++----
 5 files changed, 71 insertions(+), 54 deletions(-)
slirp/if.c +1 -1
index fb7acf8..e36b9cb 100644
@@ -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;
         }
 
slirp/mbuf.c +1 -1
index 4fefb04..92c429e 100644
@@ -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);
slirp/mbuf.h +1 -1
index b144f1c..38fedf4 100644
@@ -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 {
slirp/slirp.c +62 -45

115 lines not on this page · raw message

slirp/slirp.h +6 -6
index e4a1bd4..cd9f2d0 100644
@@ -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   */
 
Signature · 1 line
1.8.5.3
#56 lore raw

PATCH 3/16 qemu/timer.h : Adding function to second scale

In reply to Samuel Thibault

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

---
 include/qemu/timer.h | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
include/qemu/timer.h +32 -0
index 7f9a074..b46601c 100644
@@ -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
  *
Signature · 1 line
1.8.5.3
#57 lore raw

PATCH 4/16 slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration

In reply to Samuel Thibault

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.

---
 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 ++++++
 10 files changed, 1038 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
slirp/Makefile.objs +2 -2
index 2daa9dc..2dfe8e0 100644
@@ -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
slirp/cksum.c +23 -0
index 6328660..f0a1398 100644
@@ -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;
+}
slirp/ip6.h new file +139 -0

139 lines not on this page · raw message

slirp/ip6_icmp.c new file +349 -0

349 lines not on this page · raw message

slirp/ip6_icmp.h new file +248 -0

248 lines not on this page · raw message

slirp/ip6_input.c new file +75 -0

75 lines not on this page · raw message

slirp/ip6_output.c new file +41 -0

41 lines not on this page · raw message

slirp/ndp_table.c new file +87 -0

87 lines not on this page · raw message

slirp/slirp.c +39 -8

95 lines not on this page · raw message

slirp/slirp.h +35 -0
index cd9f2d0..ec9cbed 100644
@@ -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);
Signature · 1 line
1.8.5.3
#58 lore raw

PATCH 5/16 slirp: Adding ICMPv6 error sending

In reply to Samuel Thibault

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.

---
 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(-)
slirp/ip6_icmp.c +60 -0
index 4538bfd..8952bbc 100644
@@ -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
  */
slirp/ip6_icmp.h +10 -0
index bd9d3d9..deae1a1 100644
@@ -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);
 
slirp/ip6_input.c +9 -7
index 9663c42..af098a5 100644
@@ -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;
slirp/ip_icmp.c +6 -6
index 9f1cb08..1808976 100644
@@ -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);
     }
 
@@ -197,7 +197,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 */
@@ -243,7 +243,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;
@@ -251,7 +251,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);
 
@@ -441,7 +441,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! */
slirp/ip_icmp.h +2 -2
index be4426b..846761d 100644
@@ -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);
slirp/ip_input.c +4 -4
index 880bdfd..1925cdc 100644
@@ -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);
 }
slirp/socket.c +2 -2
index 37ac5cf..e87c70e 100644
@@ -459,7 +459,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! */
@@ -507,7 +507,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 {
 	  /*
slirp/tcp_input.c +1 -1
index f946db8..ba31461 100644
@@ -601,7 +601,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);
slirp/udp.c +2 -1
index fd2446a..2bead1c 100644
@@ -217,7 +217,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;
 	}
 
Signature · 1 line
1.8.5.3
#59 lore raw

PATCH 6/16 slirp: Make Socket structure IPv6 compatible

In reply to Samuel Thibault

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.

---
 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(-)
slirp/ip_icmp.c +2 -0
index 1808976..768ea4a 100644
@@ -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;
slirp/slirp.c +40 -8

60 lines not on this page · raw message

slirp/socket.c +11 -3
index e87c70e..2f166fb 100644
@@ -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;
slirp/socket.h +21 -4
index 57e0407..07f116d 100644
@@ -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? */
slirp/tcp_input.c +2 -0
index ba31461..70ef376 100644
@@ -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;
 
slirp/tcp_subr.c +2 -0
index 7571c5a..f15da70 100644
@@ -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 */
slirp/udp.c +4 -0
index 2bead1c..a3dc3e7 100644
@@ -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 */
 
@@ -377,6 +379,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) {
@@ -384,6 +387,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)
Signature · 1 line
1.8.5.3
#60 lore raw

PATCH 7/16 slirp: Factorizing address translation

In reply to Samuel Thibault

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.

---
 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(-)
slirp/bootp.c +1 -1
index b7db9fa..03e2e42 100644
@@ -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)
slirp/ip_icmp.c +4 -15
index 768ea4a..8787aae 100644
@@ -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",
slirp/socket.c +73 -20

126 lines not on this page · raw message

slirp/socket.h +3 -0
index 07f116d..50059be 100644
@@ -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_ */
slirp/tcp_subr.c +5 -19
index f15da70..4791c0c 100644
@@ -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));
 
slirp/tftp.c +3 -3
index 1a79c45..dee201b 100644
@@ -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);
slirp/udp.c +1 -26
index a3dc3e7..bab1c60 100644
@@ -237,7 +237,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)
 {
@@ -288,31 +288,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)
 {
slirp/udp.h +1 -2
index 9bf31fe..a04b8ce 100644
@@ -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
Signature · 1 line
1.8.5.3
#61 lore raw

PATCH 8/16 slirp: Factorizing and cleaning solookup()

In reply to Samuel Thibault

This patch makes solookup() compatible with all address family. 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.

---
 slirp/socket.c    | 30 ++++++++++++++++--------------
 slirp/socket.h    | 30 +++++++++++++++++++++++++++++-
 slirp/tcp_input.c | 27 +++++++++++----------------
 slirp/udp.c       | 25 ++++++-------------------
 4 files changed, 62 insertions(+), 50 deletions(-)
slirp/socket.c +16 -14
index 375281c..f333fcf 100644
@@ -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;
 }
 
 /*
slirp/socket.h +29 -1
index 50059be..ad509b9 100644
@@ -93,7 +93,35 @@ 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);
+        }
+        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:
+            return 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 *);
slirp/tcp_input.c +11 -16
index 70ef376..f7a8d49 100644
@@ -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;
slirp/udp.c +6 -19
index bab1c60..7e0f1b2 100644
@@ -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) {
 	  /*
Signature · 1 line
1.8.5.3
#62 lore raw

PATCH 9/16 slirp: Make udp_attach IPv6 compatible

In reply to Samuel Thibault

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

---
 slirp/ip_icmp.c | 2 +-
 slirp/udp.c     | 7 ++++---
 slirp/udp.h     | 2 +-
 3 files changed, 6 insertions(+), 5 deletions(-)
slirp/ip_icmp.c +1 -1
index 8787aae..c896574 100644
@@ -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);
slirp/udp.c +4 -3
index 7e0f1b2..f53ee11 100644
@@ -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);
@@ -276,9 +276,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);
   }
slirp/udp.h +1 -1
index a04b8ce..15e73c1 100644
@@ -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);
Signature · 1 line
1.8.5.3
#63 lore raw

PATCH 10/16 slirp: Adding IPv6 UDP support

In reply to Samuel Thibault

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

---
 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
slirp/Makefile.objs +1 -1
index 2dfe8e0..faa32b6 100644
@@ -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
slirp/ip6_input.c +1 -2
index af098a5..3290af8 100644
@@ -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);
slirp/socket.c +6 -1
index f333fcf..31bbb7e 100644
@@ -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 */
slirp/udp.h +5 -0
index 15e73c1..8a4d9f5 100644
@@ -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
slirp/udp6.c new file +149 -0

149 lines not on this page · raw message

Signature · 1 line
1.8.5.3
#64 lore raw

PATCH 11/16 slirp: Adding family argument to tcp_fconnect()

In reply to Samuel Thibault

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

---
 slirp/slirp.h     | 2 +-
 slirp/tcp_input.c | 3 ++-
 slirp/tcp_subr.c  | 5 +++--
 3 files changed, 6 insertions(+), 4 deletions(-)
slirp/slirp.h +1 -1
index ec9cbed..d16400b 100644
@@ -369,7 +369,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 *);
slirp/tcp_input.c +2 -1
index f7a8d49..25929bd 100644
@@ -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)));
slirp/tcp_subr.c +3 -2
index 4791c0c..3558115 100644
@@ -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;
 
Signature · 1 line
1.8.5.3
#65 lore raw

PATCH 12/16 slirp: Factorizing tcpiphdr structure with an union

In reply to Samuel Thibault

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)

---
 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(-)
slirp/if.h +2 -2
index 3327023..c7a5c57 100644
@@ -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
slirp/mbuf.c +2 -1
index 92c429e..87ee550 100644
@@ -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)
slirp/slirp.c +8 -7
index eea2fee..33ed0cd 100644
@@ -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);
slirp/socket.c +12 -1
index 31bbb7e..567f9bc 100644
@@ -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,
slirp/tcp_input.c +20 -11
index 25929bd..dde89b6 100644
@@ -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);
slirp/tcp_output.c +13 -5
index 8aa3d90..4726f00 100644
@@ -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);
slirp/tcp_subr.c +22 -9
index 3558115..b052947 100644
@@ -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);
 }
slirp/tcpip.h +23 -8
index 7974ce3..d9b5d70 100644
@@ -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
Signature · 1 line
1.8.5.3
#66 lore raw

PATCH 13/16 slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff

In reply to Samuel Thibault

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.

---
 slirp/ip_input.c   |   2 +-
 slirp/slirp.c      |   6 ++-
 slirp/slirp.h      |   5 +-
 slirp/tcp_input.c  | 142 +++++++++++++++++++++++++++++++++--------------------
 slirp/tcp_output.c |  43 +++++++++-------
 slirp/tcp_subr.c   |  94 +++++++++++++++++++++--------------
 slirp/tcp_timer.c  |   3 +-
 7 files changed, 181 insertions(+), 114 deletions(-)
slirp/ip_input.c +1 -1
index 1925cdc..9aa8909 100644
@@ -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);
slirp/slirp.c +4 -2
index 33ed0cd..7f2ed70 100644
@@ -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
             }
slirp/slirp.h +3 -2
index d16400b..3cdf984 100644
@@ -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,8 @@ void tcp_setpersist(register struct tcpcb *);
 void tcp_init(Slirp *);
 void tcp_cleanup(Slirp *);
 void tcp_template(struct tcpcb *);
-void tcp_respond(struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int);
+void tcp_respond(struct tcpcb *, register struct tcpiphdr *,
+        register struct mbuf *, tcp_seq, tcp_seq, int, sa_family_t);
 struct tcpcb * tcp_newtcpcb(struct socket *);
 struct tcpcb * tcp_close(register struct tcpcb *);
 void tcp_sockclosed(struct tcpcb *);
slirp/tcp_input.c +90 -52

203 lines not on this page · raw message

slirp/tcp_output.c +25 -18

55 lines not on this page · raw message

slirp/tcp_subr.c +56 -38

138 lines not on this page · raw message

slirp/tcp_timer.c +2 -1
index 6c5bb11..42c6e7e 100644
@@ -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;
Signature · 1 line
1.8.5.3
#67 lore raw

PATCH 14/16 slirp: Handle IPv6 in TCP functions

In reply to Samuel Thibault

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

---
 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(-)
slirp/ip6_input.c +2 -2
index 3290af8..b03b795 100644
@@ -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);
slirp/tcp.h +2 -0
index 2e2b403..61befcd 100644
@@ -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 */
slirp/tcp_input.c +44 -14

113 lines not on this page · raw message

slirp/tcp_output.c +16 -0
index ce0d0e6..64742a2 100644
@@ -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;
 	}
slirp/tcp_subr.c +32 -4
index ba4eb80..6c087e3 100644
@@ -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;
slirp/tcpip.h +9 -0
index d9b5d70..4a2987f 100644
@@ -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
Signature · 1 line
1.8.5.3
#68 lore raw

PATCH 15/16 slirp: Adding IPv6 address for DNS relay

In reply to Samuel Thibault

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.

---
 slirp/ip6.h    |  5 ++++-
 slirp/slirp.c  |  2 ++
 slirp/slirp.h  |  1 +
 slirp/socket.c | 26 ++++++++++++++++++++++++--
 4 files changed, 31 insertions(+), 3 deletions(-)
slirp/ip6.h +4 -1
index 9e65acd..c799421 100644
@@ -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))
slirp/slirp.c +2 -0
index 7f2ed70..ce3a111 100644
@@ -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);
slirp/slirp.h +1 -0
index 3cdf984..57fe17e 100644
@@ -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];
slirp/socket.c +24 -2
index 567f9bc..a9b3957 100644
@@ -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;
     }
Signature · 1 line
1.8.5.3
#69 lore raw

PATCH 16/16 qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

In reply to Samuel Thibault

This patchs 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.

---
 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(-)
net/net.c +30 -0
index 2c3af20..e62e9fb 100644
@@ -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);
net/slirp.c +40 -6

85 lines not on this page · raw message

qapi-schema.json +26 -14
index 05ced9d..a5d8e0e 100644
@@ -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 1.8)
+#
+# @ip6-prefixlen: #optional IPv6 network prefix length (since 1.8)
+#
+# @ip6-host: #optional guest-visible IPv6 address of the host (since 1.8)
+#
+# @ip6-dns: #optional guest-visible IPv6 address of the virtual nameserver (since 1.8)
+#
 # @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
qemu-options.hx +16 -2
index 56e5fdf..6ad2eb4 100644
@@ -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
slirp/libslirp.h +5 -3
index 5bdcbd5..c4b25c9 100644
@@ -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);
 
slirp/slirp.c +9 -11
index ce3a111..48e39f2 100644
@@ -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);
Signature · 1 line
1.8.5.3
#70 lore raw

Re: [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses

Quoted 1 line · Samuel Thibault

This patchs adds parameters to manage some new options in the qemu -net

s/patchs/patch/

Quoted 7 lines

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.

Quoted 9 lines
---
 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(-)

Just reviewing the QMP side:

qapi-schema.json line 2909

Quoted 6 lines

+++ b/qapi-schema.json

qapi-schema.json +1 -0
@@ -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 1.8)

There was no 1.8 release, and you've missed the 2.0 release. This, and all other instances in the patch to this file, must be '(since 2.1)'

Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
#71 lore raw
In reply to Samuel Thibault
Quoted 3 lines · Samuel Thibault

Hello,

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

When sending a new revision of a long series, it's easier if it appears as a new top-level thread, instead on in reply to the earlier series.

Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
#72 lore raw
Quoted 5 lines · Eric Blake, le Tue 11 Feb 2014 06:50:54 -0700, a écrit :
Quoted 1 line · Samuel Thibault

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

When sending a new revision of a long series, it's easier if it appears as a new top-level thread, instead on in reply to the earlier series.

Ah, ok, as you wish. I guess I don't need to resend the series again just for that :)

Samuel

#73 lore raw
Quoted 9 lines · Samuel Thibault
Quoted 5 lines · Eric Blake, le Tue 11 Feb 2014 06:50:54 -0700, a écrit :
Quoted 1 line · Samuel Thibault

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

When sending a new revision of a long series, it's easier if it appears as a new top-level thread, instead on in reply to the earlier series.

Ah, ok, as you wish. I guess I don't need to resend the series again just for that :)

I actually don't see patches 1..16, only the cover letter.

Signature · 2 lines
Thanks.
-- Max
#74 lore raw
Quoted 6 lines · Max Filippov
Quoted 4 lines · Samuel Thibault
Quoted 3 lines · Eric Blake, le Tue 11 Feb 2014 06:50:54 -0700, a écrit :
Quoted 1 line · Samuel Thibault

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

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

When sending a new revision of a long series, it's easier if it appears as a new top-level thread, instead on in reply to the earlier series.

Ah, ok, as you wish. I guess I don't need to resend the series again just for that :)

I actually don't see patches 1..16, only the cover letter.

Oops, nevermind, they're here. But I see what Eric meant.

Signature · 2 lines
Thanks.
-- Max
#75 lore raw
In reply to Samuel Thibault
Quoted 11 lines · Samuel Thibault

Hello,

This is a 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.

Some patches, like 2 and 13, can be reviewed using "interdiff -w /dev/null patchfile"
to get rid of the indentation.

The alternative is to split reindention from refactoring patches.

Quoted 4 lines

Difference with version 2 is:
- The default IP range has been made fec0::/64 instead of fc00::/64

This is very valuable work. Unfortunately, I'm lacking time to review or even test this ATM. If someone else could, that would be great.

Thanks,
Jan

Signature · 2 lines
Siemens AG, Corporate Technology, CT RTC ITP SES-DE
Corporate Competence Center Embedded Linux
#76 lore raw
Quoted 16 lines · Jan Kiszka
Quoted 11 lines · Samuel Thibault

Hello,

This is a 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.

Some patches, like 2 and 13, can be reviewed using "interdiff -w /dev/null patchfile"
to get rid of the indentation.

The alternative is to split reindention from refactoring patches.

Quoted 1 line
Quoted 6 lines
Quoted 3 lines

Difference with version 2 is:
- The default IP range has been made fec0::/64 instead of fc00::/64

This is very valuable work. Unfortunately, I'm lacking time to review or even test this ATM. If someone else could, that would be great.

I also feel a little sad to see this major feature languish but don't have much time at the moment.

My suggestion is to split all the preparation and cleanups into a smaller patch series that can be applied easily.

It will make the real IPv6 series smaller and hopefully more amenable to review.

Stefan

#77 lore raw
Quoted 5 lines · Stefan Hajnoczi, le Thu 20 Mar 2014 08:58:11 +0100, a écrit :

My suggestion is to split all the preparation and cleanups into a smaller patch series that can be applied easily.

It will make the real IPv6 series smaller and hopefully more amenable to review.

Well, I believe it's already split that way: patches 1, 2, 3, 6, 7, 8, 9, and 11 are all one-target cleanups which can be applied independently of the rest. Patches 4, 5, 10, 12, 13, 14, 15, and 16, which actually bring IPv6 support, are then mostly only line additions (only patch13 refactors things, but needs some rework to be applied right away).

The only thing I see could be separated out more is the reindentation.

Samuel

patch1-bugs

 udp.c |    1 +
 1 file changed, 1 insertion(+)

patch2-refactor

 if.c    |    2 -
 mbuf.c  |    2 -
 mbuf.h  |    2 -
 slirp.c |  107 +++++++++++++++++++++++++++++++++++++---------------------------
 slirp.h |   12 +++----
 5 files changed, 71 insertions(+), 54 deletions(-)

patch3-timer

 timer.h |   32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

patch6-socket-refactor

 ip_icmp.c   |    2 ++
 slirp.c     |   48 ++++++++++++++++++++++++++++++++++++++++--------
 socket.c    |   14 +++++++++++---
 socket.h    |   25 +++++++++++++++++++++----
 tcp_input.c |    2 ++
 tcp_subr.c  |    2 ++
 udp.c       |    4 ++++
 7 files changed, 82 insertions(+), 15 deletions(-)

patch7-socket-refactor2

 bootp.c    |    2 -
 ip_icmp.c  |   19 ++----------
 socket.c   |   93 +++++++++++++++++++++++++++++++++++++++++++++++--------------
 socket.h   |    3 +
 tcp_subr.c |   24 +++------------
 tftp.c     |    6 +--
 udp.c      |   27 -----------------
 udp.h      |    3 -
 8 files changed, 91 insertions(+), 86 deletions(-)

patch8-socket-refactor3

 socket.c    |   30 ++++++++++++++++--------------
 socket.h    |   30 +++++++++++++++++++++++++++++-
 tcp_input.c |   27 +++++++++++----------------
 udp.c       |   25 ++++++-------------------
 4 files changed, 62 insertions(+), 50 deletions(-)

patch9-udp-refactor

 ip_icmp.c |    2 +-
 udp.c     |    7 ++++---
 udp.h     |    2 +-
 3 files changed, 6 insertions(+), 5 deletions(-)

patch11-tcp-fconnect

 slirp.h     |    2 +-
 tcp_input.c |    3 ++-
 tcp_subr.c  |    5 +++--
 3 files changed, 6 insertions(+), 4 deletions(-)
#78 lore raw

Hello,

Quoted 8 lines · Samuel Thibault, le Thu 20 Mar 2014 10:03:20 +0100, a écrit :
Quoted 5 lines · Stefan Hajnoczi, le Thu 20 Mar 2014 08:58:11 +0100, a écrit :

My suggestion is to split all the preparation and cleanups into a smaller patch series that can be applied easily.

It will make the real IPv6 series smaller and hopefully more amenable to review.

Well, I believe it's already split that way

And even more so in the series I have sent on March 31st. Patches 1 to 8 there are small refactorings which should not take long to review. Patch 9 is a small addition. 10 to 18 bring the actual features.

Samuel