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 - maet...@subiron.org > GPG - C7C4 455C > Jabber - maet...@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 = 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 - maet...@subiron.org GPG - C7C4 455C Jabber - maet...@im.subiron.org IRC - maethor@(freenode|geeknode)