summaryrefslogtreecommitdiffstats
path: root/slirp/ip6_output.c
blob: 762cbfe89c13ab058834f8953c7ae668e5eb53b1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*
 * Copyright (c) 2013
 * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
 */

#include "qemu/osdep.h"
#include "qemu-common.h"
#include "slirp.h"

/* Number of packets queued before we start sending
 * (to prevent allocing too many mbufs) */
#define IF6_THRESH 10

/*
 * IPv6 output. The packet in mbuf chain m contains a IP header
 */
int ip6_output(struct socket *so, struct mbuf *m, int fast)
{
    struct ip6 *ip = mtod(m, struct ip6 *);

    DEBUG_CALL("ip6_output");
    DEBUG_ARG("so = %lx", (long)so);
    DEBUG_ARG("m = %lx", (long)m);

    /* Fill IPv6 header */
    ip->ip_v = IP6VERSION;
    ip->ip_hl = IP6_HOP_LIMIT;
    ip->ip_tc_hi = 0;
    ip->ip_tc_lo = 0;
    ip->ip_fl_hi = 0;
    ip->ip_fl_lo = 0;

    if (fast) {
        if_encap(m->slirp, m);
    } else {
        if_output(so, m);
    }

    return 0;
}
='#n120'>120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141









































































                                                                                




                                                                           





























































                                                                    
/*
 * Copyright (c) 2013
 * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
 */

#ifndef SLIRP_IP6_H_
#define SLIRP_IP6_H_

#include "net/eth.h"

#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 bool in6_equal(const struct in6_addr *a, const struct in6_addr *b)
{
    return memcmp(a, b, sizeof(*a)) == 0;
}

static inline bool in6_equal_net(const struct in6_addr *a,
                                 const struct in6_addr *b,
                                 int prefix_len)
{
    if (memcmp(a, b, prefix_len / 8) != 0) {
        return 0;
    }

    if (prefix_len % 8 == 0) {
        return 1;
    }

    return a->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8))
        == b->s6_addr[prefix_len / 8] >> (8 - (prefix_len % 8));
}

static inline bool in6_equal_mach(const struct in6_addr *a,
                                  const 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)\
    ((in6_equal_net(a, &slirp->vprefix_addr6, slirp->vprefix_len)\
      && in6_equal_mach(a, &slirp->vnameserver_addr6, slirp->vprefix_len))\
  || (in6_equal_net(a, &(struct in6_addr)LINKLOCAL_ADDR, 64)\
      && in6_equal_mach(a, &slirp->vnameserver_addr6, 64)))

#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;