@@ -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
*/
@@ -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);
@@ -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;
@@ -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);
}
@@ -197,7 +197,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 */
@@ -243,7 +243,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;
@@ -251,7 +251,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);
@@ -441,7 +441,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! */
@@ -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);
@@ -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);
}
@@ -459,7 +459,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! */
@@ -507,7 +507,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 {
/*
@@ -601,7 +601,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);
@@ -217,7 +217,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;
}
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 <meow@meowstars.org> --- 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(-)