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; }