aboutsummaryrefslogtreecommitdiff
path: root/slirp/ip6_icmp.c
diff options
context:
space:
mode:
authorYann Bordenave <meow@meowstars.org>2016-03-15 10:31:19 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2016-03-15 10:35:04 +0100
commitfc6c9257c6dd47316a1c55d356bcd89bdc5fd642 (patch)
treea3a46ef4bd2c113b7a90167c7b41b6dd1c81a02c /slirp/ip6_icmp.c
parentde40abfecfe17f79870a66acfc1f87a53fc066ca (diff)
downloadqemu-fc6c9257c6dd47316a1c55d356bcd89bdc5fd642.zip
qemu-fc6c9257c6dd47316a1c55d356bcd89bdc5fd642.tar.gz
qemu-fc6c9257c6dd47316a1c55d356bcd89bdc5fd642.tar.bz2
slirp: Adding ICMPv6 error sending
Adding icmp6_send_error to send ICMPv6 Error messages. This function is simpler than the v4 version. Adding some calls in various functions to send ICMP errors, when a received packet is too big, or when its hop limit is 0. Signed-off-by: Yann Bordenave <meow@meowstars.org> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org> Reviewed-by: Thomas Huth <thuth@redhat.com>
Diffstat (limited to 'slirp/ip6_icmp.c')
-rw-r--r--slirp/ip6_icmp.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c
index 9f3fd4a..9d61349 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
*/