From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:58771) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UFAHV-0007MJ-IS for qemu-devel@nongnu.org; Mon, 11 Mar 2013 17:29:26 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UFAHN-0003Aa-2u for qemu-devel@nongnu.org; Mon, 11 Mar 2013 17:29:17 -0400 Received: from galactus.lahouze.org ([88.191.120.158]:38656) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UFAHM-0003AQ-GC for qemu-devel@nongnu.org; Mon, 11 Mar 2013 17:29:09 -0400 Date: Mon, 11 Mar 2013 22:29:07 +0100 From: Guillaume Subiron Message-ID: <20130311212906.GB20436@subiron.org> References: <20130311182617.GA20436@subiron.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: <20130311182617.GA20436@subiron.org> Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [RFC] slirp: Adding IPv6 NDP autoconfiguration List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org, jan.kiszka@siemens.com, ped@listes.subiron.org 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,=20 >=20 > We are developing IPv6 in Qemu -net user case, starting with ICMPv6 > NDP. =20 >=20 > 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.=20 > The next thing is to send Neighbor Solicitations when if_encap needs > an IPv6 that is not in ndp_table, similarly to ARP. =20 >=20 > 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. =20 >=20 > Our next goals are to develop ICMPv6 router ping (not external ping) > and to adapt UDP. >=20 > --=20 > Guillaume Subiron=20 > Mail - maethor@subiron.org > GPG - C7C4 455C > Jabber - maethor@im.subiron.org > 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 =3D cksum.o if.o ip_icmp.o ip_input.o ip_output.o dnssear= ch.o > +common-obj-y =3D 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 +=3D slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tc= p_output.o > -common-obj-y +=3D tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_tabl= e.o > +common-obj-y +=3D tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_tabl= e.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 =3D mtod(m, struct ip6 *); > + struct ip6_pseudohdr *ih =3D mtod(m, struct ip6_pseudohdr *); > + int sum; > + > + save_ip =3D *ip; > + > + ih->ih_src =3D save_ip.ip_src; > + ih->ih_dst =3D save_ip.ip_dst; > + ih->ih_pl =3D htonl((uint32_t)ntohs(save_ip.ip_pl)); > + ih->ih_zero_hi =3D 0; > + ih->ih_zero_lo =3D 0; > + ih->ih_nh =3D save_ip.ip_nh; > + > + sum =3D cksum(m, ((int)sizeof(struct ip6_pseudohdr))=20 > + + ntohl(ih->ih_pl));=20 > + =20 > + *ip =3D 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] =3D { > + 0x52, 0x55, 0x00, 0x00, 0x00, 0x00 > +}; > + > +void icmp6_init(Slirp *slirp) > +{ > + slirp->icmp6.so_next =3D slirp->icmp6.so_prev =3D &slirp->icmp6; > + slirp->icmp6_last_so =3D &slirp->icmp6; > +} > + > +void icmp6_cleanup(Slirp *slirp) > +{ > + while (slirp->icmp6.so_next !=3D &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,=20 > + struct icmp6 *icmp)=20 > +{ > + m->m_len +=3D ETH_HLEN; > + m->m_data -=3D ETH_HLEN; > + struct ethhdr *eth =3D mtod(m, struct ethhdr *); > + m->m_len -=3D ETH_HLEN; > + m->m_data +=3D ETH_HLEN; > + > + switch (icmp->icmp6_type) { > + case ICMP6_NDP_ROUTER_SOL: > + DEBUG_CALL(" type =3D Routeur Solicitation"); > + if (ip->ip_hl =3D=3D 255 > + && icmp->icmp6_code =3D=3D 0 > + && ip->ip_pl >=3D 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 =3D m_get(slirp); > + struct ip6 *rip =3D mtod(t, struct ip6 *); > + rip->ip_src =3D (struct in6_addr)LINKLOCAL_ADDR; > + rip->ip_dst =3D (struct in6_addr)ALLNODES_MULTICAST; > + rip->ip_nh =3D IPPROTO_ICMPV6; > + rip->ip_pl =3D htons(ICMP6_NDP_RA_MINLEN=20 > + + NDPOPT_LINKLAYER_LENGTH=20 > + + NDPOPT_PREFIXINFO_LENGTH); > + t->m_len =3D sizeof(struct ip6) + ntohs(rip->ip_pl); > + > + /* Build ICMPv6 packet */ > + t->m_data +=3D sizeof(struct ip6); > + struct icmp6 *ricmp =3D mtod(t, struct icmp6 *); > + ricmp->icmp6_type =3D ICMP6_NDP_ROUTER_ADV; > + ricmp->icmp6_code =3D 0; > + ricmp->icmp6_cksum =3D 0; > + > + /* NDP */ > + ricmp->icmp6_nra.chl =3D NDP_AdvCurHopLimit; > + ricmp->icmp6_nra.M =3D NDP_AdvManagedFlag; > + ricmp->icmp6_nra.O =3D NDP_AdvOtherConfigFlag; > + ricmp->icmp6_nra.reserved =3D 0; > + ricmp->icmp6_nra.lifetime =3D htons(NDP_AdvDefaultLife= time); > + ricmp->icmp6_nra.reach_time =3D htonl(NDP_AdvReachable= Time); > + ricmp->icmp6_nra.retrans_time =3D htonl(NDP_AdvRetrans= Time); > + > + /* Source link-layer address (NDP option) */ > + t->m_data +=3D ICMP6_NDP_RA_MINLEN; > + struct ndpopt *opt =3D mtod(t, struct ndpopt *); > + opt->ndpopt_type =3D NDPOPT_LINKLAYER_SOURCE; > + opt->ndpopt_len =3D NDPOPT_LINKLAYER_LENGTH / 8; > + memcpy(opt->ndpopt_linklayer, special_ethaddr, ETH_ALE= N - 4); > + memcpy(&opt->ndpopt_linklayer[2], &slirp->vhost_addr, = 4); > + > + /* Prefix information (NDP option) */ > + t->m_data +=3D NDPOPT_LINKLAYER_LENGTH; > + struct ndpopt *opt2 =3D mtod(t, struct ndpopt *); > + opt2->ndpopt_type =3D NDPOPT_PREFIX_INFO; > + opt2->ndpopt_len =3D NDPOPT_PREFIXINFO_LENGTH / 8; > + opt2->ndpopt_prefixinfo.prefix_length =3D slirp->vpref= ix_len; > + opt2->ndpopt_prefixinfo.L =3D 1; > + opt2->ndpopt_prefixinfo.A =3D 1; > + opt2->ndpopt_prefixinfo.reserved1 =3D 0; > + opt2->ndpopt_prefixinfo.valid_lt =3D htonl(NDP_AdvVali= dLifetime); > + opt2->ndpopt_prefixinfo.pref_lt =3D htonl(NDP_AdvPrefL= ifetime); > + opt2->ndpopt_prefixinfo.reserved2 =3D 0; > + opt2->ndpopt_prefixinfo.prefix =3D slirp->vprefix_addr= 6; > + > + /* ICMPv6 Checksum */ > + t->m_data -=3D NDPOPT_LINKLAYER_LENGTH; > + t->m_data -=3D ICMP6_NDP_RA_MINLEN; > + t->m_data -=3D sizeof(struct ip6); > + ricmp->icmp6_cksum =3D ip6_cksum(t); > + > + ip6_output(NULL, t); > + } > + break; > + > + case ICMP6_NDP_ROUTER_ADV: > + DEBUG_CALL(" type =3D Routeur Advertisement"); > + fprintf(stderr,=20 > + "Warning: guest sent NDP RA, but shouldn't\n"); > + break; > + > + case ICMP6_NDP_NEIGH_SOL: > + DEBUG_CALL(" type =3D Neighbor Solicitation"); > + if (ip->ip_hl =3D=3D 255 > + && icmp->icmp6_code =3D=3D 0 > + && !in6_multicast(icmp->icmp6_nns.target) > + && ip->ip_pl >=3D ICMP6_NDP_NS_MINLEN > + && (!in6_unspecified(ip->ip_src)=20 > + || in6_multicast(ip->ip_dst))) {=20 > + // :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 =3D m_get(slirp); > + struct ip6 *rip =3D mtod(t, struct ip6 *); > + rip->ip_src =3D icmp->icmp6_nns.target; > + if (in6_unspecified(ip->ip_src)) { > + rip->ip_dst =3D (struct in6_addr)ALLNODES_MULT= ICAST; > + } else { > + rip->ip_dst =3D ip->ip_src; > + } > + rip->ip_nh =3D IPPROTO_ICMPV6; > + rip->ip_pl =3D htons(ICMP6_NDP_NA_MINLEN + NDPOPT_= LINKLAYER_LENGTH); > + t->m_len =3D sizeof(struct ip6) + ntohs(rip->ip_pl= ); > + > + /* Build ICMPv6 packet */ > + t->m_data +=3D sizeof(struct ip6); > + struct icmp6 *ricmp =3D mtod(t, struct icmp6 *); > + ricmp->icmp6_type =3D ICMP6_NDP_NEIGH_ADV; > + ricmp->icmp6_code =3D 0; > + ricmp->icmp6_cksum =3D 0; > + =20 > + /* NDP */ > + ricmp->icmp6_nna.R =3D NDP_IsRouter; > + ricmp->icmp6_nna.S =3D !in6_multicast(rip->ip_dst)= ; > + ricmp->icmp6_nna.O =3D 1; > + ricmp->icmp6_nna.reserved_hi =3D 0; > + ricmp->icmp6_nna.reserved_lo =3D 0; > + ricmp->icmp6_nna.target =3D icmp->icmp6_nns.target= ; > + =20 > + /* Build NDP option */ > + t->m_data +=3D ICMP6_NDP_NA_MINLEN; > + struct ndpopt *opt =3D mtod(t, struct ndpopt *); > + opt->ndpopt_type =3D NDPOPT_LINKLAYER_TARGET; > + opt->ndpopt_len =3D NDPOPT_LINKLAYER_LENGTH / 8; > + memcpy(opt->ndpopt_linklayer, special_ethaddr, ETH= _ALEN - 4); > + memcpy(&opt->ndpopt_linklayer[2], &slirp->vhost_ad= dr, 4); > + =20 > + /* ICMPv6 Checksum */ > + t->m_data -=3D ICMP6_NDP_NA_MINLEN; > + t->m_data -=3D sizeof(struct ip6); > + ricmp->icmp6_cksum =3D ip6_cksum(t); > + > + ip6_output(NULL, t); > + } > + } > + break; > + > + case ICMP6_NDP_NEIGH_ADV: > + DEBUG_CALL(" type =3D Neighbor Advertisement"); > + if (ip->ip_hl =3D=3D 255 > + && icmp->icmp6_code =3D=3D 0 > + && ip->ip_pl >=3D ICMP6_NDP_NA_MINLEN > + && !in6_multicast(icmp->icmp6_nna.target) > + && (!in6_multicast(ip->ip_dst) || icmp->icmp6_nna.= S =3D=3D 0)) { > + ndp_table_add(slirp, ip->ip_src, eth->h_source); > + } > + break; > + > + case ICMP6_NDP_REDIRECT: > + DEBUG_CALL(" type =3D Redirect"); > + fprintf(stderr,=20 > + "Warning: guest sent NDP REDIRECT, but shouldn't\n= "); > + break; > + > + default: > + return;=20 > + } > + return; > +} > + > +/* > + * Process a received ICMPv6 message. > + */ > +void icmp6_input(struct mbuf *m) > +{ > + struct icmp6 *icmp; > + struct ip6 *ip=3Dmtod(m, struct ip6 *); > + Slirp *slirp =3D m->slirp; > + int hlen =3D sizeof(struct ip6); > + > + DEBUG_CALL("icmp6_input"); > + DEBUG_ARG("m =3D %lx", (long )m); > + DEBUG_ARG("m_len =3D %d", m->m_len); > + > + if (ip->ip_pl < ICMP6_MINLEN) { > + goto end; > + } > + > + if (ip6_cksum(m)) { > + goto end; > + } > + > + m->m_len -=3D hlen; > + m->m_data +=3D hlen; > + icmp =3D mtod(m, struct icmp6 *); > + m->m_len +=3D hlen; > + m->m_data -=3D hlen; > + > + DEBUG_ARG("icmp6_type =3D %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 =3D so->so_m; > + int hlen =3D sizeof(struct ip6); > + /*u_char error_code;*/ > + struct icmp6 *icmp; > + int len; > + > + m->m_data +=3D hlen; > + m->m_len -=3D hlen; > + icmp =3D mtod(m, struct icmp6 *); > + > + len =3D qemu_recv(so->s, icmp, m->m_len, 0); > + > + m->m_data -=3D hlen; > + m->m_len +=3D hlen; > + > + if (len =3D=3D -1 || len =3D=3D 0) { > + /* > + if (errno =3D=3D ENETUNREACH) { > + error_code =3D ICMP_UNREACH_NET; > + } else { > + error_code =3D ICMP_UNREACH_HOST; > + } > + DEBUG_MISC((dfd, " udp icmp rx errno =3D %d-%s\n", errno, > + strerror(errno))); > + icmp_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(err= no)); > + */ > + } else { > + /*icmp_reflect(so->so_m);*/ > + so->so_m =3D 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; > + > +/*=20 > + * NDP Messages=20 > + */ > +struct ndp_router_sol { > + uint32_t reserved; > +}; > + > +struct ndp_router_adv { > + uint8_t chl; /* Cur Hop Limit */ > +#ifdef HOST_WORDS_BIGENDIAN > + uint8_t=20 > + 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=20 > + 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 */=09 > + 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 o= ctets */ > + 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-param= eters.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 prohibite= d */=20 > +#define ICMP6_UNREACH_SCOPE 2 /* beyond scope of src add= r */ > +#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 he= ader */ > +#define ICMP6_TOOBIG 2 /* Packet Too Big */ > +#define ICMP6_TIMXCEED 3 /* Time Exceeded */ =20 > +#define ICMP6_TIMXCEED_INTRANS 0 /* hop limit exceeded in t= ransit */ > +#define ICMP6_TIMXCEED_REASS 1 /* ttl=3D0 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 Heade= r type */ > +#define ICMP6_PARAMPROB_IPV6_OPT 2 /* unrecognized IPv6 optio= n */ > + > +/* 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) *= /=20 > +#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 comman= d */ > +#define ICMP6_ROUTERRENUM_RESULT 1 /* router renum result= */ > +#define ICMP6_ROUTERRENUM_RESET 255 /* sequence number res= et */ > +#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 Respo= nse */=20 > +#define ICMP6_NODEINFO_RESP_SUCCESS 0 /* successful reply */ > +#define ICMP6_NODEINFO_RESP_REFUSAL 1 /* refuses to supply a= nswer */ > +#define ICMP6_NODEINFO_RESP_UNKNOWN 2 /* Qtype unknown to th= e resp */ > +#define ICMP6_IND_SOL 141 /* Inverse Neighbor Discovery Solicita= tion */ > +#define ICMP6_IND_ADV 142 /* Inverse Neighbor Discovery Advertis= ement */ > +#define ICMP6_MLD 143 /* Multicast Listener Discovery report= s */ > +#define ICMP6_HAAD_REQUEST 144 /* Home Agent Address Discovery Reques= t */ > +#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 (SE= ND) */ > +#define ICMP6_SEND_CP_ADV 149 /* Certification Path Advertisement (S= END) */ > +#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 Confirmat= ion */ > + > +#define ICMP6_INFOTYPE(type) ((type) >=3D 128) > + > +/* Router Configuration Variables (rfc4861#section-6) */ > +#define NDP_IsRouter 1 > +#define NDP_AdvSendAdvertisements 1 > +#define NDP_MaxRtrAdvInterval 600 > +#define NDP_MinRtrAdvInterval ((NDP_MaxRtrAdvInterval>=3D9)?\ > + 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=20 > +#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 mins= ize,=20 > + const char *message); > +// :TODO:maethor:130307:=20 > +//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; > =20 > - DEBUG_CALL("if_start"); > + /*DEBUG_CALL("if_start");*/ > =20 > if (slirp->if_start_busy) { > return; > @@ -193,7 +193,7 @@ void if_start(Slirp *slirp) > =20 > /* Try to send packet unless it already expired */ > if (ifm->expiration_date >=3D now && !if_encap(slirp, ifm)) { > - /* Packet is delayed due to pending ARP resolution */ > + /* Packet is delayed due to pending ARP or NDP resolution = */ > continue; > } > =20 > 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 =3D \ > + { 0xff, 0x02, 0x00, 0x00,\ > + 0x00, 0x00, 0x00, 0x00,\ > + 0x00, 0x00, 0x00, 0x00,\ > + 0x00, 0x00, 0x00, 0x01 } } > + > +#define LINKLOCAL_ADDR { .s6_addr =3D \ > + { 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)) =3D=3D 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) =3D=3D 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]),=20 > + &(b.s6_addr[prefix_len / 8]), 16 - prefix_len / 8)= =3D=3D 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=20 > + 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 */ =20 > +} 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 > +#include > +#include "icmp6.h" > + > +/* > + * IP initialization: fill in IP protocol switch table. > + * All protocols not implemented in kernel go to raw IP protocol handl= er. > + */ > +void ip6_init(Slirp *slirp) > +{ > + /*slirp->ipq.ip_link.next =3D slirp->ipq.ip_link.prev =3D &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 =3D %lx", (long)m); > + DEBUG_ARG("m_len =3D %d", m->m_len); > + > + if (m->m_len < sizeof (struct ip6)) { > + return; > + } > + > + ip6 =3D mtod(m, struct ip6 *); > + > + if (ip6->ip_v !=3D IP6VERSION) { > + goto bad; > + } > + > + /* check ip_ttl for a correct ICMP reply */ > + if(ip6->ip_hl=3D=3D0) { > + /*icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");= */ // :TODO:maethor:130307:=20 > + goto bad; > + } > + > + /* > + * Switch out to protocol's input routine. > + */ > + switch (ip6->ip_nh) { > + //case IPPROTO_TCP: :TODO:maethor:130307:=20 > + // 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 > + > +/* 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 =3D mtod(m, struct ip6 *); > + > + DEBUG_CALL("ip6_output"); > + DEBUG_ARG("so =3D %lx", (long)so); > + DEBUG_ARG("m =3D %lx", (long)m); > + > + /* Fill IPv6 header */ > + ip->ip_v =3D IP6VERSION; > + ip->ip_hl =3D IP6_HOP_LIMIT; > + ip->ip_tc_hi =3D 0; > + ip->ip_tc_lo =3D 0; > + ip->ip_fl_hi =3D 0; > + ip->ip_fl_lo =3D 0; > + > + if_output(so, m); > + =20 > + 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 =3D 0; > m->m_nextpkt =3D NULL; > m->m_prevpkt =3D NULL; > - m->arp_requested =3D false; > + m->resolution_requested =3D false; > m->expiration_date =3D (uint64_t)-1; > end_error: > DEBUG_ARG("m =3D %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,=20 > + uint8_t ethaddr[ETH_ALEN]) > +{ > + NdpTable *ndp_table =3D &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 =3D %s", addrstr); > + DEBUG_ARGS((dfd, " hw addr =3D %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 a= ddress"); > + return; > + } > + > + /* Search for an entry */ > + for (i =3D 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 =3D ip_addr; > + memcpy(ndp_table->table[ndp_table->next_victim].eth_addr,=20 > + ethaddr, ETH_ALEN); > + ndp_table->next_victim =3D (ndp_table->next_victim + 1) % NDP_TABL= E_SIZE; > +} > + > +bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr, > + uint8_t out_ethaddr[ETH_ALEN]) > +{ > + NdpTable *ndp_table =3D &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 =3D %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] =3D 0x33; out_ethaddr[1] =3D 0x33; > + out_ethaddr[2] =3D ip_addr.s6_addr[12]; > + out_ethaddr[3] =3D ip_addr.s6_addr[13]; > + out_ethaddr[4] =3D ip_addr.s6_addr[14]; > + out_ethaddr[5] =3D ip_addr.s6_addr[15]; > + DEBUG_ARGS((dfd, " multicast addr =3D %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 =3D 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_ALE= N); > + DEBUG_ARGS((dfd, " found hw addr =3D %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) > } > =20 > f =3D fopen("/etc/resolv.conf", "r"); > - if (!f) > + if (!f) { > + fprintf(stderr, "Unable to open /etc/resolv.conf\n"); > return -1; > + } > =20 > #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; > } > =20 > @@ -214,6 +218,7 @@ Slirp *slirp_init(int restricted, struct in_addr vn= etwork, > =20 > if_init(slirp); > ip_init(slirp); > + ip6_init(slirp); > =20 > /* Initialise mbufs *after* setting the MTU */ > m_init(slirp); > @@ -221,6 +226,9 @@ Slirp *slirp_init(int restricted, struct in_addr vn= etwork, > slirp->vnetwork_addr =3D vnetwork; > slirp->vnetwork_mask =3D vnetmask; > slirp->vhost_addr =3D vhost; > + inet_pton(AF_INET6, "fc00::0", &slirp->vprefix_addr6); // :TODO:m= aethor:130311: Utiliser un argument pass=C3=A9 =C3=A0 la fonction > + slirp->vprefix_len =3D 64; // :TODO= :maethor:130311: Utiliser un argument pass=C3=A9 =C3=A0 la fonction > + inet_pton(AF_INET6, "fc00::1", &slirp->vhost_addr6); // :TODO:m= aethor:130311: Utiliser un argument pass=C3=A9 =C3=A0 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); > =20 > ip_cleanup(slirp); > + ip6_cleanup(slirp); > m_cleanup(slirp); > =20 > g_free(slirp->vdnssearch); > @@ -413,6 +422,31 @@ void slirp_select_fill(int *pnfds, > UPD_NFDS(so->s); > } > } > + > + /* > + * ICMPv6 sockets > + */ > + for (so =3D slirp->icmp6.so_next; so !=3D &slirp->icmp= 6; > + so =3D so_next) { > + so_next =3D so->so_next; > + > + /* > + * See if it's timed out > + */ > + if (so->so_expire) { > + if (so->so_expire <=3D curtime) { > + icmp6_detach(so); > + continue; > + } else { > + do_slowtimo =3D 1; /* Let socket expire */ > + } > + } > + > + if (so->so_state & SS_ISFCONNECTED) { > + FD_SET(so->s, readfds); > + UPD_NFDS(so->s); > + } > + } > } > =20 > *pnfds =3D nfds; > @@ -594,6 +628,18 @@ void slirp_select_poll(fd_set *readfds, fd_set *wr= itefds, fd_set *xfds, > icmp_receive(so); > } > } > + > + /* > + * Check incoming ICMPv6 relies. > + */ > + for (so =3D slirp->icmp6.so_next; so !=3D &slirp->icmp= 6; > + so =3D so_next) { > + so_next =3D so->so_next; > + > + if (so->s !=3D -1 && FD_ISSET(so->s, readfds)) { > + icmp6_receive(so); > + } > + } > } > =20 > 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 =3D 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 +=3D 2 + ETH_HLEN; > m->m_len -=3D 2 + ETH_HLEN; > =20 > + if (proto =3D=3D ETH_P_IP) { > ip_input(m); > + } else if (proto =3D=3D 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 =3D (struct ethhdr *)buf; > uint8_t ethaddr[ETH_ALEN]; > const struct ip *iph =3D (const struct ip *)ifm->m_data; > + const struct ip6 *ip6h =3D mtod(ifm, const struct ip6 *); > + char addrstr[INET6_ADDRSTRLEN]; > =20 > if (ifm->m_len + ETH_HLEN > sizeof(buf)) { > return 1; > } > =20 > + 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 =3D (struct ethhdr *)arp_req; > struct arphdr *rah =3D (struct arphdr *)(arp_req + ETH= _HLEN); > =20 > - if (!ifm->arp_requested) { > + if (!ifm->resolution_requested) { > /* If the client addr is not known, send an ARP re= quest */ > 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 =3D iph->ip_dst.s_addr; > slirp->client_ipaddr =3D iph->ip_dst; > slirp_output(slirp->opaque, arp_req, sizeof(arp_re= q)); > - ifm->arp_requested =3D true; > + ifm->resolution_requested =3D true; > =20 > /* Expire request and drop outgoing packet after 1= second */ > ifm->expiration_date =3D qemu_get_clock_ns(rt_cloc= k) + 1000000000ULL; > } > return 0; > } else {=20 > + eh->h_proto =3D htons(ETH_P_IP); > + break; > + } > + > + case IP6VERSION: > + inet_ntop(AF_INET6, &(ip6h->ip_dst), addrstr, INET6_ADDRST= RLEN); > + if (!ndp_table_search(slirp, ip6h->ip_dst, ethaddr)) { > + // :TODO:maethor:130311: NS > + return 0; > + } else { > + eh->h_proto =3D 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 =3D htons(ETH_P_IP); > + DEBUG_ARGS((dfd, " SOURCE =3D %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 =3D %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: =3D %d\n", ifm->m_len); > slirp_output(slirp->opaque, buf, ifm->m_len + ETH_HLEN); > return 1; > } > -} > =20 > /* 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); > =20 > #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); > =20 > #define ETH_P_IP 0x0800 /* Internet Protocol packet */ > #define ETH_P_ARP 0x0806 /* Address Resolution packet */ > +#define ETH_P_IP6 0x86DD /* IPv6 packet */ > =20 > #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]); > =20 > +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 etha= ddr[ETH_ALEN]); > +bool ndp_table_search(Slirp *slirp, struct in6_addr ip_addr,=20 > + uint8_t out_ethaddr[ETH_ALEN]);=20 > + > struct Slirp { > QTAILQ_ENTRY(Slirp) entry; > =20 > @@ -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; > =20 > @@ -250,12 +272,15 @@ struct Slirp { > /* icmp states */ > struct socket icmp; > struct socket *icmp_last_so; > + struct socket icmp6; > + struct socket *icmp6_last_so; > =20 > /* tftp states */ > char *tftp_prefix; > struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; > =20 > ArpTable arp_table; > + NdpTable ndp_table; > =20 > void *opaque; > }; > @@ -300,6 +325,7 @@ int translate_dnssearch(Slirp *s, const char ** nam= es); > =20 > /* cksum.c */ > int cksum(struct mbuf *m, int len); > +int ip6_cksum(struct mbuf *m); > =20 > /* if.c */ > void if_init(Slirp *); > @@ -315,6 +341,14 @@ void ip_stripoptions(register struct mbuf *, struc= t mbuf *); > /* ip_output.c */ > int ip_output(struct socket *, struct mbuf *); > =20 > +/* 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); --=20 Guillaume Subiron=20 Mail - maethor@subiron.org GPG - C7C4 455C Jabber - maethor@im.subiron.org IRC - maethor@(freenode|geeknode)