aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2015-05-11 12:45:14 +0100
committerMichael Brown <mcb30@ipxe.org>2015-05-11 12:45:14 +0100
commit86aa959561be5a1cc075c8c60c2f9fdc37ab9272 (patch)
treecf3279e296f4c56166eb9ffe9621fee140e734c8
parentbb6d7bebe95b619f6d0fe9066016b5020f381032 (diff)
downloadipxe-86aa959561be5a1cc075c8c60c2f9fdc37ab9272.tar.gz
[ipv6] Disambiguate received ICMPv6 errors
Originally-implemented-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/include/ipxe/icmpv6.h12
-rw-r--r--src/net/icmpv6.c80
2 files changed, 90 insertions, 2 deletions
diff --git a/src/include/ipxe/icmpv6.h b/src/include/ipxe/icmpv6.h
index db5bec2d..0474ddca 100644
--- a/src/include/ipxe/icmpv6.h
+++ b/src/include/ipxe/icmpv6.h
@@ -40,6 +40,18 @@ struct icmpv6_handler {
/** Declare an ICMPv6 handler */
#define __icmpv6_handler __table_entry ( ICMPV6_HANDLERS, 01 )
+/** ICMPv6 destination unreachable */
+#define ICMPV6_DESTINATION_UNREACHABLE 1
+
+/** ICMPv6 packet too big */
+#define ICMPV6_PACKET_TOO_BIG 2
+
+/** ICMPv6 time exceeded */
+#define ICMPV6_TIME_EXCEEDED 3
+
+/** ICMPv6 parameter problem */
+#define ICMPV6_PARAMETER_PROBLEM 4
+
/** ICMPv6 echo request */
#define ICMPV6_ECHO_REQUEST 128
diff --git a/src/net/icmpv6.c b/src/net/icmpv6.c
index 45a34440..8555aaf0 100644
--- a/src/net/icmpv6.c
+++ b/src/net/icmpv6.c
@@ -38,6 +38,65 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
+/* Disambiguate the various error causes */
+#define EHOSTUNREACH_ROUTE \
+ __einfo_error ( EINFO_EHOSTUNREACH_ROUTE )
+#define EINFO_EHOSTUNREACH_ROUTE \
+ __einfo_uniqify ( EINFO_EHOSTUNREACH, 0, \
+ "No route to destination" )
+#define EHOSTUNREACH_PROHIBITED \
+ __einfo_error ( EINFO_EHOSTUNREACH_PROHIBITED )
+#define EINFO_EHOSTUNREACH_PROHIBITED \
+ __einfo_uniqify ( EINFO_EHOSTUNREACH, 1, \
+ "Communication administratively prohibited" )
+#define EHOSTUNREACH_ADDRESS \
+ __einfo_error ( EINFO_EHOSTUNREACH_ADDRESS )
+#define EINFO_EHOSTUNREACH_ADDRESS \
+ __einfo_uniqify ( EINFO_EHOSTUNREACH, 3, \
+ "Address unreachable" )
+#define EHOSTUNREACH_PORT \
+ __einfo_error ( EINFO_EHOSTUNREACH_PORT )
+#define EINFO_EHOSTUNREACH_PORT \
+ __einfo_uniqify ( EINFO_EHOSTUNREACH, 4, \
+ "Port unreachable" )
+#define EHOSTUNREACH_CODE( code ) \
+ EUNIQ ( EINFO_EHOSTUNREACH, ( (code) & 0x1f ), \
+ EHOSTUNREACH_ROUTE, EHOSTUNREACH_PROHIBITED, \
+ EHOSTUNREACH_ADDRESS, EHOSTUNREACH_PORT )
+
+#define ETIMEDOUT_HOP \
+ __einfo_error ( EINFO_ETIMEDOUT_HOP )
+#define EINFO_ETIMEDOUT_HOP \
+ __einfo_uniqify ( EINFO_ETIMEDOUT, 0, \
+ "Hop limit exceeded in transit" )
+#define ETIMEDOUT_REASSEMBLY \
+ __einfo_error ( EINFO_ETIMEDOUT_REASSEMBLY )
+#define EINFO_ETIMEDOUT_REASSEMBLY \
+ __einfo_uniqify ( EINFO_ETIMEDOUT, 1, \
+ "Fragment reassembly time exceeded" )
+#define ETIMEDOUT_CODE( code ) \
+ EUNIQ ( EINFO_ETIMEDOUT, ( (code) & 0x1f ), \
+ ETIMEDOUT_HOP, ETIMEDOUT_REASSEMBLY )
+
+#define EPROTO_BAD_HEADER \
+ __einfo_error ( EINFO_EPROTO_BAD_HEADER )
+#define EINFO_EPROTO_BAD_HEADER \
+ __einfo_uniqify ( EINFO_EPROTO, 0, \
+ "Erroneous header field" )
+#define EPROTO_NEXT_HEADER \
+ __einfo_error ( EINFO_EPROTO_NEXT_HEADER )
+#define EINFO_EPROTO_NEXT_HEADER \
+ __einfo_uniqify ( EINFO_EPROTO, 1, \
+ "Unrecognised next header type" )
+#define EPROTO_OPTION \
+ __einfo_error ( EINFO_EPROTO_OPTION )
+#define EINFO_EPROTO_OPTION \
+ __einfo_uniqify ( EINFO_EPROTO, 2, \
+ "Unrecognised IPv6 option" )
+#define EPROTO_CODE( code ) \
+ EUNIQ ( EINFO_EPROTO, ( (code) & 0x1f ), \
+ EPROTO_BAD_HEADER, EPROTO_NEXT_HEADER, EPROTO_OPTION )
+
struct icmp_echo_protocol icmpv6_echo_protocol __icmp_echo_protocol;
/**
@@ -148,8 +207,25 @@ static int icmpv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
/* Identify handler */
handler = icmpv6_handler ( icmp->type );
if ( ! handler ) {
- DBGC ( netdev, "ICMPv6 unrecognised type %d\n", icmp->type );
- rc = -ENOTSUP;
+ switch ( icmp->type ) {
+ case ICMPV6_DESTINATION_UNREACHABLE:
+ rc = -EHOSTUNREACH_CODE ( icmp->code );
+ break;
+ case ICMPV6_PACKET_TOO_BIG:
+ rc = -ERANGE;
+ break;
+ case ICMPV6_TIME_EXCEEDED:
+ rc = -ETIMEDOUT_CODE ( icmp->code );
+ break;
+ case ICMPV6_PARAMETER_PROBLEM:
+ rc = -EPROTO_CODE ( icmp->code );
+ break;
+ default:
+ DBGC ( netdev, "ICMPv6 unrecognised type %d code %d\n",
+ icmp->type, icmp->code );
+ rc = -ENOTSUP;
+ break;
+ };
goto done;
}