[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [RFC] slirp: Adding IPv6 NDP autoconfiguration
From: |
Guillaume Subiron |
Subject: |
Re: [Qemu-devel] [RFC] slirp: Adding IPv6 NDP autoconfiguration |
Date: |
Mon, 11 Mar 2013 22:29:07 +0100 |
User-agent: |
Mutt/1.5.20 (2009-06-14) |
I forgot to say, this patch is not rebased yet. Based on commit
7d2a929feba319c18603e324b1750830d6c8b7a1
Le Mon, Mar 11, 2013 at 07:26:17PM +0100, Guillaume Subiron claviotta :
> Hi,
>
> We are developing IPv6 in Qemu -net user case, starting with ICMPv6
> NDP.
>
> With this patch, a Debian guest can perform autoconfiguration using
> NDP. We have added a full IPv6->ICMPv6->NDP stack starting from
> slirp_input and based on slirp IPv6 implementation. In the end, SLIRP
> responds to Router Solicitations by sending the fc00:: prefix in a
> Router Advertisement and the host computes a global IPv6. SLIRP also
> responds to Neighbor Solicitations, of course.
> The next thing is to send Neighbor Solicitations when if_encap needs
> an IPv6 that is not in ndp_table, similarly to ARP.
>
> This patch will be cut into 2 subpatchs to follow the submit rules of
> Qemu (refactoring, then the NDP feature), but we'd like to get some
> feedback on the general approach, to know if we are going in the good
> direction.
>
> Our next goals are to develop ICMPv6 router ping (not external ping)
> and to adapt UDP.
>
> --
> Guillaume Subiron
> Mail - address@hidden
> GPG - C7C4 455C
> Jabber - address@hidden
> IRC - maethor@(freenode|geeknode)
> diff --git a/roms/seabios b/roms/seabios
> --- a/roms/seabios
> +++ b/roms/seabios
> @@ -1 +1 @@
> -Subproject commit 4bd8aebf3534e10d9aa21e820903f2cf9120708c
> +Subproject commit 4bd8aebf3534e10d9aa21e820903f2cf9120708c-dirty
> diff --git a/roms/vgabios b/roms/vgabios
> --- a/roms/vgabios
> +++ b/roms/vgabios
> @@ -1 +1 @@
> -Subproject commit 19ea12c230ded95928ecaef0db47a82231c2e485
> +Subproject commit 19ea12c230ded95928ecaef0db47a82231c2e485-dirty
> diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs
> index 2daa9dc..08ed5d8 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 icmp6.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..913dd7d 100644
> --- a/slirp/cksum.c
> +++ b/slirp/cksum.c
> @@ -137,3 +137,28 @@ 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/icmp6.c b/slirp/icmp6.c
> new file mode 100644
> index 0000000..64fb015
> --- /dev/null
> +++ b/slirp/icmp6.c
> @@ -0,0 +1,281 @@
> +#include "slirp.h"
> +#include "icmp6.h"
> +
> +/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
> +static const uint8_t special_ethaddr[ETH_ALEN] = {
> + 0x52, 0x55, 0x00, 0x00, 0x00, 0x00
> +};
> +
> +void icmp6_init(Slirp *slirp)
> +{
> + slirp->icmp6.so_next = slirp->icmp6.so_prev = &slirp->icmp6;
> + slirp->icmp6_last_so = &slirp->icmp6;
> +}
> +
> +void icmp6_cleanup(Slirp *slirp)
> +{
> + while (slirp->icmp6.so_next != &slirp->icmp6) {
> + icmp6_detach(slirp->icmp6.so_next);
> + }
> +}
> +
> +void icmp6_detach(struct socket *so)
> +{
> + closesocket(so->s);
> + sofree(so);
> +}
> +
> +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_ROUTER_SOL:
> + DEBUG_CALL(" type = Routeur Solicitation");
> + if (ip->ip_hl == 255
> + && icmp->icmp6_code == 0
> + && ip->ip_pl >= ICMP6_NDP_RS_MINLEN) {
> + // :TODO:maethor:130308: 2 check missing
> +
> + /* 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 = (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_LENGTH
> + + NDPOPT_PREFIXINFO_LENGTH);
> + 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_ROUTER_ADV;
> + 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_LENGTH / 8;
> + memcpy(opt->ndpopt_linklayer, special_ethaddr, ETH_ALEN - 4);
> + memcpy(&opt->ndpopt_linklayer[2], &slirp->vhost_addr, 4);
> +
> + /* Prefix information (NDP option) */
> + t->m_data += NDPOPT_LINKLAYER_LENGTH;
> + struct ndpopt *opt2 = mtod(t, struct ndpopt *);
> + opt2->ndpopt_type = NDPOPT_PREFIX_INFO;
> + opt2->ndpopt_len = NDPOPT_PREFIXINFO_LENGTH / 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_LENGTH;
> + t->m_data -= ICMP6_NDP_RA_MINLEN;
> + t->m_data -= sizeof(struct ip6);
> + ricmp->icmp6_cksum = ip6_cksum(t);
> +
> + ip6_output(NULL, t);
> + }
> + break;
> +
> + case ICMP6_NDP_ROUTER_ADV:
> + DEBUG_CALL(" type = Routeur Advertisement");
> + fprintf(stderr,
> + "Warning: guest sent NDP RA, but shouldn't\n");
> + break;
> +
> + case ICMP6_NDP_NEIGH_SOL:
> + DEBUG_CALL(" type = Neighbor Solicitation");
> + if (ip->ip_hl == 255
> + && icmp->icmp6_code == 0
> + && !in6_multicast(icmp->icmp6_nns.target)
> + && ip->ip_pl >= ICMP6_NDP_NS_MINLEN
> + && (!in6_unspecified(ip->ip_src)
> + || in6_multicast(ip->ip_dst))) {
> + // :TODO:maethor:130308: 1 check missing
> + 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_LENGTH);
> + 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_NEIGH_ADV;
> + 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_LENGTH / 8;
> + memcpy(opt->ndpopt_linklayer, special_ethaddr, ETH_ALEN
> - 4);
> + memcpy(&opt->ndpopt_linklayer[2], &slirp->vhost_addr, 4);
> +
> + /* 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);
> + }
> + }
> + break;
> +
> + case ICMP6_NDP_NEIGH_ADV:
> + DEBUG_CALL(" type = Neighbor Advertisement");
> + if (ip->ip_hl == 255
> + && icmp->icmp6_code == 0
> + && 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;
> +}
> +
> +/*
> + * 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 (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_NDP_ROUTER_SOL:
> + case ICMP6_NDP_ROUTER_ADV:
> + case ICMP6_NDP_NEIGH_SOL:
> + case ICMP6_NDP_NEIGH_ADV:
> + 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;
> + } /* swith */
> +
> +end:
> + m_free(m);
> + return;
> +}
> +
> +void icmp6_receive(struct socket *so)
> +{
> + struct mbuf *m = so->so_m;
> + int hlen = sizeof(struct ip6);
> + /*u_char error_code;*/
> + struct icmp6 *icmp;
> + int len;
> +
> + m->m_data += hlen;
> + m->m_len -= hlen;
> + icmp = mtod(m, struct icmp6 *);
> +
> + len = qemu_recv(so->s, icmp, m->m_len, 0);
> +
> + m->m_data -= hlen;
> + m->m_len += hlen;
> +
> + if (len == -1 || len == 0) {
> + /*
> + if (errno == ENETUNREACH) {
> + error_code = ICMP_UNREACH_NET;
> + } else {
> + error_code = ICMP_UNREACH_HOST;
> + }
> + 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));
> + */
> + } else {
> + /*icmp_reflect(so->so_m);*/
> + so->so_m = NULL; /* Don't m_free() it again! */
> + }
> + icmp6_detach(so);
> +}
> diff --git a/slirp/icmp6.h b/slirp/icmp6.h
> new file mode 100644
> index 0000000..7c6f253
> --- /dev/null
> +++ b/slirp/icmp6.h
> @@ -0,0 +1,234 @@
> +#ifndef _NETINET_ICMP6_H_
> +#define _NETINET_ICMP6_H_
> +
> +/*
> + * Interface Control Message Protocol version 6 Definitions.
> + * Per RFC 4443, March 2006.
> + */
> +
> +typedef uint32_t n_time;
> +
> +/*
> + * NDP Messages
> + */
> +struct ndp_router_sol {
> + uint32_t reserved;
> +};
> +
> +struct ndp_router_adv {
> + 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_neigh_sol {
> + uint32_t reserved;
> + struct in6_addr target; /* Target Address */
> +} QEMU_PACKED;
> +
> +struct ndp_neigh_adv {
> +#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 ndp_router_sol ndp_router_sol;
> + struct ndp_router_adv ndp_router_adv;
> + struct ndp_neigh_sol ndp_neigh_sol;
> + struct ndp_neigh_adv ndp_neigh_adv;
> + struct ndp_redirect ndp_redirect;
> + } icmp6_body;
> +#define icmp6_nrs icmp6_body.ndp_router_sol
> +#define icmp6_nra icmp6_body.ndp_router_adv
> +#define icmp6_nns icmp6_body.ndp_neigh_sol
> +#define icmp6_nna icmp6_body.ndp_neigh_adv
> +#define icmp6_redirect icmp6_body.ndp_redirect
> +} QEMU_PACKED;
> +
> +/*
> + * icmp6 + ip6 pseudo-header, used to compute et verify checksum.
> + */
> +struct icmp6ip6 {
> + struct ip6_pseudohdr ip6; /* overlaid ip structure */
> + struct icmp6 icmp6; /* tcp header */
> +};
> +
> +
> +#define ICMP6_MINLEN 4 /* abs minimum: 32 bits */
> +#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
> +
> +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 MTU 5 /* MTU */
> +
> +/* NDP options size, in octets. */
> +#define NDPOPT_LINKLAYER_LENGTH 8
> +#define NDPOPT_PREFIXINFO_LENGTH 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_ROUTER_SOL 133 /* Router Solicitation (NDP) */
> +#define ICMP6_NDP_ROUTER_ADV 134 /* Router Advertisement (NDP) */
> +#define ICMP6_NDP_NEIGH_SOL 135 /* Neighbor Solicitation (NDP) */
> +#define ICMP6_NDP_NEIGH_ADV 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_SOL 141 /* Inverse Neighbor Discovery Solicitation */
> +#define ICMP6_IND_ADV 142 /* Inverse Neighbor Discovery Advertisement
> */
> +#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_CP_SOL 148 /* Certification Path Solicitation (SEND) */
> +#define ICMP6_SEND_CP_ADV 149 /* Certification Path Advertisement (SEND) */
> +#define ICMP6_MRD_ADV 151 /* Multicast Router Advertisement (MRD) */
> +#define ICMP6_MRD_SOL 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:9)
> +#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 *);
> +void icmp6_error(struct mbuf *msrc, u_char type, u_char code, int minsize,
> + const char *message);
> +// :TODO:maethor:130307:
> +//void icmp6_reflect(struct mbuf *);
> +void icmp6_receive(struct socket *so);
> +void icmp6_detach(struct socket *so);
> +
> +#endif
> diff --git a/slirp/if.c b/slirp/if.c
> index dcd5faf..a957ce2 100644
> --- a/slirp/if.c
> +++ b/slirp/if.c
> @@ -158,7 +158,7 @@ void if_start(Slirp *slirp)
> bool from_batchq, next_from_batchq;
> struct mbuf *ifm, *ifm_next, *ifqt;
>
> - DEBUG_CALL("if_start");
> + /*DEBUG_CALL("if_start");*/
>
> if (slirp->if_start_busy) {
> return;
> @@ -193,7 +193,7 @@ void if_start(Slirp *slirp)
>
> /* Try to send packet unless it already expired */
> if (ifm->expiration_date >= now && !if_encap(slirp, ifm)) {
> - /* Packet is delayed due to pending ARP resolution */
> + /* Packet is delayed due to pending ARP or NDP resolution */
> continue;
> }
>
> diff --git a/slirp/ip6.h b/slirp/ip6.h
> new file mode 100644
> index 0000000..c853cd7
> --- /dev/null
> +++ b/slirp/ip6.h
> @@ -0,0 +1,98 @@
> +#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 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 (prefix_len % 8) {
> + assert(0); // ::TODO:maethor:130311: Manage this case
> + } else {
> + return (memcmp(&a, &b, prefix_len / 8) == 0);
> + }
> +}
> +
> +static inline int in6_equal_mach(struct in6_addr a, struct in6_addr b, int
> prefix_len) {
> + if (prefix_len % 8) {
> + assert(0); // :TODO:maethor:130311: Manage this case
> + } else {
> + return (memcmp(&(a.s6_addr[prefix_len / 8]),
> + &(b.s6_addr[prefix_len / 8]), 16 - prefix_len / 8) == 0);
> + }
> +}
> +
> +#define in6_equal_router(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->vhost_addr6, slirp->vprefix_len))
> +
> +#define in6_equal_dns(a) 0
> +
> +#define in6_equal_host(a)\
> + (in6_equal_router(a) || in6_equal_dns(a))
> +
> +typedef uint32_t n_long; /* long as received from the net */
> +
> +/*
> + * 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_input.c b/slirp/ip6_input.c
> new file mode 100644
> index 0000000..32b4ea2
> --- /dev/null
> +++ b/slirp/ip6_input.c
> @@ -0,0 +1,68 @@
> +#include <slirp.h>
> +#include <qemu/osdep.h>
> +#include "icmp6.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)
> +{
> + /*slirp->ipq.ip_link.next = slirp->ipq.ip_link.prev =
> &slirp->ipq.ip_link;*/
> + /*udp_init(slirp);*/
> + /*tcp_init(slirp);*/
> + icmp6_init(slirp);
> +}
> +
> +void ip6_cleanup(Slirp *slirp)
> +{
> + /*udp_cleanup(slirp);*/
> + /*tcp_cleanup(slirp);*/
> + icmp6_cleanup(slirp);
> +}
> +
> +void ip6_input(struct mbuf *m)
> +{
> + register struct ip6 *ip6;
> +
> + DEBUG_CALL("ip6_input");
> + DEBUG_ARG("m = %lx", (long)m);
> + DEBUG_ARG("m_len = %d", m->m_len);
> +
> + if (m->m_len < sizeof (struct ip6)) {
> + return;
> + }
> +
> + ip6 = mtod(m, struct ip6 *);
> +
> + if (ip6->ip_v != IP6VERSION) {
> + goto bad;
> + }
> +
> + /* check ip_ttl for a correct ICMP reply */
> + if(ip6->ip_hl==0) {
> + /*icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");*/ //
> :TODO:maethor:130307:
> + goto bad;
> + }
> +
> + /*
> + * Switch out to protocol's input routine.
> + */
> + switch (ip6->ip_nh) {
> + //case IPPROTO_TCP: :TODO:maethor:130307:
> + // tcp_input(m, hlen, (struct socket *)NULL);
> + // break;
> + //case IPPROTO_UDP:
> + // udp_input(m, hlen);
> + // break;
> + 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..e38b421
> --- /dev/null
> +++ b/slirp/ip6_output.c
> @@ -0,0 +1,29 @@
> +#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)
> +{
> + 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_output(so, m);
> +
> + return 0;
> +}
> diff --git a/slirp/mbuf.c b/slirp/mbuf.c
> index 4fefb04..92c429e 100644
> --- a/slirp/mbuf.c
> +++ b/slirp/mbuf.c
> @@ -91,7 +91,7 @@ m_get(Slirp *slirp)
> m->m_len = 0;
> m->m_nextpkt = NULL;
> m->m_prevpkt = NULL;
> - m->arp_requested = false;
> + m->resolution_requested = false;
> m->expiration_date = (uint64_t)-1;
> end_error:
> DEBUG_ARG("m = %lx", (long )m);
> diff --git a/slirp/mbuf.h b/slirp/mbuf.h
> index 3f3ab09..4110184 100644
> --- a/slirp/mbuf.h
> +++ b/slirp/mbuf.h
> @@ -82,7 +82,7 @@ struct m_hdr {
> struct mbuf {
> struct m_hdr m_hdr;
> Slirp *slirp;
> - bool arp_requested;
> + bool resolution_requested;
> uint64_t expiration_date;
> /* start of dynamic buffer area, must be last element */
> union M_dat {
> diff --git a/slirp/ndp_table.c b/slirp/ndp_table.c
> new file mode 100644
> index 0000000..b556d25
> --- /dev/null
> +++ b/slirp/ndp_table.c
> @@ -0,0 +1,79 @@
> +#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 0e6e232..e46212a 100644
> --- a/slirp/slirp.c
> +++ b/slirp/slirp.c
> @@ -135,8 +135,10 @@ int get_dns_addr(struct in_addr *pdns_addr)
> }
>
> f = fopen("/etc/resolv.conf", "r");
> - if (!f)
> + if (!f) {
> + fprintf(stderr, "Unable to open /etc/resolv.conf\n");
> return -1;
> + }
>
> #ifdef DEBUG
> lprint("IP address of your DNS(s): ");
> @@ -168,8 +170,10 @@ int get_dns_addr(struct in_addr *pdns_addr)
> }
> }
> fclose(f);
> - if (!found)
> + if (!found) {
> + fprintf(stderr, "No IPv4 found in /etc/resolv.conf\n");
> return -1;
> + }
> return 0;
> }
>
> @@ -214,6 +218,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 +226,9 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork,
> slirp->vnetwork_addr = vnetwork;
> slirp->vnetwork_mask = vnetmask;
> slirp->vhost_addr = vhost;
> + inet_pton(AF_INET6, "fc00::0", &slirp->vprefix_addr6); //
> :TODO:maethor:130311: Utiliser un argument passé à la fonction
> + slirp->vprefix_len = 64; //
> :TODO:maethor:130311: Utiliser un argument passé à la fonction
> + inet_pton(AF_INET6, "fc00::1", &slirp->vhost_addr6); //
> :TODO:maethor:130311: Utiliser un argument passé à la fonction
> if (vhostname) {
> pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
> vhostname);
> @@ -251,6 +259,7 @@ void slirp_cleanup(Slirp *slirp)
> unregister_savevm(NULL, "slirp", slirp);
>
> ip_cleanup(slirp);
> + ip6_cleanup(slirp);
> m_cleanup(slirp);
>
> g_free(slirp->vdnssearch);
> @@ -413,6 +422,31 @@ void slirp_select_fill(int *pnfds,
> UPD_NFDS(so->s);
> }
> }
> +
> + /*
> + * ICMPv6 sockets
> + */
> + for (so = slirp->icmp6.so_next; so != &slirp->icmp6;
> + so = so_next) {
> + so_next = so->so_next;
> +
> + /*
> + * See if it's timed out
> + */
> + if (so->so_expire) {
> + if (so->so_expire <= curtime) {
> + icmp6_detach(so);
> + continue;
> + } else {
> + do_slowtimo = 1; /* Let socket expire */
> + }
> + }
> +
> + if (so->so_state & SS_ISFCONNECTED) {
> + FD_SET(so->s, readfds);
> + UPD_NFDS(so->s);
> + }
> + }
> }
>
> *pnfds = nfds;
> @@ -594,6 +628,18 @@ void slirp_select_poll(fd_set *readfds, fd_set
> *writefds, fd_set *xfds,
> icmp_receive(so);
> }
> }
> +
> + /*
> + * Check incoming ICMPv6 relies.
> + */
> + for (so = slirp->icmp6.so_next; so != &slirp->icmp6;
> + so = so_next) {
> + so_next = so->so_next;
> +
> + if (so->s != -1 && FD_ISSET(so->s, readfds)) {
> + icmp6_receive(so);
> + }
> + }
> }
>
> if_start(slirp);
> @@ -682,6 +728,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;
> @@ -695,8 +742,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;
>
> + if (proto == ETH_P_IP) {
> ip_input(m);
> + } else if (proto == ETH_P_IP6) {
> + ip6_input(m);
> + }
> break;
> +
> default:
> break;
> }
> @@ -707,21 +759,26 @@ void slirp_input(Slirp *slirp, const uint8_t *pkt, int
> pkt_len)
> */
> int if_encap(Slirp *slirp, struct mbuf *ifm)
> {
> + DEBUG_CALL("if_encap");
> uint8_t buf[1600];
> 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;
> }
>
> + switch (iph->ip_v) {
> + case IPVERSION:
> if (!arp_table_search(slirp, iph->ip_dst.s_addr, ethaddr)) {
> uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
> struct ethhdr *reh = (struct ethhdr *)arp_req;
> struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
>
> - if (!ifm->arp_requested) {
> + if (!ifm->resolution_requested) {
> /* If the client addr is not known, send an ARP request
> */
> memset(reh->h_dest, 0xff, ETH_ALEN);
> memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
> @@ -747,23 +804,47 @@ int if_encap(Slirp *slirp, struct mbuf *ifm)
> rah->ar_tip = iph->ip_dst.s_addr;
> slirp->client_ipaddr = iph->ip_dst;
> slirp_output(slirp->opaque, arp_req, sizeof(arp_req));
> - ifm->arp_requested = true;
> + ifm->resolution_requested = true;
>
> /* Expire request and drop outgoing packet after 1
> second */
> ifm->expiration_date = qemu_get_clock_ns(rt_clock) +
> 1000000000ULL;
> }
> return 0;
> } else {
> + 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)) {
> + // :TODO:maethor:130311: NS
> + return 0;
> + } else {
> + eh->h_proto = htons(ETH_P_IP6);
> + }
> + break;
> +
> + default:
> + assert(0);
> + break;
> + }
> +
> memcpy(eh->h_dest, ethaddr, ETH_ALEN);
> memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
> /* XXX: not correct */
> memcpy(&eh->h_source[2], &slirp->vhost_addr, 4);
> - eh->h_proto = htons(ETH_P_IP);
> + DEBUG_ARGS((dfd, " SOURCE = %02x:%02x:%02x:%02x:%02x:%02x\n",
> + eh->h_source[0], eh->h_source[1], eh->h_source[2],
> + eh->h_source[3], eh->h_source[4], eh->h_source[5]));
> + DEBUG_ARGS((dfd, " DEST = %02x:%02x:%02x:%02x:%02x:%02x\n",
> + eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
> + eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]));
> memcpy(buf + sizeof(struct ethhdr), ifm->m_data, ifm->m_len);
> + printf("TAILLE: = %d\n", ifm->m_len);
> slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN);
> return 1;
> }
> -}
>
> /* Drop host forwarding rule, return 0 if found. */
> int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr,
> diff --git a/slirp/slirp.h b/slirp/slirp.h
> index fe0e65d..816a494 100644
> --- a/slirp/slirp.h
> +++ b/slirp/slirp.h
> @@ -138,12 +138,14 @@ void free(void *ptr);
>
> #include "libslirp.h"
> #include "ip.h"
> +#include "ip6.h"
> #include "tcp.h"
> #include "tcp_timer.h"
> #include "tcp_var.h"
> #include "tcpip.h"
> #include "udp.h"
> #include "ip_icmp.h"
> +#include "icmp6.h"
> #include "mbuf.h"
> #include "sbuf.h"
> #include "socket.h"
> @@ -163,6 +165,7 @@ 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 */
>
> #define ARPOP_REQUEST 1 /* ARP request */
> #define ARPOP_REPLY 2 /* ARP reply */
> @@ -201,6 +204,22 @@ 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;
>
> @@ -208,6 +227,9 @@ struct Slirp {
> struct in_addr vnetwork_addr;
> struct in_addr vnetwork_mask;
> struct in_addr vhost_addr;
> + struct in6_addr vprefix_addr6;
> + uint8_t vprefix_len;
> + struct in6_addr vhost_addr6;
> struct in_addr vdhcp_startaddr;
> struct in_addr vnameserver_addr;
>
> @@ -250,12 +272,15 @@ struct Slirp {
> /* icmp states */
> struct socket icmp;
> struct socket *icmp_last_so;
> + struct socket icmp6;
> + struct socket *icmp6_last_so;
>
> /* tftp states */
> char *tftp_prefix;
> struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
>
> ArpTable arp_table;
> + NdpTable ndp_table;
>
> void *opaque;
> };
> @@ -300,6 +325,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 *);
> @@ -315,6 +341,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 *);
> +
> /* tcp_input.c */
> void tcp_input(register struct mbuf *, int, struct socket *);
> int tcp_mss(register struct tcpcb *, u_int);
--
Guillaume Subiron
Mail - address@hidden
GPG - C7C4 455C
Jabber - address@hidden
IRC - maethor@(freenode|geeknode)