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>
This commit is contained in:
Yann Bordenave 2016-03-15 10:31:19 +01:00 committed by Samuel Thibault
parent de40abfecf
commit fc6c9257c6
3 changed files with 84 additions and 3 deletions

View File

@ -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
*/

View File

@ -19,6 +19,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
*/
@ -82,6 +88,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;
@ -89,6 +96,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
@ -98,6 +106,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
@ -197,6 +206,7 @@ struct ndpopt {
void icmp6_init(Slirp *slirp);
void icmp6_cleanup(Slirp *slirp);
void icmp6_input(struct mbuf *);
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);

View File

@ -39,9 +39,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) {
/*icmp_send_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl");*/
icmp6_send_error(m, ICMP6_TIMXCEED, ICMP6_TIMXCEED_INTRANS);
goto bad;
}
@ -50,10 +55,10 @@ void ip6_input(struct mbuf *m)
*/
switch (ip6->ip_nh) {
case IPPROTO_TCP:
/*tcp_input(m, hlen, (struct socket *)NULL);*/
icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
break;
case IPPROTO_UDP:
/*udp_input(m, hlen);*/
icmp6_send_error(m, ICMP6_UNREACH, ICMP6_UNREACH_NO_ROUTE);
break;
case IPPROTO_ICMPV6:
icmp6_input(m);