diff options
Diffstat (limited to 'slirp/ip6_icmp.c')
-rw-r--r-- | slirp/ip6_icmp.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c index 9f3fd4a332..9d61349c7d 100644 --- a/slirp/ip6_icmp.c +++ b/slirp/ip6_icmp.c @@ -60,6 +60,72 @@ static void icmp6_send_echoreply(struct mbuf *m, Slirp *slirp, struct ip6 *ip, 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 *); + + DEBUG_CALL("icmp6_send_error"); + DEBUG_ARGS((dfd, " type = %d, code = %d\n", type, code)); + + if (IN6_IS_ADDR_MULTICAST(&ip->ip_src) || + IN6_IS_ADDR_UNSPECIFIED(&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; +#if !defined(_WIN32) || (_WIN32_WINNT >= 0x0600) + char addrstr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &rip->ip_dst, addrstr, INET6_ADDRSTRLEN); + DEBUG_ARG("target = %s", addrstr); +#endif + + 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 */ |