From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:52471) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WUO8u-0006fd-H9 for qemu-devel@nongnu.org; Sun, 30 Mar 2014 18:23:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WUO8o-0002eD-4K for qemu-devel@nongnu.org; Sun, 30 Mar 2014 18:23:52 -0400 Received: from toccata.ens-lyon.org ([140.77.166.68]:40717) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WUO8n-0002e2-P9 for qemu-devel@nongnu.org; Sun, 30 Mar 2014 18:23:46 -0400 From: Samuel Thibault Date: Mon, 31 Mar 2014 00:23:02 +0200 Message-Id: <1396218189-14422-12-git-send-email-samuel.thibault@ens-lyon.org> In-Reply-To: <1396218189-14422-1-git-send-email-samuel.thibault@ens-lyon.org> References: <1396218189-14422-1-git-send-email-samuel.thibault@ens-lyon.org> Subject: [Qemu-devel] [PATCH 11/18] slirp: Adding ICMPv6 error sending List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Stefan Hajnoczi , Yann Bordenave , Jan Kiszka , Samuel Thibault , Guillaume Subiron Disambiguation : icmp_error is renamed into icmp_send_error, since it doesn't manage errors, but only sends ICMP Error messages. 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 --- slirp/ip6_icmp.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ slirp/ip6_icmp.h | 10 ++++++++++ slirp/ip6_input.c | 16 ++++++++------- slirp/ip_icmp.c | 12 +++++------ slirp/ip_icmp.h | 4 ++-- slirp/ip_input.c | 8 ++++---- slirp/socket.c | 4 ++-- slirp/tcp_input.c | 2 +- slirp/udp.c | 3 ++- 9 files changed, 96 insertions(+), 23 deletions(-) diff --git a/slirp/ip6_icmp.c b/slirp/ip6_icmp.c index 4538bfd..8952bbc 100644 --- a/slirp/ip6_icmp.c +++ b/slirp/ip6_icmp.c @@ -64,6 +64,66 @@ 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 = m_get(slirp); + struct ip6 *ip = mtod(m, struct ip6 *); + + char addrstr[INET6_ADDRSTRLEN]; + DEBUG_CALL("icmp_send_error"); + DEBUG_ARGS((dfd, " type = %d, code = %d\n", type, code)); + + /* IPv6 packet */ + struct ip6 *rip = mtod(t, struct ip6 *); + rip->ip_src = (struct in6_addr)LINKLOCAL_ADDR; + if (in6_multicast(ip->ip_src) || in6_unspecified(ip->ip_src)) { + /* :TODO:maethor:130317: icmp error? */ + return; + } + 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:Meow:130316: Handle this case */ + break; + default: + assert(0); + 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); +} + /* * Process a NDP message */ diff --git a/slirp/ip6_icmp.h b/slirp/ip6_icmp.h index bd9d3d9..deae1a1 100644 --- a/slirp/ip6_icmp.h +++ b/slirp/ip6_icmp.h @@ -22,6 +22,12 @@ struct icmp6_echo { /* Echo Messages */ uint16_t seq_num; }; +union icmp6_error_body { + uint32_t unused; + uint32_t pointer; + uint32_t mtu; +}; + /* * NDP Messages */ @@ -85,6 +91,7 @@ struct icmp6 { uint8_t icmp6_code; /* type sub code */ uint16_t icmp6_cksum; /* ones complement cksum of struct */ union { + union icmp6_error_body error_body; struct icmp6_echo echo; struct ndp_rs ndp_rs; struct ndp_ra ndp_ra; @@ -92,6 +99,7 @@ struct icmp6 { struct ndp_na ndp_na; struct ndp_redirect ndp_redirect; } icmp6_body; +#define icmp6_err icmp6_body.error_body #define icmp6_echo icmp6_body.echo #define icmp6_nrs icmp6_body.ndp_rs #define icmp6_nra icmp6_body.ndp_ra @@ -101,6 +109,7 @@ struct icmp6 { } QEMU_PACKED; #define ICMP6_MINLEN 4 +#define ICMP6_ERROR_MINLEN 8 #define ICMP6_ECHO_MINLEN 8 #define ICMP6_NDP_RS_MINLEN 8 #define ICMP6_NDP_RA_MINLEN 16 @@ -242,6 +251,7 @@ void icmp6_input(struct mbuf *); void icmp6_error(struct mbuf *msrc, u_char type, u_char code, int minsize, const char *message); */ +void icmp6_send_error(struct mbuf *m, uint8_t type, uint8_t code); void ndp_send_ra(Slirp *slirp); void ndp_send_ns(Slirp *slirp, struct in6_addr addr); diff --git a/slirp/ip6_input.c b/slirp/ip6_input.c index 9663c42..af098a5 100644 --- a/slirp/ip6_input.c +++ b/slirp/ip6_input.c @@ -33,7 +33,7 @@ void ip6_input(struct mbuf *m) DEBUG_ARG("m_len = %d", m->m_len); if (m->m_len < sizeof(struct ip6)) { - return; + goto bad; } ip6 = mtod(m, struct ip6 *); @@ -42,10 +42,14 @@ void ip6_input(struct mbuf *m) goto bad; } + if (ntohs(ip6->ip_pl) > IF_MTU) { + icmp6_send_error(m, ICMP6_TOOBIG, 0); + goto bad; + } + /* check ip_ttl for a correct ICMP reply */ if (ip6->ip_hl == 0) { - /* :TODO:maethor:130307: icmp6_error */ - /*icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");*/ + icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS); goto bad; } @@ -53,16 +57,14 @@ void ip6_input(struct mbuf *m) * Switch out to protocol's input routine. */ switch (ip6->ip_nh) { -#if 0 case IPPROTO_TCP: /* :TODO:maethor:130307: TCP */ - tcp_input(m, hlen, (struct socket *)NULL); + icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE); break; case IPPROTO_UDP: /* :TODO:maethor:130312: UDP */ - udp_input(m, hlen); + icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE); break; -#endif case IPPROTO_ICMPV6: icmp6_input(m); break; diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c index 382b5dd..c896574 100644 --- a/slirp/ip_icmp.c +++ b/slirp/ip_icmp.c @@ -37,7 +37,7 @@ /* Be nice and tell them it's just a pseudo-ping packet */ static const char icmp_ping_msg[] = "This is a pseudo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; -/* list of actions for icmp_error() on RX of an icmp message */ +/* list of actions for icmp_send_error() on RX of an icmp message */ static const int icmp_flush[19] = { /* ECHO REPLY (0) */ 0, 1, @@ -100,7 +100,7 @@ static int icmp_send(struct socket *so, struct mbuf *m, int hlen) (struct sockaddr *)&addr, sizeof(addr)) == -1) { DEBUG_MISC((dfd, "icmp_input icmp sendto tx errno = %d-%s\n", errno, strerror(errno))); - icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno)); + icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno)); icmp_detach(so); } @@ -188,7 +188,7 @@ icmp_input(struct mbuf *m, int hlen) (struct sockaddr *)&addr, sizeof(addr)) == -1) { DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n", errno,strerror(errno))); - icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); + icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, strerror(errno)); udp_detach(so); } } /* if ip->ip_dst.s_addr == alias_addr.s_addr */ @@ -234,7 +234,7 @@ end_error: #define ICMP_MAXDATALEN (IP_MSS-28) void -icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize, +icmp_send_error(struct mbuf *msrc, u_char type, u_char code, int minsize, const char *message) { unsigned hlen, shlen, s_ip_len; @@ -242,7 +242,7 @@ icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize, register struct icmp *icp; register struct mbuf *m; - DEBUG_CALL("icmp_error"); + DEBUG_CALL("icmp_send_error"); DEBUG_ARG("msrc = %lx", (long )msrc); DEBUG_ARG("msrc_len = %d", msrc->m_len); @@ -432,7 +432,7 @@ void icmp_receive(struct socket *so) } DEBUG_MISC((dfd, " udp icmp rx errno = %d-%s\n", errno, strerror(errno))); - icmp_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno)); + icmp_send_error(so->so_m, ICMP_UNREACH, error_code, 0, strerror(errno)); } else { icmp_reflect(so->so_m); so->so_m = NULL; /* Don't m_free() it again! */ diff --git a/slirp/ip_icmp.h b/slirp/ip_icmp.h index be4426b..846761d 100644 --- a/slirp/ip_icmp.h +++ b/slirp/ip_icmp.h @@ -156,8 +156,8 @@ struct icmp { void icmp_init(Slirp *slirp); void icmp_cleanup(Slirp *slirp); void icmp_input(struct mbuf *, int); -void icmp_error(struct mbuf *msrc, u_char type, u_char code, int minsize, - const char *message); +void icmp_send_error(struct mbuf *msrc, u_char type, u_char code, int minsize, + const char *message); void icmp_reflect(struct mbuf *); void icmp_receive(struct socket *so); void icmp_detach(struct socket *so); diff --git a/slirp/ip_input.c b/slirp/ip_input.c index 880bdfd..1925cdc 100644 --- a/slirp/ip_input.c +++ b/slirp/ip_input.c @@ -131,9 +131,9 @@ ip_input(struct mbuf *m) m_adj(m, ip->ip_len - m->m_len); /* check ip_ttl for a correct ICMP reply */ - if(ip->ip_ttl==0) { - icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl"); - goto bad; + if (ip->ip_ttl == 0) { + icmp_send_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0, "ttl"); + goto bad; } /* @@ -636,7 +636,7 @@ typedef uint32_t n_time; } return (0); bad: - icmp_error(m, type, code, 0, 0); + icmp_send_error(m, type, code, 0, 0); return (1); } diff --git a/slirp/socket.c b/slirp/socket.c index 0e37a52..f333fcf 100644 --- a/slirp/socket.c +++ b/slirp/socket.c @@ -462,7 +462,7 @@ sorecvfrom(struct socket *so) DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n", errno,strerror(errno))); - icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); + icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno)); } else { icmp_reflect(so->so_m); so->so_m = NULL; /* Don't m_free() it again! */ @@ -510,7 +510,7 @@ sorecvfrom(struct socket *so) else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code)); - icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); + icmp_send_error(so->so_m, ICMP_UNREACH, code, 0, strerror(errno)); m_free(m); } else { /* diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c index 4c72430..25929bd 100644 --- a/slirp/tcp_input.c +++ b/slirp/tcp_input.c @@ -599,7 +599,7 @@ findso: m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); m->m_len += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); *ip=save_ip; - icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno)); + icmp_send_error(m, ICMP_UNREACH, code, 0, strerror(errno)); } tcp_close(tp); m_free(m); diff --git a/slirp/udp.c b/slirp/udp.c index d5be05f..f53ee11 100644 --- a/slirp/udp.c +++ b/slirp/udp.c @@ -206,7 +206,8 @@ udp_input(register struct mbuf *m, int iphlen) m->m_data -= iphlen; *ip=save_ip; DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno))); - icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); + icmp_send_error(m, ICMP_UNREACH, ICMP_UNREACH_NET, 0, + strerror(errno)); goto bad; } -- 1.9.0