diff options
Diffstat (limited to 'slirp/slirp.c')
-rw-r--r-- | slirp/slirp.c | 61 |
1 files changed, 58 insertions, 3 deletions
diff --git a/slirp/slirp.c b/slirp/slirp.c index 0466d330da..049c2cfb1e 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -210,10 +210,12 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork, 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); @@ -221,6 +223,19 @@ Slirp *slirp_init(int restricted, struct in_addr vnetwork, 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); @@ -251,8 +266,11 @@ void slirp_cleanup(Slirp *slirp) 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); @@ -744,6 +762,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_IPV6: m = m_get(slirp); if (!m) return; @@ -757,8 +776,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; - ip_input(m); + if (proto == ETH_P_IP) { + ip_input(m); + } else if (proto == ETH_P_IPV6) { + ip6_input(m); + } break; + default: break; } @@ -826,6 +850,31 @@ static int if_encap4(Slirp *slirp, struct mbuf *ifm, struct ethhdr *eh, } } +/* 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. */ @@ -849,9 +898,15 @@ int if_encap(Slirp *slirp, struct mbuf *ifm) } 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; } |