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 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <string.h>
  25. #include <errno.h>
  26. #include <byteswap.h>
  27. #include <ipxe/in.h>
  28. #include <ipxe/iobuf.h>
  29. #include <ipxe/tcpip.h>
  30. #include <ipxe/ping.h>
  31. #include <ipxe/icmpv6.h>
  32. /** @file
  33. *
  34. * ICMPv6 protocol
  35. *
  36. */
  37. struct icmp_echo_protocol icmpv6_echo_protocol __icmp_echo_protocol;
  38. /**
  39. * Process received ICMPv6 echo request packet
  40. *
  41. * @v iobuf I/O buffer
  42. * @v netdev Network device
  43. * @v sin6_src Source socket address
  44. * @v sin6_dest Destination socket address
  45. * @ret rc Return status code
  46. */
  47. static int icmpv6_rx_echo_request ( struct io_buffer *iobuf,
  48. struct net_device *netdev __unused,
  49. struct sockaddr_in6 *sin6_src,
  50. struct sockaddr_in6 *sin6_dest __unused ) {
  51. struct sockaddr_tcpip *st_src =
  52. ( ( struct sockaddr_tcpip * ) sin6_src );
  53. return icmp_rx_echo_request ( iobuf, st_src, &icmpv6_echo_protocol );
  54. }
  55. /** ICMPv6 echo request handler */
  56. struct icmpv6_handler icmpv6_echo_request_handler __icmpv6_handler = {
  57. .type = ICMPV6_ECHO_REQUEST,
  58. .rx = icmpv6_rx_echo_request,
  59. };
  60. /**
  61. * Process received ICMPv6 echo reply packet
  62. *
  63. * @v iobuf I/O buffer
  64. * @v netdev Network device
  65. * @v sin6_src Source socket address
  66. * @v sin6_dest Destination socket address
  67. * @ret rc Return status code
  68. */
  69. static int icmpv6_rx_echo_reply ( struct io_buffer *iobuf,
  70. struct net_device *netdev __unused,
  71. struct sockaddr_in6 *sin6_src,
  72. struct sockaddr_in6 *sin6_dest __unused ) {
  73. struct sockaddr_tcpip *st_src =
  74. ( ( struct sockaddr_tcpip * ) sin6_src );
  75. return icmp_rx_echo_reply ( iobuf, st_src );
  76. }
  77. /** ICMPv6 echo reply handler */
  78. struct icmpv6_handler icmpv6_echo_reply_handler __icmpv6_handler = {
  79. .type = ICMPV6_ECHO_REPLY,
  80. .rx = icmpv6_rx_echo_reply,
  81. };
  82. /**
  83. * Identify ICMPv6 handler
  84. *
  85. * @v type ICMPv6 type
  86. * @ret handler ICMPv6 handler, or NULL if not found
  87. */
  88. static struct icmpv6_handler * icmpv6_handler ( unsigned int type ) {
  89. struct icmpv6_handler *handler;
  90. for_each_table_entry ( handler, ICMPV6_HANDLERS ) {
  91. if ( handler->type == type )
  92. return handler;
  93. }
  94. return NULL;
  95. }
  96. /**
  97. * Process a received packet
  98. *
  99. * @v iobuf I/O buffer
  100. * @v netdev Network device
  101. * @v st_src Partially-filled source address
  102. * @v st_dest Partially-filled destination address
  103. * @v pshdr_csum Pseudo-header checksum
  104. * @ret rc Return status code
  105. */
  106. static int icmpv6_rx ( struct io_buffer *iobuf, struct net_device *netdev,
  107. struct sockaddr_tcpip *st_src,
  108. struct sockaddr_tcpip *st_dest, uint16_t pshdr_csum ) {
  109. struct sockaddr_in6 *sin6_src = ( ( struct sockaddr_in6 * ) st_src );
  110. struct sockaddr_in6 *sin6_dest = ( ( struct sockaddr_in6 * ) st_dest );
  111. struct icmp_header *icmp = iobuf->data;
  112. size_t len = iob_len ( iobuf );
  113. struct icmpv6_handler *handler;
  114. unsigned int csum;
  115. int rc;
  116. /* Sanity check */
  117. if ( len < sizeof ( *icmp ) ) {
  118. DBGC ( netdev, "ICMPv6 packet too short at %zd bytes (min %zd "
  119. "bytes)\n", len, sizeof ( *icmp ) );
  120. rc = -EINVAL;
  121. goto done;
  122. }
  123. /* Verify checksum */
  124. csum = tcpip_continue_chksum ( pshdr_csum, icmp, len );
  125. if ( csum != 0 ) {
  126. DBGC ( netdev, "ICMPv6 checksum incorrect (is %04x, should be "
  127. "0000)\n", csum );
  128. DBGC_HDA ( netdev, 0, icmp, len );
  129. rc = -EINVAL;
  130. goto done;
  131. }
  132. /* Identify handler */
  133. handler = icmpv6_handler ( icmp->type );
  134. if ( ! handler ) {
  135. DBGC ( netdev, "ICMPv6 unrecognised type %d\n", icmp->type );
  136. rc = -ENOTSUP;
  137. goto done;
  138. }
  139. /* Pass to handler */
  140. if ( ( rc = handler->rx ( iob_disown ( iobuf ), netdev, sin6_src,
  141. sin6_dest ) ) != 0 ) {
  142. DBGC ( netdev, "ICMPv6 could not handle type %d: %s\n",
  143. icmp->type, strerror ( rc ) );
  144. goto done;
  145. }
  146. done:
  147. free_iob ( iobuf );
  148. return rc;
  149. }
  150. /** ICMPv6 TCP/IP protocol */
  151. struct tcpip_protocol icmpv6_protocol __tcpip_protocol = {
  152. .name = "ICMPv6",
  153. .rx = icmpv6_rx,
  154. .tcpip_proto = IP_ICMP6,
  155. };
  156. /** ICMPv6 echo protocol */
  157. struct icmp_echo_protocol icmpv6_echo_protocol __icmp_echo_protocol = {
  158. .family = AF_INET6,
  159. .request = ICMPV6_ECHO_REQUEST,
  160. .reply = ICMPV6_ECHO_REPLY,
  161. .tcpip_protocol = &icmpv6_protocol,
  162. .net_checksum = 1,
  163. };