qemu-devel
[Top][All Lists]
Advanced

[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)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]