You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

icmpv6.c 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Copyright (C) 2013 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. FILE_LICENCE ( GPL2_OR_LATER );
  20. #include <string.h>
  21. #include <errno.h>
  22. #include <byteswap.h>
  23. #include <ipxe/in.h>
  24. #include <ipxe/iobuf.h>
  25. #include <ipxe/tcpip.h>
  26. #include <ipxe/ping.h>
  27. #include <ipxe/icmpv6.h>
  28. /** @file
  29. *
  30. * ICMPv6 protocol
  31. *
  32. */
  33. struct icmp_echo_protocol icmpv6_echo_protocol __icmp_echo_protocol;
  34. /**
  35. * Process received ICMPv6 echo request packet
  36. *
  37. * @v iobuf I/O buffer
  38. * @v netdev Network device
  39. * @v sin6_src Source socket address
  40. * @v sin6_dest Destination socket address
  41. * @ret rc Return status code
  42. */
  43. static int icmpv6_rx_echo_request ( struct io_buffer *iobuf,
  44. struct net_device *netdev __unused,
  45. struct sockaddr_in6 *sin6_src,
  46. struct sockaddr_in6 *sin6_dest __unused ) {
  47. struct sockaddr_tcpip *st_src =
  48. ( ( struct sockaddr_tcpip * ) sin6_src );
  49. return icmp_rx_echo_request ( iobuf, st_src, &icmpv6_echo_protocol );
  50. }
  51. /** ICMPv6 echo request handler */
  52. struct icmpv6_handler icmpv6_echo_request_handler __icmpv6_handler = {
  53. .type = ICMPV6_ECHO_REQUEST,
  54. .rx = icmpv6_rx_echo_request,
  55. };
  56. /**
  57. * Process received ICMPv6 echo reply packet
  58. *
  59. * @v iobuf I/O buffer
  60. * @v netdev Network device
  61. * @v sin6_src Source socket address
  62. * @v sin6_dest Destination socket address
  63. * @ret rc Return status code
  64. */
  65. static int icmpv6_rx_echo_reply ( struct io_buffer *iobuf,
  66. struct net_device *netdev __unused,
  67. struct sockaddr_in6 *sin6_src,
  68. struct sockaddr_in6 *sin6_dest __unused ) {
  69. struct sockaddr_tcpip *st_src =
  70. ( ( struct sockaddr_tcpip * ) sin6_src );
  71. return icmp_rx_echo_reply ( iobuf, st_src );
  72. }
  73. /** ICMPv6 echo reply handler */
  74. struct icmpv6_handler icmpv6_echo_reply_handler __icmpv6_handler = {
  75. .type = ICMPV6_ECHO_REPLY,
  76. .rx = icmpv6_rx_echo_reply,
  77. };
  78. /**
  79. * Identify ICMPv6 handler
  80. *
  81. * @v type ICMPv6 type
  82. * @ret handler ICMPv6 handler, or NULL if not found
  83. */
  84. static struct icmpv6_handler * icmpv6_handler ( unsigned int type ) {
  85. struct icmpv6_handler *handler;
  86. for_each_table_entry ( handler, ICMPV6_HANDLERS ) {
  87. if ( handler->type == type )
  88. return handler;
  89. }
  90. return NULL;
  91. }
  92. /**
  93. * Process a received packet
  94. *
  95. * @v iobuf I/O buffer
  96. * @v netdev Network device
  97. * @v st_src Partially-filled source address
  98. * @v st_dest Partially-filled destination address
  99. * @v pshdr_csum Pseudo-header checksum
  100. * @ret rc Return status code
  101. */
  102. static int icmpv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
  103. struct sockaddr_tcpip *st_src,
  104. struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
  105. struct sockaddr_in6 *sin6_src = ( ( struct sockaddr_in6 * ) st_src );
  106. struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest );
  107. struct icmp_header *icmp = iobuf->data;
  108. size_t len = iob_len ( iobuf );
  109. struct icmpv6_handler *handler;
  110. unsigned int csum;
  111. int rc;
  112. /* Sanity check */
  113. if ( len < sizeof ( *icmp ) ) {
  114. DBGC ( netdev, "ICMPv6 packet too short at %zd bytes (min %zd "
  115. "bytes)\n", len, sizeof ( *icmp ) );
  116. rc = -EINVAL;
  117. goto done;
  118. }
  119. /* Verify checksum */
  120. csum = tcpip_continue_chksum ( pshdr_csum, icmp, len );
  121. if ( csum != 0 ) {
  122. DBGC ( netdev, "ICMPv6 checksum incorrect (is %04x, should be "
  123. "0000)\n", csum );
  124. DBGC_HDA ( netdev, 0, icmp, len );
  125. rc = -EINVAL;
  126. goto done;
  127. }
  128. /* Identify handler */
  129. handler = icmpv6_handler ( icmp->type );
  130. if ( ! handler ) {
  131. DBGC ( netdev, "ICMPv6 unrecognised type %d\n", icmp->type );
  132. rc = -ENOTSUP;
  133. goto done;
  134. }
  135. /* Pass to handler */
  136. if ( ( rc = handler->rx ( iob_disown ( iobuf ), netdev, sin6_src,
  137. sin6_dest ) ) != 0 ) {
  138. DBGC ( netdev, "ICMPv6 could not handle type %d: %s\n",
  139. icmp->type, strerror ( rc ) );
  140. goto done;
  141. }
  142. done:
  143. free_iob ( iobuf );
  144. return rc;
  145. }
  146. /** ICMPv6 TCP/IP protocol */
  147. struct tcpip_protocol icmpv6_protocol __tcpip_protocol = {
  148. .name = "ICMPv6",
  149. .rx = icmpv6_rx,
  150. .tcpip_proto = IP_ICMP6,
  151. };
  152. /** ICMPv6 echo protocol */
  153. struct icmp_echo_protocol icmpv6_echo_protocol __icmp_echo_protocol = {
  154. .family = AF_INET6,
  155. .request = ICMPV6_ECHO_REQUEST,
  156. .reply = ICMPV6_ECHO_REPLY,
  157. .tcpip_protocol = &icmpv6_protocol,
  158. .net_checksum = 1,
  159. };