slirp_init_once();
+ slirp->grand = g_rand_new();
slirp->restricted = restricted;
if_init(slirp);
ip_init(slirp);
+ ip6_init(slirp);
/* Initialise mbufs *after* setting the MTU */
m_init(slirp);
slirp->vnetwork_addr = vnetwork;
slirp->vnetwork_mask = vnetmask;
slirp->vhost_addr = vhost;
+#if defined(_WIN32) && (_WIN32_WINNT < 0x0600)
+ /* No inet_pton helper... */
+ memset(&slirp->vprefix_addr6, 0, sizeof(slirp->vprefix_addr6));
+ slirp->vprefix_addr6.s6_addr[0] = 0xfe;
+ slirp->vprefix_addr6.s6_addr[1] = 0xc0;
+ slirp->vprefix_len = 64;
+ slirp->vhost_addr6 = slirp->vprefix_addr6;
+ slirp->vhost_addr6.s6_addr[15] = 0x2;
+#else
+ inet_pton(AF_INET6, "fec0::0", &slirp->vprefix_addr6);
+ slirp->vprefix_len = 64;
+ inet_pton(AF_INET6, "fec0::2", &slirp->vhost_addr6);
+#endif
if (vhostname) {
pstrcpy(slirp->client_hostname, sizeof(slirp->client_hostname),
vhostname);
unregister_savevm(NULL, "slirp", slirp);
ip_cleanup(slirp);
+ ip6_cleanup(slirp);
m_cleanup(slirp);
+ g_rand_free(slirp->grand);
+
g_free(slirp->vdnssearch);
g_free(slirp->tftp_prefix);
g_free(slirp->bootp_filename);
arp_input(slirp, pkt, pkt_len);
break;
case ETH_P_IP:
+ case ETH_P_IPV6:
m = m_get(slirp);
if (!m)
return;
m->m_data += 2 + ETH_HLEN;
m->m_len -= 2 + ETH_HLEN;
- ip_input(m);
+ if (proto == ETH_P_IP) {
+ ip_input(m);
+ } else if (proto == ETH_P_IPV6) {
+ ip6_input(m);
+ }
break;
+
default:
break;
}
}
}
+/* Prepare the IPv6 packet to be sent to the ethernet device. Returns 1 if no
+ * packet should be sent, 0 if the packet must be re-queued, 2 if the packet
+ * is ready to go.
+ */
+static int if_encap6(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh,
+ uint8_t ethaddr[ETH_ALEN])
+{
+ const struct ip6 *ip6h = mtod(ifm, const struct ip6 *);
+ if (!ndp_table_search(slirp, ip6h->ip_dst, ethaddr)) {
+ if (!ifm->resolution_requested) {
+ ndp_send_ns(slirp, ip6h->ip_dst);
+ ifm->resolution_requested = true;
+ ifm->expiration_date =
+ qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + 1000000000ULL;
+ }
+ return 0;
+ } else {
+ eh->h_proto = htons(ETH_P_IPV6);
+ in6_compute_ethaddr(ip6h->ip_src, eh->h_source);
+
+ /* Send this */
+ return 2;
+ }
+}
+
/* Output the IP packet to the ethernet device. Returns 0 if the packet must be
* re-queued.
*/
}
break;
+ case IP6VERSION:
+ ret = if_encap6(slirp, ifm, eh, ethaddr);
+ if (ret < 2) {
+ return ret;
+ }
+ break;
+
default:
- /* Do not assert while we don't manage IP6VERSION */
- /* assert(0); */
+ g_assert_not_reached();
break;
}