[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 04/16] slirp: Adding IPv6, ICMPv6 Echo and NDP autoc
From: |
Samuel Thibault |
Subject: |
[Qemu-devel] [PATCH 04/16] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration |
Date: |
Sun, 17 Nov 2013 16:04:36 +0100 |
This patch adds the functions needed to handle IPv6 packets. ICMPv6 and
NDP headers are implemented.
Slirp is now able to send NDP Router or Neighbor Advertisement when it
receives Router or Neighbor Solicitation. Using a 64bit-sized IPv6
prefix, the guest is now able to perform stateless autoconfiguration
(SLAAC) and to compute its IPv6 address.
This patch adds an ndp_table, mainly inspired by arp_table, to keep an
NDP cache and manage network address resolution.
Slirp regularly sends NDP Neighbor Advertisement, as recommended by the
RFC, to make the guest refresh its route.
This also adds ip6_cksum() to compute ICMPv6 checksums using IPv6
pseudo-header.
Signed-off-by: Guillaume Subiron <address@hidden>
Signed-off-by: Samuel Thibault <address@hidden>
---
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
diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs
index 2daa9dc..2dfe8e0 100644
--- a/slirp/Makefile.objs
+++ b/slirp/Makefile.objs
@@ -1,3 +1,3 @@
-common-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o dnssearch.o
+common-obj-y = cksum.o if.o ip_icmp.o ip6_icmp.o ip6_input.o ip6_output.o
ip_input.o ip_output.o dnssearch.o
common-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o
-common-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o
+common-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o
ndp_table.o
diff --git a/slirp/cksum.c b/slirp/cksum.c
index 6328660..f0a1398 100644
--- a/slirp/cksum.c
+++ b/slirp/cksum.c
@@ -137,3 +137,26 @@ cont:
REDUCE;
return (~sum & 0xffff);
}
+
+int ip6_cksum(struct mbuf *m)
+{
+ struct ip6 save_ip, *ip = mtod(m, struct ip6 *);
+ struct ip6_pseudohdr *ih = mtod(m, struct ip6_pseudohdr *);
+ int sum;
+
+ save_ip = *ip;
+
+ ih->ih_src = save_ip.ip_src;
+ ih->ih_dst = save_ip.ip_dst;
+ ih->ih_pl = htonl((uint32_t)ntohs(save_ip.ip_pl));
+ ih->ih_zero_hi = 0;
+ ih->ih_zero_lo = 0;
+ ih->ih_nh = save_ip.ip_nh;
+
+ sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr))
+ + ntohl(ih->ih_pl));
+
+ *ip = save_ip;
+
+ return sum;
+}
diff --git a/slirp/ip6.h b/slirp/ip6.h
new file mode 100644
index 0000000..16124ec
--- /dev/null
+++ b/slirp/ip6.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef _IP6_H_
+#define _IP6_H_
+
+#define in6_multicast(a) IN6_IS_ADDR_MULTICAST(&(a))
+#define in6_linklocal(a) IN6_IS_ADDR_LINKLOCAL(&(a))
+#define in6_unspecified(a) IN6_IS_ADDR_UNSPECIFIED(&(a))
+
+#define ALLNODES_MULTICAST { .s6_addr = \
+ { 0xff, 0x02, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x01 } }
+
+#define SOLICITED_NODE_PREFIX { .s6_addr = \
+ { 0xff, 0x02, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x01,\
+ 0xff, 0x00, 0x00, 0x00 } }
+
+#define LINKLOCAL_ADDR { .s6_addr = \
+ { 0xfe, 0x80, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x00,\
+ 0x00, 0x00, 0x00, 0x01 } }
+
+static inline int in6_equal(struct in6_addr a, struct in6_addr b)
+{
+ return memcmp(&a, &b, sizeof(a)) == 0;
+}
+
+static inline int in6_equal_net(struct in6_addr a, struct in6_addr b,
+ int prefix_len)
+{
+ if (memcmp(&a, &b, prefix_len / 8) != 0) {
+ return 0;
+ }
+
+ if (prefix_len % 8 == 0) {
+ return 1;
+ }
+
+ return (a.s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8)))
+ == (b.s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8)));
+}
+
+static inline int in6_equal_mach(struct in6_addr a, struct in6_addr b,
+ int prefix_len)
+{
+ if (memcmp(&(a.s6_addr[(prefix_len + 7) / 8]),
+ &(b.s6_addr[(prefix_len + 7) / 8]),
+ 16 - (prefix_len + 7) / 8) != 0) {
+ return 0;
+ }
+
+ if (prefix_len % 8 == 0) {
+ return 1;
+ }
+
+ return (a.s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 1))
+ == (b.s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 1));
+}
+
+#define in6_equal_router(a)\
+ ((in6_equal_net(a, slirp->vprefix_addr6, slirp->vprefix_len)\
+ && in6_equal_mach(a, slirp->vhost_addr6, slirp->vprefix_len))\
+ || (in6_equal_net(a, (struct in6_addr)LINKLOCAL_ADDR, 64)\
+ && in6_equal_mach(a, slirp->vhost_addr6, 64)))
+
+#define in6_equal_dns(a) 0
+
+#define in6_equal_host(a)\
+ (in6_equal_router(a) || in6_equal_dns(a))
+
+#define in6_solicitednode_multicast(a)\
+ (in6_equal_net(a, (struct in6_addr)SOLICITED_NODE_PREFIX, 104))
+
+/* Compute emulated host MAC address from its ipv6 address */
+static inline void in6_compute_ethaddr(struct in6_addr ip,
+ uint8_t eth[ETH_ALEN])
+{
+ eth[0] = 0x52;
+ eth[1] = 0x56;
+ memcpy(ð[2], &(ip.s6_addr[16-(ETH_ALEN-2)]), ETH_ALEN-2);
+}
+
+/*
+ * Definitions for internet protocol version 6.
+ * Per RFC 2460, December 1998.
+ */
+#define IP6VERSION 6
+#define IP6_HOP_LIMIT 255
+
+/*
+ * Structure of an internet header, naked of options.
+ */
+struct ip6 {
+#ifdef HOST_WORDS_BIGENDIAN
+ uint32_t
+ ip_v:4, /* version */
+ ip_tc_hi:4, /* traffic class */
+ ip_tc_lo:4,
+ ip_fl_hi:4, /* flow label */
+ ip_fl_lo:16;
+#else
+ uint32_t
+ ip_tc_hi:4,
+ ip_v:4,
+ ip_fl_hi:4,
+ ip_tc_lo:4,
+ ip_fl_lo:16;
+#endif
+ uint16_t ip_pl; /* payload length */
+ uint8_t ip_nh; /* next header */
+ uint8_t ip_hl; /* hop limit */
+ struct in6_addr ip_src, ip_dst; /* source and dest address */
+} QEMU_PACKED;
+
+/*
+ * IPv6 pseudo-header used by upper-layer protocols
+ */
+struct ip6_pseudohdr {
+ struct in6_addr ih_src; /* source internet address */
+ struct in6_addr ih_dst; /* destination internet address */
+ uint32_t ih_pl; /* upper-layer packet length */
+ uint16_t ih_zero_hi; /* zero */
+ uint8_t ih_zero_lo; /* zero */
+ uint8_t ih_nh; /* next header */
+} QEMU_PACKED;
+
+
+#endif
diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c
new file mode 100644
index 0000000..4538bfd
--- /dev/null
+++ b/slirp/ip6_icmp.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.h"
+#include "ip6_icmp.h"
+#include "qemu/timer.h"
+#include <stdlib.h>
+#include <time.h>
+
+#define rand_a_b(a, b)\
+ (rand()%(int)(b-a)+a)
+#define NDP_Interval rand_a_b(NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval)
+
+static void ra_timer_handler(void *opaque)
+{
+ Slirp *slirp = opaque;
+ timer_mod(slirp->ra_timer, qemu_clock_get_s(QEMU_CLOCK_VIRTUAL) +
NDP_Interval);
+ ndp_send_ra(slirp);
+}
+
+void icmp6_init(Slirp *slirp)
+{
+ srand(time(NULL));
+ slirp->ra_timer = timer_new_s(QEMU_CLOCK_VIRTUAL, ra_timer_handler, slirp);
+ timer_mod(slirp->ra_timer, qemu_clock_get_s(QEMU_CLOCK_VIRTUAL) +
NDP_Interval);
+}
+
+#undef NDP_Interval
+#undef rand_a_b
+
+void icmp6_cleanup(Slirp *slirp)
+{
+ timer_del(slirp->ra_timer);
+ timer_free(slirp->ra_timer);
+}
+
+static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
+ struct icmp6 *icmp)
+{
+ struct mbuf *t = m_get(slirp);
+ t->m_len = sizeof(struct ip6) + ntohs(ip->ip_pl);
+ memcpy(t->m_data, m->m_data, t->m_len);
+
+ /* IPv6 Packet */
+ struct ip6 *rip = mtod(t, struct ip6 *);
+ rip->ip_dst = ip->ip_src;
+ rip->ip_src = ip->ip_dst;
+
+ /* ICMPv6 packet */
+ t->m_data += sizeof(struct ip6);
+ struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+ ricmp->icmp6_type = ICMP6_ECHO_REPLY;
+ ricmp->icmp6_cksum = 0;
+
+ /* Checksum */
+ t->m_data -= sizeof(struct ip6);
+ ricmp->icmp6_cksum = ip6_cksum(t);
+
+ ip6_output(NULL, t, 0);
+}
+
+/*
+ * Process a NDP message
+ */
+static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
+ struct icmp6 *icmp)
+{
+ m->m_len += ETH_HLEN;
+ m->m_data -= ETH_HLEN;
+ struct ethhdr *eth = mtod(m, struct ethhdr *);
+ m->m_len -= ETH_HLEN;
+ m->m_data += ETH_HLEN;
+
+ switch (icmp->icmp6_type) {
+ case ICMP6_NDP_RS:
+ DEBUG_CALL(" type = Routeur Solicitation");
+ if (ip->ip_hl == 255
+ && icmp->icmp6_code == 0
+ && ntohs(ip->ip_pl) >= ICMP6_NDP_RS_MINLEN) {
+ /* Gratuitous NDP */
+ ndp_table_add(slirp, ip->ip_src, eth->h_source);
+
+ ndp_send_ra(slirp);
+ }
+ break;
+
+ case ICMP6_NDP_RA:
+ DEBUG_CALL(" type = Routeur Advertisement");
+ fprintf(stderr,
+ "Warning: guest sent NDP RA, but shouldn't\n");
+ break;
+
+ case ICMP6_NDP_NS:
+ DEBUG_CALL(" type = Neighbor Solicitation");
+ if (ip->ip_hl == 255
+ && icmp->icmp6_code == 0
+ && !in6_multicast(icmp->icmp6_nns.target)
+ && ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN
+ && (!in6_unspecified(ip->ip_src)
+ || in6_solicitednode_multicast(ip->ip_dst))) {
+ if (in6_equal_host(icmp->icmp6_nns.target)) {
+ /* Gratuitous NDP */
+ ndp_table_add(slirp, ip->ip_src, eth->h_source);
+
+ /* Build IPv6 packet */
+ struct mbuf *t = m_get(slirp);
+ struct ip6 *rip = mtod(t, struct ip6 *);
+ rip->ip_src = icmp->icmp6_nns.target;
+ if (in6_unspecified(ip->ip_src)) {
+ rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
+ } else {
+ rip->ip_dst = ip->ip_src;
+ }
+ rip->ip_nh = IPPROTO_ICMPV6;
+ rip->ip_pl = htons(ICMP6_NDP_NA_MINLEN
+ + NDPOPT_LINKLAYER_LEN);
+ t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
+
+ /* Build ICMPv6 packet */
+ t->m_data += sizeof(struct ip6);
+ struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+ ricmp->icmp6_type = ICMP6_NDP_NA;
+ ricmp->icmp6_code = 0;
+ ricmp->icmp6_cksum = 0;
+
+ /* NDP */
+ ricmp->icmp6_nna.R = NDP_IsRouter;
+ ricmp->icmp6_nna.S = !in6_multicast(rip->ip_dst);
+ ricmp->icmp6_nna.O = 1;
+ ricmp->icmp6_nna.reserved_hi = 0;
+ ricmp->icmp6_nna.reserved_lo = 0;
+ ricmp->icmp6_nna.target = icmp->icmp6_nns.target;
+
+ /* Build NDP option */
+ t->m_data += ICMP6_NDP_NA_MINLEN;
+ struct ndpopt *opt = mtod(t, struct ndpopt *);
+ opt->ndpopt_type = NDPOPT_LINKLAYER_TARGET;
+ opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
+ in6_compute_ethaddr(ricmp->icmp6_nna.target,
+ opt->ndpopt_linklayer);
+
+ /* ICMPv6 Checksum */
+ t->m_data -= ICMP6_NDP_NA_MINLEN;
+ t->m_data -= sizeof(struct ip6);
+ ricmp->icmp6_cksum = ip6_cksum(t);
+
+ ip6_output(NULL, t, 0);
+ }
+ }
+ break;
+
+ case ICMP6_NDP_NA:
+ DEBUG_CALL(" type = Neighbor Advertisement");
+ if (ip->ip_hl == 255
+ && icmp->icmp6_code == 0
+ && ntohs(ip->ip_pl) >= ICMP6_NDP_NA_MINLEN
+ && !in6_multicast(icmp->icmp6_nna.target)
+ && (!in6_multicast(ip->ip_dst) || icmp->icmp6_nna.S == 0)) {
+ ndp_table_add(slirp, ip->ip_src, eth->h_source);
+ }
+ break;
+
+ case ICMP6_NDP_REDIRECT:
+ DEBUG_CALL(" type = Redirect");
+ fprintf(stderr,
+ "Warning: guest sent NDP REDIRECT, but shouldn't\n");
+ break;
+
+ default:
+ return;
+ }
+ return;
+}
+
+/*
+ * Send NDP Router Advertisement
+ */
+void ndp_send_ra(Slirp *slirp)
+{
+ DEBUG_CALL("ndp_send_ra");
+
+ /* Build IPv6 packet */
+ struct mbuf *t = m_get(slirp);
+ struct ip6 *rip = mtod(t, struct ip6 *);
+ rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
+ rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
+ rip->ip_nh = IPPROTO_ICMPV6;
+ rip->ip_pl = htons(ICMP6_NDP_RA_MINLEN
+ + NDPOPT_LINKLAYER_LEN
+ + NDPOPT_PREFIXINFO_LEN);
+ t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
+
+ /* Build ICMPv6 packet */
+ t->m_data += sizeof(struct ip6);
+ struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+ ricmp->icmp6_type = ICMP6_NDP_RA;
+ ricmp->icmp6_code = 0;
+ ricmp->icmp6_cksum = 0;
+
+ /* NDP */
+ ricmp->icmp6_nra.chl = NDP_AdvCurHopLimit;
+ ricmp->icmp6_nra.M = NDP_AdvManagedFlag;
+ ricmp->icmp6_nra.O = NDP_AdvOtherConfigFlag;
+ ricmp->icmp6_nra.reserved = 0;
+ ricmp->icmp6_nra.lifetime = htons(NDP_AdvDefaultLifetime);
+ ricmp->icmp6_nra.reach_time = htonl(NDP_AdvReachableTime);
+ ricmp->icmp6_nra.retrans_time = htonl(NDP_AdvRetransTime);
+
+ /* Source link-layer address (NDP option) */
+ t->m_data += ICMP6_NDP_RA_MINLEN;
+ struct ndpopt *opt = mtod(t, struct ndpopt *);
+ opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
+ opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
+ in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer);
+
+ /* Prefix information (NDP option) */
+ t->m_data += NDPOPT_LINKLAYER_LEN;
+ struct ndpopt *opt2 = mtod(t, struct ndpopt *);
+ opt2->ndpopt_type = NDPOPT_PREFIX_INFO;
+ opt2->ndpopt_len = NDPOPT_PREFIXINFO_LEN / 8;
+ opt2->ndpopt_prefixinfo.prefix_length = slirp->vprefix_len;
+ opt2->ndpopt_prefixinfo.L = 1;
+ opt2->ndpopt_prefixinfo.A = 1;
+ opt2->ndpopt_prefixinfo.reserved1 = 0;
+ opt2->ndpopt_prefixinfo.valid_lt = htonl(NDP_AdvValidLifetime);
+ opt2->ndpopt_prefixinfo.pref_lt = htonl(NDP_AdvPrefLifetime);
+ opt2->ndpopt_prefixinfo.reserved2 = 0;
+ opt2->ndpopt_prefixinfo.prefix = slirp->vprefix_addr6;
+
+ /* ICMPv6 Checksum */
+ t->m_data -= NDPOPT_LINKLAYER_LEN;
+ t->m_data -= ICMP6_NDP_RA_MINLEN;
+ t->m_data -= sizeof(struct ip6);
+ ricmp->icmp6_cksum = ip6_cksum(t);
+
+ ip6_output(NULL, t, 0);
+}
+
+/*
+ * Send NDP Neighbor Solitication
+ */
+void ndp_send_ns(Slirp *slirp, struct in6_addr addr)
+{
+ char addrstr[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN);
+ DEBUG_CALL("ndp_send_ns");
+ DEBUG_ARG("target = %s", addrstr);
+
+ /* Build IPv6 packet */
+ struct mbuf *t = m_get(slirp);
+ struct ip6 *rip = mtod(t, struct ip6 *);
+ rip->ip_src = slirp->vhost_addr6;
+ rip->ip_dst = (struct in6_addr)SOLICITED_NODE_PREFIX;
+ memcpy(&rip->ip_dst.s6_addr[13], &addr.s6_addr[13], 3);
+ rip->ip_nh = IPPROTO_ICMPV6;
+ rip->ip_pl = htons(ICMP6_NDP_NS_MINLEN + NDPOPT_LINKLAYER_LEN);
+ t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
+
+ /* Build ICMPv6 packet */
+ t->m_data += sizeof(struct ip6);
+ struct icmp6 *ricmp = mtod(t, struct icmp6 *);
+ ricmp->icmp6_type = ICMP6_NDP_NS;
+ ricmp->icmp6_code = 0;
+ ricmp->icmp6_cksum = 0;
+
+ /* NDP */
+ ricmp->icmp6_nns.reserved = 0;
+ ricmp->icmp6_nns.target = addr;
+
+ /* Build NDP option */
+ t->m_data += ICMP6_NDP_NS_MINLEN;
+ struct ndpopt *opt = mtod(t, struct ndpopt *);
+ opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
+ opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
+ in6_compute_ethaddr(slirp->vhost_addr6, opt->ndpopt_linklayer);
+
+ /* ICMPv6 Checksum */
+ t->m_data -= ICMP6_NDP_NA_MINLEN;
+ t->m_data -= sizeof(struct ip6);
+ ricmp->icmp6_cksum = ip6_cksum(t);
+
+ ip6_output(NULL, t, 1);
+}
+
+/*
+ * Process a received ICMPv6 message.
+ */
+void icmp6_input(struct mbuf *m)
+{
+ struct icmp6 *icmp;
+ struct ip6 *ip = mtod(m, struct ip6 *);
+ Slirp *slirp = m->slirp;
+ int hlen = sizeof(struct ip6);
+
+ DEBUG_CALL("icmp6_input");
+ DEBUG_ARG("m = %lx", (long) m);
+ DEBUG_ARG("m_len = %d", m->m_len);
+
+ if (ntohs(ip->ip_pl) < ICMP6_MINLEN) {
+ goto end;
+ }
+
+ if (ip6_cksum(m)) {
+ goto end;
+ }
+
+ m->m_len -= hlen;
+ m->m_data += hlen;
+ icmp = mtod(m, struct icmp6 *);
+ m->m_len += hlen;
+ m->m_data -= hlen;
+
+ DEBUG_ARG("icmp6_type = %d", icmp->icmp6_type);
+ switch (icmp->icmp6_type) {
+ case ICMP6_ECHO_REQUEST:
+ if (in6_equal_host(ip->ip_dst)) {
+ icmp6_send_echoreply(m, slirp, ip, icmp);
+ } else {
+ /* TODO */
+ lprint("external icmpv6 not supported yet\n");
+ }
+ break;
+
+ case ICMP6_NDP_RS:
+ case ICMP6_NDP_RA:
+ case ICMP6_NDP_NS:
+ case ICMP6_NDP_NA:
+ case ICMP6_NDP_REDIRECT:
+ ndp_input(m, slirp, ip, icmp);
+ break;
+
+ case ICMP6_UNREACH:
+ case ICMP6_TOOBIG:
+ case ICMP6_TIMXCEED:
+ case ICMP6_PARAMPROB:
+ /* XXX? report error? close socket? */
+ default:
+ break;
+ }
+
+end:
+ m_free(m);
+ return;
+}
diff --git a/slirp/ip6_icmp.h b/slirp/ip6_icmp.h
new file mode 100644
index 0000000..bd9d3d9
--- /dev/null
+++ b/slirp/ip6_icmp.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#ifndef _NETINET_ICMP6_H_
+#define _NETINET_ICMP6_H_
+
+/*
+ * Interface Control Message Protocol version 6 Definitions.
+ * Per RFC 4443, March 2006.
+ *
+ * Network Discover Protocol Definitions.
+ * Per RFC 4861, September 2007.
+ */
+
+struct icmp6_echo { /* Echo Messages */
+ uint16_t id;
+ uint16_t seq_num;
+};
+
+/*
+ * NDP Messages
+ */
+struct ndp_rs { /* Router Solicitation Message */
+ uint32_t reserved;
+};
+
+struct ndp_ra { /* Router Advertisement Message */
+ uint8_t chl; /* Cur Hop Limit */
+#ifdef HOST_WORDS_BIGENDIAN
+ uint8_t
+ M:1,
+ O:1,
+ reserved:6;
+#else
+ uint8_t
+ reserved:6,
+ O:1,
+ M:1;
+#endif
+ uint16_t lifetime; /* Router Lifetime */
+ uint32_t reach_time; /* Reachable Time */
+ uint32_t retrans_time; /* Retrans Timer */
+} QEMU_PACKED;
+
+struct ndp_ns { /* Neighbor Solicitation Message */
+ uint32_t reserved;
+ struct in6_addr target; /* Target Address */
+} QEMU_PACKED;
+
+struct ndp_na { /* Neighbor Advertisement Message */
+#ifdef HOST_WORDS_BIGENDIAN
+ uint32_t
+ R:1, /* Router Flag */
+ S:1, /* Solicited Flag */
+ O:1, /* Override Flag */
+ reserved_hi:5,
+ reserved_lo:24;
+#else
+ uint32_t
+ reserved_hi:5,
+ O:1,
+ S:1,
+ R:1,
+ reserved_lo:24;
+#endif
+ struct in6_addr target; /* Target Address */
+} QEMU_PACKED;
+
+struct ndp_redirect {
+ uint32_t reserved;
+ struct in6_addr target; /* Target Address */
+ struct in6_addr dest; /* Destination Address */
+} QEMU_PACKED;
+
+/*
+ * Structure of an icmpv6 header.
+ */
+struct icmp6 {
+ uint8_t icmp6_type; /* type of message, see below */
+ uint8_t icmp6_code; /* type sub code */
+ uint16_t icmp6_cksum; /* ones complement cksum of struct */
+ union {
+ struct icmp6_echo echo;
+ struct ndp_rs ndp_rs;
+ struct ndp_ra ndp_ra;
+ struct ndp_ns ndp_ns;
+ struct ndp_na ndp_na;
+ struct ndp_redirect ndp_redirect;
+ } icmp6_body;
+#define icmp6_echo icmp6_body.echo
+#define icmp6_nrs icmp6_body.ndp_rs
+#define icmp6_nra icmp6_body.ndp_ra
+#define icmp6_nns icmp6_body.ndp_ns
+#define icmp6_nna icmp6_body.ndp_na
+#define icmp6_redirect icmp6_body.ndp_redirect
+} QEMU_PACKED;
+
+#define ICMP6_MINLEN 4
+#define ICMP6_ECHO_MINLEN 8
+#define ICMP6_NDP_RS_MINLEN 8
+#define ICMP6_NDP_RA_MINLEN 16
+#define ICMP6_NDP_NS_MINLEN 24
+#define ICMP6_NDP_NA_MINLEN 24
+#define ICMP6_NDP_REDIRECT_MINLEN 40
+
+/*
+ * NDP Options
+ */
+struct ndpopt {
+ uint8_t ndpopt_type; /* Option type */
+ uint8_t ndpopt_len; /* /!\ In units of 8 octets */
+ union {
+ unsigned char linklayer_addr[6]; /* Source/Target Link-layer */
+ struct prefixinfo { /* Prefix Information */
+ uint8_t prefix_length;
+#ifdef HOST_WORDS_BIGENDIAN
+ uint8_t L:1, A:1, reserved1:6;
+#else
+ uint8_t reserved1:6, A:1, L:1;
+#endif
+ uint32_t valid_lt; /* Valid Lifetime */
+ uint32_t pref_lt; /* Preferred Lifetime */
+ uint32_t reserved2;
+ struct in6_addr prefix;
+ } QEMU_PACKED prefixinfo;
+ } ndpopt_body;
+#define ndpopt_linklayer ndpopt_body.linklayer_addr
+#define ndpopt_prefixinfo ndpopt_body.prefixinfo
+} QEMU_PACKED;
+
+/* NDP options type */
+#define NDPOPT_LINKLAYER_SOURCE 1 /* Source Link-Layer Address */
+#define NDPOPT_LINKLAYER_TARGET 2 /* Target Link-Layer Address */
+#define NDPOPT_PREFIX_INFO 3 /* Prefix Information */
+#define NDPOPT_REDIRECTED_HDR 4 /* Redirected Header */
+#define NDPOPT_MTU 5 /* MTU */
+
+/* NDP options size, in octets. */
+#define NDPOPT_LINKLAYER_LEN 8
+#define NDPOPT_PREFIXINFO_LEN 32
+
+/*
+ * Definition of type and code field values.
+ * Per https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml
+ * Last Updated 2012-11-12
+ */
+
+/* Errors */
+#define ICMP6_UNREACH 1 /* Destination Unreachable */
+#define ICMP6_UNREACH_NO_ROUTE 0 /* no route to dest */
+#define ICMP6_UNREACH_DEST_PROHIB 1 /* com with dest prohibited */
+#define ICMP6_UNREACH_SCOPE 2 /* beyond scope of src addr */
+#define ICMP6_UNREACH_ADDRESS 3 /* address unreachable */
+#define ICMP6_UNREACH_PORT 4 /* port unreachable */
+#define ICMP6_UNREACH_SRC_FAIL 5 /* src addr failed */
+#define ICMP6_UNREACH_REJECT_ROUTE 6 /* reject route to dest */
+#define ICMP6_UNREACH_SRC_HDR_ERROR 7 /* error in src routing header */
+#define ICMP6_TOOBIG 2 /* Packet Too Big */
+#define ICMP6_TIMXCEED 3 /* Time Exceeded */
+#define ICMP6_TIMXCEED_INTRANS 0 /* hop limit exceeded in transit */
+#define ICMP6_TIMXCEED_REASS 1 /* ttl=0 in reass */
+#define ICMP6_PARAMPROB 4 /* Parameter Problem */
+#define ICMP6_PARAMPROB_HDR_FIELD 0 /* err header field */
+#define ICMP6_PARAMPROB_NXTHDR_TYPE 1 /* unrecognized Next Header type */
+#define ICMP6_PARAMPROB_IPV6_OPT 2 /* unrecognized IPv6 option */
+
+/* Informational Messages */
+#define ICMP6_ECHO_REQUEST 128 /* Echo Request */
+#define ICMP6_ECHO_REPLY 129 /* Echo Reply */
+#define ICMP6_MCASTLST_QUERY 130 /* Multicast Listener Query */
+#define ICMP6_MCASTLST_REPORT 131 /* Multicast Listener Report */
+#define ICMP6_MCASTLST_DONE 132 /* Multicast Listener Done */
+#define ICMP6_NDP_RS 133 /* Router Solicitation (NDP) */
+#define ICMP6_NDP_RA 134 /* Router Advertisement (NDP) */
+#define ICMP6_NDP_NS 135 /* Neighbor Solicitation (NDP) */
+#define ICMP6_NDP_NA 136 /* Neighbor Advertisement (NDP) */
+#define ICMP6_NDP_REDIRECT 137 /* Redirect Message (NDP) */
+#define ICMP6_ROUTERRENUM 138 /* Router Renumbering */
+#define ICMP6_ROUTERRENUM_COMMAND 0 /* router renum command */
+#define ICMP6_ROUTERRENUM_RESULT 1 /* router renum result */
+#define ICMP6_ROUTERRENUM_RESET 255 /* sequence number reset */
+#define ICMP6_NODEINFO_QUERY 139 /* ICMP Node Information Query */
+#define ICMP6_NODEINFO_QUERY_IPV6 0 /* subject is an IPv6 */
+#define ICMP6_NODEINFO_QUERY_NAME 1 /* subj is a name (or empty) */
+#define ICMP6_NODEINFO_QUERY_IPV4 2 /* subject is an IPv4 */
+#define ICMP6_NODEINFO_RESP 140 /* ICMP Node Information Response */
+#define ICMP6_NODEINFO_RESP_SUCCESS 0 /* successful reply */
+#define ICMP6_NODEINFO_RESP_REFUSAL 1 /* refuses to supply answer */
+#define ICMP6_NODEINFO_RESP_UNKNOWN 2 /* Qtype unknown to the resp */
+#define ICMP6_IND_S 141 /* Inverse Neighbor Discovery Sol. */
+#define ICMP6_IND_A 142 /* Inverse Neighbor Discovery Adv. */
+#define ICMP6_MLD 143 /* Multicast Listener Discovery reports */
+#define ICMP6_HAAD_REQUEST 144 /* Home Agent Address Discovery Request */
+#define ICMP6_HAAD_REPLY 145 /* Home Agent Address Discovery Reply */
+#define ICMP6_MP_SOL 146 /* Mobile Prefix Solicitation */
+#define ICMP6_MP_ADV 147 /* Mobile Prefix Advertisement */
+#define ICMP6_SEND_CPS 148 /* Certification Path Solicitation (SEND)
*/
+#define ICMP6_SEND_CPA 149 /* Certification Path Adv. (SEND) */
+#define ICMP6_MRD_RA 151 /* Multicast Router Advertisement (MRD) */
+#define ICMP6_MRD_RS 152 /* Multicast Router Solicitation (MRD) */
+#define ICMP6_MRD_TERM 153 /* Multicast Router Termination (MRD) */
+#define ICMP6_FMIP6 154 /* FMIPv6 Messages */
+#define ICMP6_FMIP6_RTSOLPR 2 /* RtSolPr */
+#define ICMP6_FMIP6_PRRTADV 3 /* PrRtAdv */
+#define ICMP6_RPL_CONTROL 155 /* RPL Control Message */
+#define ICMP6_ILNP6_LU 156 /* ILNPv6 Locator Update Message */
+#define ICMP6_DUPADDR_REQUEST 157 /* Duplicate Address Request */
+#define ICMP6_DUPADDR_CONFIRM 158 /* Duplicate Address Confirmation */
+
+#define ICMP6_INFOTYPE(type) ((type) >= 128)
+
+/*
+ * Router Configuration Variables (rfc4861#section-6)
+ */
+#define NDP_IsRouter 1
+#define NDP_AdvSendAdvertisements 1
+#define NDP_MaxRtrAdvInterval 600
+#define NDP_MinRtrAdvInterval ((NDP_MaxRtrAdvInterval >= 9) ? \
+ 0.33*NDP_MaxRtrAdvInterval : \
+ NDP_MaxRtrAdvInterval)
+#define NDP_AdvManagedFlag 0
+#define NDP_AdvOtherConfigFlag 0
+#define NDP_AdvLinkMTU 0
+#define NDP_AdvReachableTime 0
+#define NDP_AdvRetransTime 0
+#define NDP_AdvCurHopLimit 64
+#define NDP_AdvDefaultLifetime (3 * NDP_MaxRtrAdvInterval)
+#define NDP_AdvValidLifetime 86400
+#define NDP_AdvOnLinkFlag 1
+#define NDP_AdvPrefLifetime 14400
+#define NDP_AdvAutonomousFlag 1
+
+void icmp6_init(Slirp *slirp);
+void icmp6_cleanup(Slirp *slirp);
+void icmp6_input(struct mbuf *);
+/* :TODO:maethor:130312: icmp6_error
+void icmp6_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
+ const char *message);
+*/
+void ndp_send_ra(Slirp *slirp);
+void ndp_send_ns(Slirp *slirp, struct in6_addr addr);
+
+#endif
diff --git a/slirp/ip6_input.c b/slirp/ip6_input.c
new file mode 100644
index 0000000..9663c42
--- /dev/null
+++ b/slirp/ip6_input.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+#include <qemu/osdep.h>
+#include "ip6_icmp.h"
+
+/*
+ * IP initialization: fill in IP protocol switch table.
+ * All protocols not implemented in kernel go to raw IP protocol handler.
+ */
+void ip6_init(Slirp *slirp)
+{
+ icmp6_init(slirp);
+}
+
+void ip6_cleanup(Slirp *slirp)
+{
+ icmp6_cleanup(slirp);
+}
+
+void ip6_input(struct mbuf *m)
+{
+ struct ip6 *ip6;
+
+ DEBUG_CALL("ip6_input");
+ DEBUG_ARG("m = %lx", (long)m);
+ DEBUG_ARG("m_len = %d", m->m_len);
+
+ if (m->m_len < sizeof(struct ip6)) {
+ return;
+ }
+
+ ip6 = mtod(m, struct ip6 *);
+
+ if (ip6->ip_v != IP6VERSION) {
+ goto bad;
+ }
+
+ /* check ip_ttl for a correct ICMP reply */
+ if (ip6->ip_hl == 0) {
+ /* :TODO:maethor:130307: icmp6_error */
+ /*icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");*/
+ goto bad;
+ }
+
+ /*
+ * Switch out to protocol's input routine.
+ */
+ switch (ip6->ip_nh) {
+#if 0
+ case IPPROTO_TCP:
+ /* :TODO:maethor:130307: TCP */
+ tcp_input(m, hlen, (struct socket *)NULL);
+ break;
+ case IPPROTO_UDP:
+ /* :TODO:maethor:130312: UDP */
+ udp_input(m, hlen);
+ break;
+#endif
+ case IPPROTO_ICMPV6:
+ icmp6_input(m);
+ break;
+ default:
+ m_free(m);
+ }
+ return;
+bad:
+ m_free(m);
+}
diff --git a/slirp/ip6_output.c b/slirp/ip6_output.c
new file mode 100644
index 0000000..178a968
--- /dev/null
+++ b/slirp/ip6_output.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include <slirp.h>
+
+/* Number of packets queued before we start sending
+ * (to prevent allocing too many mbufs) */
+#define IF6_THRESH 10
+
+/*
+ * IPv6 output. The packet in mbuf chain m contains a IP header
+ */
+int ip6_output(struct socket *so, struct mbuf *m, int fast)
+{
+ struct ip6 *ip = mtod(m, struct ip6 *);
+
+ DEBUG_CALL("ip6_output");
+ DEBUG_ARG("so = %lx", (long)so);
+ DEBUG_ARG("m = %lx", (long)m);
+
+ /* Fill IPv6 header */
+ ip->ip_v = IP6VERSION;
+ ip->ip_hl = IP6_HOP_LIMIT;
+ ip->ip_tc_hi = 0;
+ ip->ip_tc_lo = 0;
+ ip->ip_fl_hi = 0;
+ ip->ip_fl_lo = 0;
+
+ if (fast) {
+ if_encap(m->slirp, m);
+ } else {
+ if_output(so, m);
+ }
+
+ return 0;
+}
diff --git a/slirp/ndp_table.c b/slirp/ndp_table.c
new file mode 100644
index 0000000..0a091bc
--- /dev/null
+++ b/slirp/ndp_table.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2013
+ * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
+ *
+ * Please read the file COPYRIGHT for the
+ * terms and conditions of the copyright.
+ */
+
+#include "slirp.h"
+
+void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
+ uint8_t ethaddr[ETH_ALEN])
+{
+ NdpTable *ndp_table = &slirp->ndp_table;
+ int i;
+ char addrstr[INET6_ADDRSTRLEN];
+
+ DEBUG_CALL("ndp_table_add");
+ inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
+ DEBUG_ARG("ip = %s", addrstr);
+ DEBUG_ARGS((dfd, " hw addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ethaddr[0], ethaddr[1], ethaddr[2],
+ ethaddr[3], ethaddr[4], ethaddr[5]));
+
+ if (in6_multicast(ip_addr) || in6_unspecified(ip_addr)) {
+ /* Do not register multicast or unspecified addresses */
+ DEBUG_CALL(" abort: do not register multicast or unspecified address");
+ return;
+ }
+
+ /* Search for an entry */
+ for (i = 0; i < NDP_TABLE_SIZE; i++) {
+ if (in6_equal(ndp_table->table[i].ip_addr, ip_addr)) {
+ DEBUG_CALL(" already in table: update the entry");
+ /* Update the entry */
+ memcpy(ndp_table->table[i].eth_addr, ethaddr, ETH_ALEN);
+ return;
+ }
+ }
+
+ /* No entry found, create a new one */
+ DEBUG_CALL(" create new entry");
+ ndp_table->table[ndp_table->next_victim].ip_addr = ip_addr;
+ memcpy(ndp_table->table[ndp_table->next_victim].eth_addr,
+ ethaddr, ETH_ALEN);
+ ndp_table->next_victim = (ndp_table->next_victim + 1) % NDP_TABLE_SIZE;
+}
+
+bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
+ uint8_t out_ethaddr[ETH_ALEN])
+{
+ NdpTable *ndp_table = &slirp->ndp_table;
+ int i;
+ char addrstr[INET6_ADDRSTRLEN];
+
+ DEBUG_CALL("ndp_table_search");
+ inet_ntop(AF_INET6, &(ip_addr), addrstr, INET6_ADDRSTRLEN);
+ DEBUG_ARG("ip = %s", addrstr);
+
+ assert(!in6_unspecified(ip_addr));
+
+ /* Multicast address: fc00::abcd:efgh/8 -> 33:33:ab:cd:ef:gh */
+ if (in6_multicast(ip_addr)) {
+ out_ethaddr[0] = 0x33; out_ethaddr[1] = 0x33;
+ out_ethaddr[2] = ip_addr.s6_addr[12];
+ out_ethaddr[3] = ip_addr.s6_addr[13];
+ out_ethaddr[4] = ip_addr.s6_addr[14];
+ out_ethaddr[5] = ip_addr.s6_addr[15];
+ DEBUG_ARGS((dfd, " multicast addr = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+ out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]));
+ return 1;
+ }
+
+ for (i = 0; i < NDP_TABLE_SIZE; i++) {
+ if (in6_equal(ndp_table->table[i].ip_addr, ip_addr)) {
+ memcpy(out_ethaddr, ndp_table->table[i].eth_addr, ETH_ALEN);
+ DEBUG_ARGS((dfd, " found hw addr =
%02x:%02x:%02x:%02x:%02x:%02x\n",
+ out_ethaddr[0], out_ethaddr[1], out_ethaddr[2],
+ out_ethaddr[3], out_ethaddr[4], out_ethaddr[5]));
+ return 1;
+ }
+ }
+
+ DEBUG_CALL(" ip not found in table");
+ return 0;
+}
diff --git a/slirp/slirp.c b/slirp/slirp.c
index bfc4832..f5e46fb 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -214,6 +214,7 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
if_init(slirp);
ip_init(slirp);
+ ip6_init(slirp);
/* Initialise mbufs *after* setting the MTU */
m_init(slirp);
@@ -221,6 +222,12 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
slirp->vnetwork_addr = vnetwork;
slirp->vnetwork_mask = vnetmask;
slirp->vhost_addr = vhost;
+ /* :TODO:maethor:130311: Use a parameter passed to the function */
+ inet_pton(AF_INET6, "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);
if (vhostname) {
pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
vhostname);
@@ -251,6 +258,7 @@ void slirp_cleanup(Slirp *slirp)
unregister_savevm(NULL, "slirp", slirp);
ip_cleanup(slirp);
+ ip6_cleanup(slirp);
m_cleanup(slirp);
g_free(slirp->vdnssearch);
@@ -744,6 +752,7 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int
pkt_len)
arp_input(slirp, pkt, pkt_len);
break;
case ETH_P_IP:
+ case ETH_P_IP6:
m = m_get(slirp);
if (!m)
return;
@@ -757,8 +766,13 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int
pkt_len)
m->m_data += 2 + ETH_HLEN;
m->m_len -= 2 + ETH_HLEN;
- ip_input(m);
+ if (proto == ETH_P_IP) {
+ ip_input(m);
+ } else if (proto == ETH_P_IP6) {
+ ip6_input(m);
+ }
break;
+
default:
break;
}
@@ -773,6 +787,8 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
struct ethhdr *eh = (struct ethhdr *)buf;
uint8_t ethaddr[ETH_ALEN];
const struct ip *iph = (const struct ip *)ifm->m_data;
+ const struct ip6 *ip6h = mtod(ifm, const struct ip6 *);
+ char addrstr[INET6_ADDRSTRLEN];
if (ifm->m_len + ETH_HLEN > sizeof(buf)) {
return 1;
@@ -817,18 +833,33 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
ifm->expiration_date =
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL;
}
+ return 0;
+ } else {
+ memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
+ /* XXX: not correct */
+ memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
+ eh->h_proto = htons(ETH_P_IP);
+ break;
+ }
+
+ case IP6VERSION:
+ inet_ntop(AF_INET6, &(ip6h->ip_dst), addrstr, INET6_ADDRSTRLEN);
+ if (!ndp_table_search(slirp, ip6h->ip_dst, ethaddr)) {
+ if (!ifm->resolution_requested) {
+ ndp_send_ns(slirp, ip6h->ip_dst);
+ ifm->resolution_requested = true;
+ ifm->expiration_date =
+ qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL;
+ }
return 0;
} else {
- memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
- /* XXX: not correct */
- memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
- eh->h_proto = htons(ETH_P_IP);
- break;
+ eh->h_proto = htons(ETH_P_IP6);
+ in6_compute_ethaddr(ip6h->ip_src, eh->h_source);
}
+ break;
default:
- /* Do not assert while we don't manage IP6VERSION */
- /* assert(0); */
+ assert(0);
break;
}
diff --git a/slirp/slirp.h b/slirp/slirp.h
index cd9f2d0..ec9cbed 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -141,15 +141,18 @@ void free(void *ptr);
#define ETH_P_IP 0x0800 /* Internet Protocol packet */
#define ETH_P_ARP 0x0806 /* Address Resolution packet */
+#define ETH_P_IP6 0x86DD /* IPv6 packet */
#include "libslirp.h"
#include "ip.h"
+#include "ip6.h"
#include "tcp.h"
#include "tcp_timer.h"
#include "tcp_var.h"
#include "tcpip.h"
#include "udp.h"
#include "ip_icmp.h"
+#include "ip6_icmp.h"
#include "mbuf.h"
#include "sbuf.h"
#include "socket.h"
@@ -201,6 +204,23 @@ void arp_table_add(Slirp *slirp, uint32_t ip_addr, uint8_t
ethaddr[ETH_ALEN]);
bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
uint8_t out_ethaddr[ETH_ALEN]);
+struct ndpentry {
+ unsigned char eth_addr[ETH_ALEN]; /* sender hardware address */
+ struct in6_addr ip_addr; /* sender IP address */
+} QEMU_PACKED;
+
+#define NDP_TABLE_SIZE 16
+
+typedef struct NdpTable {
+ struct ndpentry table[NDP_TABLE_SIZE];
+ int next_victim;
+} NdpTable;
+
+void ndp_table_add(Slirp *slirp, struct in6_addr ip_addr,
+ uint8_t ethaddr[ETH_ALEN]);
+bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,
+ uint8_t out_ethaddr[ETH_ALEN]);
+
struct Slirp {
QTAILQ_ENTRY(Slirp) entry;
u_int time_fasttimo;
@@ -211,6 +231,9 @@ struct Slirp {
struct in_addr vnetwork_addr;
struct in_addr vnetwork_mask;
struct in_addr vhost_addr;
+ struct in6_addr vprefix_addr6;
+ uint8_t vprefix_len;
+ struct in6_addr vhost_addr6;
struct in_addr vdhcp_startaddr;
struct in_addr vnameserver_addr;
@@ -259,6 +282,9 @@ struct Slirp {
struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
ArpTable arp_table;
+ NdpTable ndp_table;
+
+ QEMUTimer *ra_timer;
void *opaque;
};
@@ -303,6 +329,7 @@ int translate_dnssearch(Slirp *s, const char ** names);
/* cksum.c */
int cksum(struct mbuf *m, int len);
+int ip6_cksum(struct mbuf *m);
/* if.c */
void if_init(Slirp *);
@@ -318,6 +345,14 @@ void ip_stripoptions(register struct mbuf *, struct mbuf
*);
/* ip_output.c */
int ip_output(struct socket *, struct mbuf *);
+/* ip6_input.c */
+void ip6_init(Slirp *);
+void ip6_cleanup(Slirp *);
+void ip6_input(struct mbuf *);
+
+/* ip6_output */
+int ip6_output(struct socket *, struct mbuf *, int fast);
+
/* tcp_input.c */
void tcp_input(register struct mbuf *, int, struct socket *);
int tcp_mss(register struct tcpcb *, u_int);
--
1.8.4.2
- [Qemu-devel] [PATCHv2 00/16] slirp: Adding IPv6 support to Qemu -net user mode, Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 02/16] slirp: Generalizing and neutralizing code before adding IPv6 stuff, Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 03/16] qemu/timer.h : Adding function to second scale, Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 09/16] slirp: Make udp_attach IPv6 compatible, Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 06/16] slirp: Make Socket structure IPv6 compatible, Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 08/16] slirp: Factorizing and cleaning solookup(), Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 04/16] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration,
Samuel Thibault <=
- [Qemu-devel] [PATCH 01/16] slirp: goto bad in udp_input if sosendto fails, Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 07/16] slirp: Factorizing address translation, Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 10/16] slirp: Adding IPv6 UDP support, Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 15/16] slirp: Adding IPv6 address for DNS relay, Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 11/16] slirp: Adding family argument to tcp_fconnect(), Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 12/16] slirp: Factorizing tcpiphdr structure with an union, Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 14/16] slirp: Handle IPv6 in TCP functions, Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 05/16] slirp: Adding ICMPv6 error sending, Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 13/16] slirp: Generalizing and neutralizing various TCP functions before adding IPv6 stuff, Samuel Thibault, 2013/11/17
- [Qemu-devel] [PATCH 16/16] qapi-schema, qemu-options & slirp: Adding Qemu options for IPv6 addresses, Samuel Thibault, 2013/11/17