aboutsummaryrefslogtreecommitdiff
path: root/slirp/src/ip6_icmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'slirp/src/ip6_icmp.c')
m---------slirp0
-rw-r--r--slirp/src/ip6_icmp.c438
2 files changed, 0 insertions, 438 deletions
diff --git a/slirp b/slirp
new file mode 160000
+Subproject 59a1b1f165458c2acb7ff0525b543945f741622
diff --git a/slirp/src/ip6_icmp.c b/slirp/src/ip6_icmp.c
deleted file mode 100644
index 5642457fdd..0000000000
--- a/slirp/src/ip6_icmp.c
+++ /dev/null
@@ -1,438 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Copyright (c) 2013
- * Guillaume Subiron, Yann Bordenave, Serigne Modou Wagne.
- */
-
-#include "slirp.h"
-#include "ip6_icmp.h"
-
-#define NDP_Interval g_rand_int_range(slirp->grand, \
- NDP_MinRtrAdvInterval, NDP_MaxRtrAdvInterval)
-
-static void ra_timer_handler(void *opaque)
-{
- Slirp *slirp = opaque;
-
- slirp->cb->timer_mod(slirp->ra_timer,
- slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS + NDP_Interval,
- slirp->opaque);
- ndp_send_ra(slirp);
-}
-
-void icmp6_init(Slirp *slirp)
-{
- if (!slirp->in6_enabled) {
- return;
- }
-
- slirp->ra_timer = slirp->cb->timer_new(ra_timer_handler, slirp, slirp->opaque);
- slirp->cb->timer_mod(slirp->ra_timer,
- slirp->cb->clock_get_ns(slirp->opaque) / SCALE_MS + NDP_Interval,
- slirp->opaque);
-}
-
-void icmp6_cleanup(Slirp *slirp)
-{
- if (!slirp->in6_enabled) {
- return;
- }
-
- slirp->cb->timer_free(slirp->ra_timer, slirp->opaque);
-}
-
-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 *);
- 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 *);
- 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);
-}
-
-void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code)
-{
- Slirp *slirp = m->slirp;
- struct mbuf *t;
- struct ip6 *ip = mtod(m, struct ip6 *);
- char addrstr[INET6_ADDRSTRLEN];
-
- DEBUG_CALL("icmp6_send_error");
- DEBUG_ARG("type = %d, code = %d", type, code);
-
- if (IN6_IS_ADDR_MULTICAST(&ip->ip_src) ||
- in6_zero(&ip->ip_src)) {
- /* TODO icmp error? */
- return;
- }
-
- t = m_get(slirp);
-
- /* IPv6 packet */
- struct ip6 *rip = mtod(t, struct ip6 *);
- rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
- rip->ip_dst = ip->ip_src;
- inet_ntop(AF_INET6, &rip->ip_dst, addrstr, INET6_ADDRSTRLEN);
- DEBUG_ARG("target = %s", addrstr);
-
- rip->ip_nh = IPPROTO_ICMPV6;
- const int error_data_len = MIN(m->m_len,
- IF_MTU - (sizeof(struct ip6) + ICMP6_ERROR_MINLEN));
- rip->ip_pl = htons(ICMP6_ERROR_MINLEN + error_data_len);
- t->m_len = sizeof(struct ip6) + ntohs(rip->ip_pl);
-
- /* ICMPv6 packet */
- t->m_data += sizeof(struct ip6);
- struct icmp6 *ricmp = mtod(t, struct icmp6 *);
- ricmp->icmp6_type = type;
- ricmp->icmp6_code = code;
- ricmp->icmp6_cksum = 0;
-
- switch (type) {
- case ICMP6_UNREACH:
- case ICMP6_TIMXCEED:
- ricmp->icmp6_err.unused = 0;
- break;
- case ICMP6_TOOBIG:
- ricmp->icmp6_err.mtu = htonl(IF_MTU);
- break;
- case ICMP6_PARAMPROB:
- /* TODO: Handle this case */
- break;
- default:
- g_assert_not_reached();
- break;
- }
- t->m_data += ICMP6_ERROR_MINLEN;
- memcpy(t->m_data, m->m_data, error_data_len);
-
- /* Checksum */
- t->m_data -= ICMP6_ERROR_MINLEN;
- t->m_data -= sizeof(struct ip6);
- ricmp->icmp6_cksum = ip6_cksum(t);
-
- ip6_output(NULL, t, 0);
-}
-
-/*
- * 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 *);
- size_t pl_size = 0;
- struct in6_addr addr;
- uint32_t scope_id;
-
- rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR;
- rip->ip_dst = (struct in6_addr)ALLNODES_MULTICAST;
- rip->ip_nh = IPPROTO_ICMPV6;
-
- /* Build ICMPv6 packet */
- t->m_data += sizeof(struct ip6);
- struct icmp6 *ricmp = mtod(t, struct icmp6 *);
- 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);
- t->m_data += ICMP6_NDP_RA_MINLEN;
- pl_size += ICMP6_NDP_RA_MINLEN;
-
- /* Source link-layer address (NDP option) */
- struct ndpopt *opt = mtod(t, struct ndpopt *);
- opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
- opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
- in6_compute_ethaddr(rip->ip_src, opt->ndpopt_linklayer);
- t->m_data += NDPOPT_LINKLAYER_LEN;
- pl_size += NDPOPT_LINKLAYER_LEN;
-
- /* Prefix information (NDP option) */
- struct ndpopt *opt2 = mtod(t, struct ndpopt *);
- 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;
- t->m_data += NDPOPT_PREFIXINFO_LEN;
- pl_size += NDPOPT_PREFIXINFO_LEN;
-
- /* Prefix information (NDP option) */
- if (get_dns6_addr(&addr, &scope_id) >= 0) {
- /* Host system does have an IPv6 DNS server, announce our proxy. */
- struct ndpopt *opt3 = mtod(t, struct ndpopt *);
- opt3->ndpopt_type = NDPOPT_RDNSS;
- opt3->ndpopt_len = NDPOPT_RDNSS_LEN / 8;
- opt3->ndpopt_rdnss.reserved = 0;
- opt3->ndpopt_rdnss.lifetime = htonl(2 * NDP_MaxRtrAdvInterval);
- opt3->ndpopt_rdnss.addr = slirp->vnameserver_addr6;
- t->m_data += NDPOPT_RDNSS_LEN;
- pl_size += NDPOPT_RDNSS_LEN;
- }
-
- rip->ip_pl = htons(pl_size);
- t->m_data -= sizeof(struct ip6) + pl_size;
- t->m_len = sizeof(struct ip6) + pl_size;
-
- /* ICMPv6 Checksum */
- ricmp->icmp6_cksum = ip6_cksum(t);
-
- ip6_output(NULL, t, 0);
-}
-
-/*
- * Send NDP Neighbor Solitication
- */
-void ndp_send_ns(Slirp *slirp, struct in6_addr addr)
-{
- char addrstr[INET6_ADDRSTRLEN];
-
- inet_ntop(AF_INET6, &addr, addrstr, INET6_ADDRSTRLEN);
-
- DEBUG_CALL("ndp_send_ns");
- DEBUG_ARG("target = %s", addrstr);
-
- /* Build IPv6 packet */
- struct mbuf *t = m_get(slirp);
- struct ip6 *rip = mtod(t, struct ip6 *);
- rip->ip_src = slirp->vhost_addr6;
- rip->ip_dst = (struct in6_addr)SOLICITED_NODE_PREFIX;
- memcpy(&rip->ip_dst.s6_addr[13], &addr.s6_addr[13], 3);
- rip->ip_nh = IPPROTO_ICMPV6;
- rip->ip_pl = htons(ICMP6_NDP_NS_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_NS;
- ricmp->icmp6_code = 0;
- ricmp->icmp6_cksum = 0;
-
- /* NDP */
- ricmp->icmp6_nns.reserved = 0;
- ricmp->icmp6_nns.target = addr;
-
- /* Build NDP option */
- t->m_data += ICMP6_NDP_NS_MINLEN;
- struct ndpopt *opt = mtod(t, struct ndpopt *);
- opt->ndpopt_type = NDPOPT_LINKLAYER_SOURCE;
- opt->ndpopt_len = NDPOPT_LINKLAYER_LEN / 8;
- in6_compute_ethaddr(slirp->vhost_addr6, 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, 1);
-}
-
-/*
- * Send NDP Neighbor Advertisement
- */
-static void ndp_send_na(Slirp *slirp, struct ip6 *ip, struct icmp6 *icmp)
-{
- /* 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_zero(&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_IS_ADDR_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);
-}
-
-/*
- * 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;
-
- switch (icmp->icmp6_type) {
- case ICMP6_NDP_RS:
- DEBUG_CALL(" type = Router Solicitation");
- 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 = Router Advertisement");
- slirp->cb->guest_error("Warning: guest sent NDP RA, but shouldn't",
- slirp->opaque);
- break;
-
- case ICMP6_NDP_NS:
- DEBUG_CALL(" type = Neighbor Solicitation");
- if (ip->ip_hl == 255
- && icmp->icmp6_code == 0
- && !IN6_IS_ADDR_MULTICAST(&icmp->icmp6_nns.target)
- && ntohs(ip->ip_pl) >= ICMP6_NDP_NS_MINLEN
- && (!in6_zero(&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);
- ndp_send_na(slirp, ip, icmp);
- }
- }
- 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_IS_ADDR_MULTICAST(&icmp->icmp6_nna.target)
- && (!IN6_IS_ADDR_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");
- slirp->cb->guest_error(
- "Warning: guest sent NDP REDIRECT, but shouldn't", slirp->opaque);
- break;
- }
-}
-
-/*
- * 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 = %p", 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 */
- g_critical("external icmpv6 not supported yet");
- }
- 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);
-}