qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP a


From: Thomas Huth
Subject: Re: [Qemu-devel] [PATCHv7 1/9] slirp: Adding IPv6, ICMPv6 Echo and NDP autoconfiguration
Date: Tue, 9 Feb 2016 17:14:15 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.5.0

On 08.02.2016 11:28, Samuel Thibault wrote:
> From: Guillaume Subiron <address@hidden>
> 
> This patch adds the functions needed to handle IPv6 packets. ICMPv6 and
> NDP headers are implemented.
> 
> Slirp is now able to send NDP Router or Neighbor Advertisement when it
> receives Router or Neighbor Solicitation. Using a 64bit-sized IPv6
> prefix, the guest is now able to perform stateless autoconfiguration
> (SLAAC) and to compute its IPv6 address.
> 
> This patch adds an ndp_table, mainly inspired by arp_table, to keep an
> NDP cache and manage network address resolution.
> Slirp regularly sends NDP Neighbor Advertisement, as recommended by the
> RFC, to make the guest refresh its route.
> 
> This also adds ip6_cksum() to compute ICMPv6 checksums using IPv6
> pseudo-header.
> 
> Some #define ETH_* are moved upper in slirp.h to make them accessible to
> other slirp/*.h
> 
> Signed-off-by: Guillaume Subiron <address@hidden>
> Signed-off-by: Samuel Thibault <address@hidden>
> ---
>  slirp/Makefile.objs |   4 +-
>  slirp/cksum.c       |  23 ++++
>  slirp/if.c          |   2 +-
>  slirp/ip6.h         | 139 +++++++++++++++++++++
>  slirp/ip6_icmp.c    | 350 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  slirp/ip6_icmp.h    | 244 ++++++++++++++++++++++++++++++++++++
>  slirp/ip6_input.c   |  72 +++++++++++
>  slirp/ip6_output.c  |  41 ++++++
>  slirp/ndp_table.c   |  87 +++++++++++++
>  slirp/slirp.c       |  48 ++++++-
>  slirp/slirp.h       |  34 +++++
>  slirp/socket.h      |   7 ++
>  12 files changed, 1045 insertions(+), 6 deletions(-)
>  create mode 100644 slirp/ip6.h
>  create mode 100644 slirp/ip6_icmp.c
>  create mode 100644 slirp/ip6_icmp.h
>  create mode 100644 slirp/ip6_input.c
>  create mode 100644 slirp/ip6_output.c
>  create mode 100644 slirp/ndp_table.c
> 
> diff --git a/slirp/Makefile.objs b/slirp/Makefile.objs
> index 2daa9dc..2dfe8e0 100644
> --- a/slirp/Makefile.objs
> +++ b/slirp/Makefile.objs
> @@ -1,3 +1,3 @@
> -common-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o dnssearch.o
> +common-obj-y = cksum.o if.o ip_icmp.o ip6_icmp.o ip6_input.o ip6_output.o 
> ip_input.o ip_output.o dnssearch.o
>  common-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o 
> tcp_output.o
> -common-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o
> +common-obj-y += tcp_subr.o tcp_timer.o udp.o bootp.o tftp.o arp_table.o 
> ndp_table.o

The lines in this file are now longer than 80 columns ... could you
please rearrange them so that they do not exceed this limit anymore?

> diff --git a/slirp/cksum.c b/slirp/cksum.c
> index bc0d017..d2b0a83 100644
> --- a/slirp/cksum.c
> +++ b/slirp/cksum.c
> @@ -138,3 +138,26 @@ cont:
>       REDUCE;
>       return (~sum & 0xffff);
>  }
> +
> +int ip6_cksum(struct mbuf *m)
> +{
> +    struct ip6 save_ip, *ip = mtod(m, struct ip6 *);
> +    struct ip6_pseudohdr *ih = mtod(m, struct ip6_pseudohdr *);
> +    int sum;
> +
> +    save_ip = *ip;
> +
> +    ih->ih_src = save_ip.ip_src;
> +    ih->ih_dst = save_ip.ip_dst;
> +    ih->ih_pl = htonl((uint32_t)ntohs(save_ip.ip_pl));
> +    ih->ih_zero_hi = 0;
> +    ih->ih_zero_lo = 0;
> +    ih->ih_nh = save_ip.ip_nh;
> +
> +    sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr))
> +                    + ntohl(ih->ih_pl));
> +
> +    *ip = save_ip;
> +
> +    return sum;
> +}

Just a small remark here: The function looks ok to me, so it should be
OK for now, but I think there's some possibility for optimization here:
Either the fields in the pseudohdr could be aligned with the fields in
the real ip6 header, so that you would not need to copy all fields over
here, or the cksum() function could maybe be changed in a way so that it
is possible to calculate the checksum of the pseudoheader and upper
layer header separately (and then return the sum of both checksums), so
that you don't have to replace the ip6 header in-place here.
Anyway, no need to do that right now, IMHO, but we might keep this in
mind as a future possibility for optimization.

> diff --git a/slirp/if.c b/slirp/if.c
> index 93d7cc0..2e21f43 100644
> --- a/slirp/if.c
> +++ b/slirp/if.c
> @@ -194,7 +194,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..9e65acd
> --- /dev/null
> +++ b/slirp/ip6.h
> @@ -0,0 +1,139 @@
> +/*
> + * Copyright (c) 2013
> + * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
> + *
> + * Please read the file COPYRIGHT for the
> + * terms and conditions of the copyright.
> + */
> +
> +#ifndef _IP6_H_
> +#define _IP6_H_

IIRC, defines that start with an underscore are reserved by the C
standard ... so maybe better use SLIRP_IP6_H or so instead of _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))

I think at least I personally would not introduce these additional three
macros here, and use the original macros instead. But that's likely just
my personal taste.

BTW, at least in6_linklocal() seems to be unused, so you could remove
that one.

> +#define ALLNODES_MULTICAST  { .s6_addr = \
> +                            { 0xff, 0x02, 0x00, 0x00,\
> +                            0x00, 0x00, 0x00, 0x00,\
> +                            0x00, 0x00, 0x00, 0x00,\
> +                            0x00, 0x00, 0x00, 0x01 } }
> +
> +#define SOLICITED_NODE_PREFIX { .s6_addr = \
> +                            { 0xff, 0x02, 0x00, 0x00,\
> +                            0x00, 0x00, 0x00, 0x00,\
> +                            0x00, 0x00, 0x00, 0x01,\
> +                            0xff, 0x00, 0x00, 0x00 } }
> +
> +#define LINKLOCAL_ADDR  { .s6_addr = \
> +                        { 0xfe, 0x80, 0x00, 0x00,\
> +                        0x00, 0x00, 0x00, 0x00,\
> +                        0x00, 0x00, 0x00, 0x00,\
> +                        0x00, 0x00, 0x00, 0x02 } }
> +
> +static inline int in6_equal(struct in6_addr a, struct in6_addr b)

What about using pointers to the structs as parameters? Passing whole
structs here sounds cumbersome to me.
(that also applies to the other inline functions below)

> +{
> +    return memcmp(&a, &b, sizeof(a)) == 0;
> +}
> +
> +static inline int in6_equal_net(struct in6_addr a, struct in6_addr b,
> +        int prefix_len)
> +{
> +    if (memcmp(&a, &b, prefix_len / 8) != 0) {
> +        return 0;
> +    }
> +
> +    if (prefix_len % 8 == 0) {
> +        return 1;
> +    }
> +
> +    return (a.s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8)))
> +        == (b.s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8)));

checkpatch.pl complains here:

ERROR: return is not a function, parentheses are not required

There are also some other stylistic problems that checkpatch.pl reports
in this file ... would be nice to fix them.

> +}
> +
> +static inline int in6_equal_mach(struct in6_addr a, struct in6_addr b,
> +        int prefix_len)
> +{
> +    if (memcmp(&(a.s6_addr[(prefix_len + 7) / 8]),
> +                &(b.s6_addr[(prefix_len + 7) / 8]),
> +                16 - (prefix_len + 7) / 8) != 0) {
> +        return 0;
> +    }
> +
> +    if (prefix_len % 8 == 0) {
> +        return 1;
> +    }
> +
> +    return (a.s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 1))
> +        == (b.s6_addr[prefix_len / 8] & ((1U << (8 - (prefix_len % 8))) - 
> 1));
> +}
> +
> +#define in6_equal_router(a)\
> +    ((in6_equal_net(a, slirp->vprefix_addr6, slirp->vprefix_len)\
> +      && in6_equal_mach(a, slirp->vhost_addr6, slirp->vprefix_len))\
> +  || (in6_equal_net(a, (struct in6_addr)LINKLOCAL_ADDR, 64)\
> +      && in6_equal_mach(a, slirp->vhost_addr6, 64)))
> +
> +#define in6_equal_dns(a) 0
> +
> +#define in6_equal_host(a)\
> +    (in6_equal_router(a) || in6_equal_dns(a))
> +
> +#define in6_solicitednode_multicast(a)\
> +    (in6_equal_net(a, (struct in6_addr)SOLICITED_NODE_PREFIX, 104))
> +
> +/* Compute emulated host MAC address from its ipv6 address */
> +static inline void in6_compute_ethaddr(struct in6_addr ip,
> +                                       uint8_t eth[ETH_ALEN])
> +{
> +    eth[0] = 0x52;
> +    eth[1] = 0x56;
> +    memcpy(&eth[2], &(ip.s6_addr[16-(ETH_ALEN-2)]), ETH_ALEN-2);

checkpatch.pl complains about the style here ... and I think you could
also drop the parentheses around "ip.s6_addr[16-(ETH_ALEN-2)]".

> +}
> +
> +/*
> + * Definitions for internet protocol version 6.
> + * Per RFC 2460, December 1998.
> + */
> +#define IP6VERSION      6
> +#define IP6_HOP_LIMIT 255
> +
> +/*
> + * Structure of an internet header, naked of options.
> + */
> +struct ip6 {
> +#ifdef HOST_WORDS_BIGENDIAN
> +    uint32_t
> +        ip_v:4,         /* version */
> +        ip_tc_hi:4,     /* traffic class */
> +        ip_tc_lo:4,
> +        ip_fl_hi:4,     /* flow label */
> +        ip_fl_lo:16;
> +#else
> +    uint32_t
> +        ip_tc_hi:4,
> +        ip_v:4,
> +        ip_fl_hi:4,
> +        ip_tc_lo:4,
> +        ip_fl_lo:16;
> +#endif
> +    uint16_t    ip_pl;               /* payload length */
> +    uint8_t     ip_nh;               /* next header */
> +    uint8_t     ip_hl;               /* hop limit */
> +    struct in6_addr ip_src, ip_dst;  /* source and dest address */
> +} QEMU_PACKED;
> +
> +/*
> + * IPv6 pseudo-header used by upper-layer protocols
> + */
> +struct ip6_pseudohdr {
> +    struct      in6_addr ih_src;  /* source internet address */
> +    struct      in6_addr ih_dst;  /* destination internet address */
> +    uint32_t    ih_pl;            /* upper-layer packet length */
> +    uint16_t    ih_zero_hi;       /* zero */
> +    uint8_t     ih_zero_lo;       /* zero */
> +    uint8_t     ih_nh;            /* next header */
> +} QEMU_PACKED;
> +
> +
> +#endif
> diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c
> new file mode 100644
> index 0000000..13f89af
> --- /dev/null
> +++ b/slirp/ip6_icmp.c
> @@ -0,0 +1,350 @@
> +/*
> + * Copyright (c) 2013
> + * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
> + *
> + * Please read the file COPYRIGHT for the
> + * terms and conditions of the copyright.
> + */
> +
> +#include "slirp.h"
> +#include "ip6_icmp.h"
> +#include "qemu/timer.h"
> +#include "qemu/error-report.h"
> +#include <stdlib.h>
> +#include <time.h>
> +
> +#define rand_a_b(a, b)\
> +    (rand()%(int)(b-a)+a)
> +#define NDP_Interval rand_a_b(NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval)
> +
> +static void ra_timer_handler(void *opaque)
> +{
> +    Slirp *slirp = opaque;
> +    timer_mod(slirp->ra_timer,
> +              qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
> +    ndp_send_ra(slirp);
> +}
> +
> +void icmp6_init(Slirp *slirp)
> +{
> +    srand(time(NULL));

That srand should maybe be done in main() instead? (Otherwise every
subsystem might end up in repeating this all over the place)

> +    slirp->ra_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, ra_timer_handler, 
> slirp);
> +    timer_mod(slirp->ra_timer,
> +              qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + NDP_Interval);
> +}
> +
> +#undef NDP_Interval
> +#undef rand_a_b
> +
> +void icmp6_cleanup(Slirp *slirp)
> +{
> +    timer_del(slirp->ra_timer);
> +    timer_free(slirp->ra_timer);
> +}
> +
> +static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 
> *ip,
> +        struct icmp6 *icmp)
> +{
> +    struct mbuf *t = m_get(slirp);
> +    t->m_len = sizeof(struct ip6) + ntohs(ip->ip_pl);
> +    memcpy(t->m_data, m->m_data, t->m_len);
> +
> +    /* IPv6 Packet */
> +    struct ip6 *rip = mtod(t, struct ip6 *);

Not sure how strictly this is handled in QEMU, but for proper portable
C, variables should be declared at the beginning of a scope, as far as I
know.

> +    rip->ip_dst = ip->ip_src;
> +    rip->ip_src = ip->ip_dst;
> +
> +    /* ICMPv6 packet */
> +    t->m_data += sizeof(struct ip6);
> +    struct icmp6 *ricmp = mtod(t, struct icmp6 *);

dito

> +    ricmp->icmp6_type = ICMP6_ECHO_REPLY;
> +    ricmp->icmp6_cksum = 0;
> +
> +    /* Checksum */
> +    t->m_data -= sizeof(struct ip6);
> +    ricmp->icmp6_cksum = ip6_cksum(t);
> +
> +    ip6_output(NULL, t, 0);
> +}
> +
> +/*
> + * Process a NDP message
> + */
> +static void ndp_input(struct mbuf *m, Slirp *slirp, struct ip6 *ip,
> +        struct icmp6 *icmp)
> +{
> +    m->m_len += ETH_HLEN;
> +    m->m_data -= ETH_HLEN;
> +    struct ethhdr *eth = mtod(m, struct ethhdr *);
> +    m->m_len -= ETH_HLEN;
> +    m->m_data += ETH_HLEN;

Manipulating m_len is not really required here, is it?
Also the variable declaration should be at the beginning of the scope again.

> +    switch (icmp->icmp6_type) {
> +    case ICMP6_NDP_RS:
> +        DEBUG_CALL(" type = Routeur Solicitation");

s/Routeur/Router/

> +        if (ip->ip_hl == 255
> +                && icmp->icmp6_code == 0
> +                && ntohs(ip->ip_pl) >= ICMP6_NDP_RS_MINLEN) {
> +            /* Gratuitous NDP */
> +            ndp_table_add(slirp, ip->ip_src, eth->h_source);
> +
> +            ndp_send_ra(slirp);
> +        }
> +        break;
> +
> +    case ICMP6_NDP_RA:
> +        DEBUG_CALL(" type = Routeur Advertisement");

s/Routeur/Router/

> +        error_report("Warning: guest sent NDP RA, but shouldn't\n");

If you use error_report, then please do not use "\n" in the strings.
OTOH, I wonder whether this should maybe rather be a
qemu_log_mask(LOG_GUEST_ERROR, ...) instead?

> +        break;
> +
> +    case ICMP6_NDP_NS:
> +        DEBUG_CALL(" type = Neighbor Solicitation");
> +        if (ip->ip_hl == 255
> +                && icmp->icmp6_code == 0
> +                && !in6_multicast(icmp->icmp6_nns.target)
> +                && ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN
> +                && (!in6_unspecified(ip->ip_src)
> +                    || in6_solicitednode_multicast(ip->ip_dst))) {
> +            if (in6_equal_host(icmp->icmp6_nns.target)) {
> +                /* Gratuitous NDP */
> +                ndp_table_add(slirp, ip->ip_src, eth->h_source);
> +
> +                /* Build IPv6 packet */
> +                struct mbuf *t = m_get(slirp);
> +                struct ip6 *rip = mtod(t, struct ip6 *);
> +                rip->ip_src = icmp->icmp6_nns.target;
> +                if (in6_unspecified(ip->ip_src)) {
> +                    rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
> +                } else {
> +                    rip->ip_dst = ip->ip_src;
> +                }
> +                rip->ip_nh = IPPROTO_ICMPV6;
> +                rip->ip_pl = htons(ICMP6_NDP_NA_MINLEN
> +                                    + NDPOPT_LINKLAYER_LEN);
> +                t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
> +
> +                /* Build ICMPv6 packet */
> +                t->m_data += sizeof(struct ip6);
> +                struct icmp6 *ricmp = mtod(t, struct icmp6 *);
> +                ricmp->icmp6_type = ICMP6_NDP_NA;
> +                ricmp->icmp6_code = 0;
> +                ricmp->icmp6_cksum = 0;
> +
> +                /* NDP */
> +                ricmp->icmp6_nna.R = NDP_IsRouter;
> +                ricmp->icmp6_nna.S = !in6_multicast(rip->ip_dst);
> +                ricmp->icmp6_nna.O = 1;
> +                ricmp->icmp6_nna.reserved_hi = 0;
> +                ricmp->icmp6_nna.reserved_lo = 0;
> +                ricmp->icmp6_nna.target = icmp->icmp6_nns.target;
> +
> +                /* Build NDP option */
> +                t->m_data += ICMP6_NDP_NA_MINLEN;
> +                struct ndpopt *opt = mtod(t, struct ndpopt *);
> +                opt->ndpopt_type = NDPOPT_LINKLAYER_TARGET;
> +                opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
> +                in6_compute_ethaddr(ricmp->icmp6_nna.target,
> +                                opt->ndpopt_linklayer);
> +
> +                /* ICMPv6 Checksum */
> +                t->m_data -= ICMP6_NDP_NA_MINLEN;
> +                t->m_data -= sizeof(struct ip6);
> +                ricmp->icmp6_cksum = ip6_cksum(t);
> +
> +                ip6_output(NULL, t, 0);

Since this case statement is rather long and has a big indentation depth
already, I'd like to suggest to move the above code into a separate
function instead.

> +            }
> +        }
> +        break;
> +
> +    case ICMP6_NDP_NA:
> +        DEBUG_CALL(" type = Neighbor Advertisement");
> +        if (ip->ip_hl == 255
> +                && icmp->icmp6_code == 0
> +                && ntohs(ip->ip_pl) >= ICMP6_NDP_NA_MINLEN
> +                && !in6_multicast(icmp->icmp6_nna.target)
> +                && (!in6_multicast(ip->ip_dst) || icmp->icmp6_nna.S == 0)) {
> +            ndp_table_add(slirp, ip->ip_src, eth->h_source);
> +        }
> +        break;
> +
> +    case ICMP6_NDP_REDIRECT:
> +        DEBUG_CALL(" type = Redirect");
> +        error_report("Warning: guest sent NDP REDIRECT, but shouldn't\n");

Either remove the "\n" or use qemu_log_mask(LOG_GUEST_ERROR, ...)

> +        break;
> +
> +    default:
> +       return;

You can remove that default case.

> +    }
> +    return;

You can remove that return statement.

> +}
> +
> +/*
> + * Send NDP Router Advertisement
> + */
> +void ndp_send_ra(Slirp *slirp)
> +{
> +    DEBUG_CALL("ndp_send_ra");
> +
> +    /* Build IPv6 packet */
> +    struct mbuf *t = m_get(slirp);
> +    struct ip6 *rip = mtod(t, struct ip6 *);
> +    rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
> +    rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
> +    rip->ip_nh = IPPROTO_ICMPV6;
> +    rip->ip_pl = htons(ICMP6_NDP_RA_MINLEN
> +                        + NDPOPT_LINKLAYER_LEN
> +                        + NDPOPT_PREFIXINFO_LEN);
> +    t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
> +
> +    /* Build ICMPv6 packet */
> +    t->m_data += sizeof(struct ip6);
> +    struct icmp6 *ricmp = mtod(t, struct icmp6 *);

Please move the variable declaration to the beginning of the scope.

> +    ricmp->icmp6_type = ICMP6_NDP_RA;
> +    ricmp->icmp6_code = 0;
> +    ricmp->icmp6_cksum = 0;
> +
> +    /* NDP */
> +    ricmp->icmp6_nra.chl = NDP_AdvCurHopLimit;
> +    ricmp->icmp6_nra.M = NDP_AdvManagedFlag;
> +    ricmp->icmp6_nra.O = NDP_AdvOtherConfigFlag;
> +    ricmp->icmp6_nra.reserved = 0;
> +    ricmp->icmp6_nra.lifetime = htons(NDP_AdvDefaultLifetime);
> +    ricmp->icmp6_nra.reach_time = htonl(NDP_AdvReachableTime);
> +    ricmp->icmp6_nra.retrans_time = htonl(NDP_AdvRetransTime);
> +
> +    /* Source link-layer address (NDP option) */
> +    t->m_data += ICMP6_NDP_RA_MINLEN;
> +    struct ndpopt *opt = mtod(t, struct ndpopt *);

dito

> +    opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
> +    opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
> +    in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer);
> +
> +    /* Prefix information (NDP option) */
> +    t->m_data += NDPOPT_LINKLAYER_LEN;
> +    struct ndpopt *opt2 = mtod(t, struct ndpopt *);

dito

> +    opt2->ndpopt_type = NDPOPT_PREFIX_INFO;
> +    opt2->ndpopt_len = NDPOPT_PREFIXINFO_LEN / 8;
> +    opt2->ndpopt_prefixinfo.prefix_length = slirp->vprefix_len;
> +    opt2->ndpopt_prefixinfo.L = 1;
> +    opt2->ndpopt_prefixinfo.A = 1;
> +    opt2->ndpopt_prefixinfo.reserved1 = 0;
> +    opt2->ndpopt_prefixinfo.valid_lt = htonl(NDP_AdvValidLifetime);
> +    opt2->ndpopt_prefixinfo.pref_lt = htonl(NDP_AdvPrefLifetime);
> +    opt2->ndpopt_prefixinfo.reserved2 = 0;
> +    opt2->ndpopt_prefixinfo.prefix = slirp->vprefix_addr6;
> +
> +    /* ICMPv6 Checksum */
> +    t->m_data -= NDPOPT_LINKLAYER_LEN;
> +    t->m_data -= ICMP6_NDP_RA_MINLEN;
> +    t->m_data -= sizeof(struct ip6);

I think you could shorten this to:

    t_m_data = rip;

?

> +    ricmp->icmp6_cksum = ip6_cksum(t);
> +
> +    ip6_output(NULL, t, 0);
> +}
...
> +/*
> + * Process a received ICMPv6 message.
> + */
> +void icmp6_input(struct mbuf *m)
> +{
> +    struct icmp6 *icmp;
> +    struct ip6 *ip = mtod(m, struct ip6 *);
> +    Slirp *slirp = m->slirp;
> +    int hlen = sizeof(struct ip6);
> +
> +    DEBUG_CALL("icmp6_input");
> +    DEBUG_ARG("m = %lx", (long) m);
> +    DEBUG_ARG("m_len = %d", m->m_len);
> +
> +    if (ntohs(ip->ip_pl) < ICMP6_MINLEN) {
> +        goto end;
> +    }
> +
> +    if (ip6_cksum(m)) {
> +        goto end;
> +    }
> +
> +    m->m_len -= hlen;
> +    m->m_data += hlen;
> +    icmp = mtod(m, struct icmp6 *);
> +    m->m_len += hlen;
> +    m->m_data -= hlen;
> +
> +    DEBUG_ARG("icmp6_type = %d", icmp->icmp6_type);
> +    switch (icmp->icmp6_type) {
> +    case ICMP6_ECHO_REQUEST:
> +        if (in6_equal_host(ip->ip_dst)) {
> +            icmp6_send_echoreply(m, slirp, ip, icmp);
> +        } else {
> +            /* TODO */
> +            error_report("external icmpv6 not supported yet\n");

Please remove the "\n" in the string.

> +        }
> +        break;
> +
> +    case ICMP6_NDP_RS:
> +    case ICMP6_NDP_RA:
> +    case ICMP6_NDP_NS:
> +    case ICMP6_NDP_NA:
> +    case ICMP6_NDP_REDIRECT:
> +        ndp_input(m, slirp, ip, icmp);
> +        break;
> +
> +    case ICMP6_UNREACH:
> +    case ICMP6_TOOBIG:
> +    case ICMP6_TIMXCEED:
> +    case ICMP6_PARAMPROB:
> +        /* XXX? report error? close socket? */
> +    default:
> +        break;
> +    }
> +
> +end:
> +    m_free(m);
> +    return;

Superfluous return statement.

> +}
> diff --git a/slirp/ip6_icmp.h b/slirp/ip6_icmp.h
> new file mode 100644
> index 0000000..1ae003b
> --- /dev/null
> +++ b/slirp/ip6_icmp.h
> @@ -0,0 +1,244 @@
> +/*
> + * Copyright (c) 2013
> + * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
> + *
> + * Please read the file COPYRIGHT for the
> + * terms and conditions of the copyright.
> + */
> +
> +#ifndef _NETINET_ICMP6_H_
> +#define _NETINET_ICMP6_H_

Could you please use "SLIRP_IP6_ICMP_H" or so instead? At least please
don't use underscore in the beginning.

> +
> +/*
> + * Interface Control Message Protocol version 6 Definitions.
> + * Per RFC 4443, March 2006.
> + *
> + * Network Discover Protocol Definitions.
> + * Per RFC 4861, September 2007.
> + */
> +
> +struct icmp6_echo { /* Echo Messages */
> +    uint16_t id;
> +    uint16_t seq_num;
> +};
> +
> +/*
> + * NDP Messages
> + */
> +struct ndp_rs {     /* Router Solicitation Message */
> +    uint32_t reserved;
> +};
> +
> +struct ndp_ra {     /* Router Advertisement Message */
> +    uint8_t chl;    /* Cur Hop Limit */
> +#ifdef HOST_WORDS_BIGENDIAN
> +    uint8_t
> +        M:1,
> +        O:1,
> +        reserved:6;
> +#else
> +    uint8_t
> +        reserved:6,
> +        O:1,
> +        M:1;
> +#endif
> +    uint16_t lifetime;      /* Router Lifetime */
> +    uint32_t reach_time;    /* Reachable Time */
> +    uint32_t retrans_time;  /* Retrans Timer */
> +} QEMU_PACKED;
> +
> +struct ndp_ns {     /* Neighbor Solicitation Message */
> +    uint32_t reserved;
> +    struct in6_addr target; /* Target Address */
> +} QEMU_PACKED;
> +
> +struct ndp_na {     /* Neighbor Advertisement Message */
> +#ifdef HOST_WORDS_BIGENDIAN
> +    uint32_t
> +        R:1,                /* Router Flag */
> +        S:1,                /* Solicited Flag */
> +        O:1,                /* Override Flag */
> +        reserved_hi:5,
> +        reserved_lo:24;
> +#else
> +    uint32_t
> +        reserved_hi:5,
> +        O:1,
> +        S:1,
> +        R:1,
> +        reserved_lo:24;
> +#endif
> +    struct in6_addr target; /* Target Address */
> +} QEMU_PACKED;
> +
> +struct ndp_redirect {
> +    uint32_t reserved;
> +    struct in6_addr target; /* Target Address */
> +    struct in6_addr dest;   /* Destination Address */
> +} QEMU_PACKED;
> +
> +/*
> + * Structure of an icmpv6 header.
> + */
> +struct icmp6 {
> +    uint8_t     icmp6_type;         /* type of message, see below */
> +    uint8_t     icmp6_code;         /* type sub code */
> +    uint16_t    icmp6_cksum;        /* ones complement cksum of struct */
> +    union {
> +        struct icmp6_echo echo;
> +        struct ndp_rs ndp_rs;
> +        struct ndp_ra ndp_ra;
> +        struct ndp_ns ndp_ns;
> +        struct ndp_na ndp_na;
> +        struct ndp_redirect ndp_redirect;
> +    } icmp6_body;
> +#define icmp6_echo icmp6_body.echo
> +#define icmp6_nrs icmp6_body.ndp_rs
> +#define icmp6_nra icmp6_body.ndp_ra
> +#define icmp6_nns icmp6_body.ndp_ns
> +#define icmp6_nna icmp6_body.ndp_na
> +#define icmp6_redirect icmp6_body.ndp_redirect
> +} QEMU_PACKED;
> +
> +#define ICMP6_MINLEN    4
> +#define ICMP6_ECHO_MINLEN   8
> +#define ICMP6_NDP_RS_MINLEN 8
> +#define ICMP6_NDP_RA_MINLEN 16
> +#define ICMP6_NDP_NS_MINLEN 24
> +#define ICMP6_NDP_NA_MINLEN 24
> +#define ICMP6_NDP_REDIRECT_MINLEN 40
> +
> +/*
> + * NDP Options
> + */
> +struct ndpopt {
> +    uint8_t     ndpopt_type;                    /* Option type */
> +    uint8_t     ndpopt_len;                     /* /!\ In units of 8 octets 
> */
> +    union {
> +        unsigned char   linklayer_addr[6];      /* Source/Target Link-layer 
> */
> +        struct prefixinfo {                     /* Prefix Information */
> +            uint8_t     prefix_length;
> +#ifdef HOST_WORDS_BIGENDIAN
> +            uint8_t     L:1, A:1, reserved1:6;
> +#else
> +            uint8_t     reserved1:6, A:1, L:1;
> +#endif
> +            uint32_t    valid_lt;               /* Valid Lifetime */
> +            uint32_t    pref_lt;                /* Preferred Lifetime */
> +            uint32_t    reserved2;
> +            struct in6_addr prefix;
> +        } QEMU_PACKED prefixinfo;
> +    } ndpopt_body;
> +#define ndpopt_linklayer ndpopt_body.linklayer_addr
> +#define ndpopt_prefixinfo ndpopt_body.prefixinfo
> +} QEMU_PACKED;
> +
> +/* NDP options type */
> +#define NDPOPT_LINKLAYER_SOURCE     1   /* Source Link-Layer Address */
> +#define NDPOPT_LINKLAYER_TARGET     2   /* Target Link-Layer Address */
> +#define NDPOPT_PREFIX_INFO          3   /* Prefix Information */
> +#define NDPOPT_REDIRECTED_HDR       4   /* Redirected Header */
> +#define NDPOPT_MTU                  5   /* MTU */
> +
> +/* NDP options size, in octets. */
> +#define NDPOPT_LINKLAYER_LEN    8
> +#define NDPOPT_PREFIXINFO_LEN   32
> +
> +/*
> + * Definition of type and code field values.
> + * Per 
> https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml
> + * Last Updated 2012-11-12
> + */
> +
> +/* Errors */
> +#define ICMP6_UNREACH   1   /* Destination Unreachable */
> +#define     ICMP6_UNREACH_NO_ROUTE      0   /* no route to dest */
> +#define     ICMP6_UNREACH_DEST_PROHIB   1   /* com with dest prohibited */
> +#define     ICMP6_UNREACH_SCOPE         2   /* beyond scope of src addr */
> +#define     ICMP6_UNREACH_ADDRESS       3   /* address unreachable */
> +#define     ICMP6_UNREACH_PORT          4   /* port unreachable */
> +#define     ICMP6_UNREACH_SRC_FAIL      5   /* src addr failed */
> +#define     ICMP6_UNREACH_REJECT_ROUTE  6   /* reject route to dest */
> +#define     ICMP6_UNREACH_SRC_HDR_ERROR 7   /* error in src routing header */
> +#define ICMP6_TOOBIG    2   /* Packet Too Big */
> +#define ICMP6_TIMXCEED  3   /* Time Exceeded */
> +#define     ICMP6_TIMXCEED_INTRANS      0   /* hop limit exceeded in transit 
> */
> +#define     ICMP6_TIMXCEED_REASS        1   /* ttl=0 in reass */
> +#define ICMP6_PARAMPROB 4   /* Parameter Problem */
> +#define     ICMP6_PARAMPROB_HDR_FIELD   0   /* err header field */
> +#define     ICMP6_PARAMPROB_NXTHDR_TYPE 1   /* unrecognized Next Header type 
> */
> +#define     ICMP6_PARAMPROB_IPV6_OPT    2   /* unrecognized IPv6 option */
> +
> +/* Informational Messages */
> +#define ICMP6_ECHO_REQUEST      128 /* Echo Request */
> +#define ICMP6_ECHO_REPLY        129 /* Echo Reply */
> +#define ICMP6_MCASTLST_QUERY    130 /* Multicast Listener Query */
> +#define ICMP6_MCASTLST_REPORT   131 /* Multicast Listener Report */
> +#define ICMP6_MCASTLST_DONE     132 /* Multicast Listener Done */
> +#define ICMP6_NDP_RS            133 /* Router Solicitation (NDP) */
> +#define ICMP6_NDP_RA            134 /* Router Advertisement (NDP) */
> +#define ICMP6_NDP_NS            135 /* Neighbor Solicitation (NDP) */
> +#define ICMP6_NDP_NA            136 /* Neighbor Advertisement (NDP) */
> +#define ICMP6_NDP_REDIRECT      137 /* Redirect Message (NDP) */
> +#define ICMP6_ROUTERRENUM       138 /* Router Renumbering */
> +#define     ICMP6_ROUTERRENUM_COMMAND   0       /* router renum command */
> +#define     ICMP6_ROUTERRENUM_RESULT    1       /* router renum result */
> +#define     ICMP6_ROUTERRENUM_RESET     255     /* sequence number reset */
> +#define ICMP6_NODEINFO_QUERY    139 /* ICMP Node Information Query */
> +#define     ICMP6_NODEINFO_QUERY_IPV6   0       /* subject is an IPv6 */
> +#define     ICMP6_NODEINFO_QUERY_NAME   1       /* subj is a name (or empty) 
> */
> +#define     ICMP6_NODEINFO_QUERY_IPV4   2       /* subject is an IPv4 */
> +#define ICMP6_NODEINFO_RESP     140 /* ICMP Node Information Response */
> +#define     ICMP6_NODEINFO_RESP_SUCCESS 0       /* successful reply */
> +#define     ICMP6_NODEINFO_RESP_REFUSAL 1       /* refuses to supply answer 
> */
> +#define     ICMP6_NODEINFO_RESP_UNKNOWN 2       /* Qtype unknown to the resp 
> */
> +#define ICMP6_IND_S             141 /* Inverse Neighbor Discovery Sol. */
> +#define ICMP6_IND_A             142 /* Inverse Neighbor Discovery Adv. */
> +#define ICMP6_MLD               143 /* Multicast Listener Discovery reports 
> */
> +#define ICMP6_HAAD_REQUEST      144 /* Home Agent Address Discovery Request 
> */
> +#define ICMP6_HAAD_REPLY        145 /* Home Agent Address Discovery Reply */
> +#define ICMP6_MP_SOL            146 /* Mobile Prefix Solicitation */
> +#define ICMP6_MP_ADV            147 /* Mobile Prefix Advertisement */
> +#define ICMP6_SEND_CPS          148 /* Certification Path Solicitation 
> (SEND) */
> +#define ICMP6_SEND_CPA          149 /* Certification Path Adv. (SEND) */
> +#define ICMP6_MRD_RA            151 /* Multicast Router Advertisement (MRD) 
> */
> +#define ICMP6_MRD_RS            152 /* Multicast Router Solicitation (MRD) */
> +#define ICMP6_MRD_TERM          153 /* Multicast Router Termination (MRD) */
> +#define ICMP6_FMIP6             154 /* FMIPv6 Messages */
> +#define     ICMP6_FMIP6_RTSOLPR         2       /* RtSolPr */
> +#define     ICMP6_FMIP6_PRRTADV         3       /* PrRtAdv */
> +#define ICMP6_RPL_CONTROL       155 /* RPL Control Message */
> +#define ICMP6_ILNP6_LU          156 /* ILNPv6 Locator Update Message */
> +#define ICMP6_DUPADDR_REQUEST   157 /* Duplicate Address Request */
> +#define ICMP6_DUPADDR_CONFIRM   158 /* Duplicate Address Confirmation */
> +
> +#define ICMP6_INFOTYPE(type) ((type) >= 128)

A lot of these defines seem to be define in <netinet/icmp6.h> already
(as recommended by RFC 3542) ... would it be feasible to use that
standard header, instead of redefining here everything?

> +/*
> + * Router Configuration Variables (rfc4861#section-6)
> + */
> +#define NDP_IsRouter                1
> +#define NDP_AdvSendAdvertisements   1
> +#define NDP_MaxRtrAdvInterval       600000
> +#define NDP_MinRtrAdvInterval       ((NDP_MaxRtrAdvInterval >= 9) ? \
> +                                        0.33*NDP_MaxRtrAdvInterval : \

Could you use NDP_MaxRtrAdvInterval/3 instead of
0.33*NDP_MaxRtrAdvInterval to avoid the usage of floats here?

> +                                        NDP_MaxRtrAdvInterval)
> +#define NDP_AdvManagedFlag          0
> +#define NDP_AdvOtherConfigFlag      0
> +#define NDP_AdvLinkMTU              0
> +#define NDP_AdvReachableTime        0
> +#define NDP_AdvRetransTime          0
> +#define NDP_AdvCurHopLimit          64
> +#define NDP_AdvDefaultLifetime      ((3 * NDP_MaxRtrAdvInterval) / 1000)
> +#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 ndp_send_ra(Slirp *slirp);
> +void ndp_send_ns(Slirp *slirp, struct in6_addr addr);
> +
> +#endif
...

 Thomas





reply via email to

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