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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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 <byteswap.h>
  22. #include <errno.h>
  23. #include <ipxe/iobuf.h>
  24. #include <ipxe/in.h>
  25. #include <ipxe/tcpip.h>
  26. #include <ipxe/ping.h>
  27. #include <ipxe/crc32.h>
  28. #include <ipxe/icmp.h>
  29. /** @file
  30. *
  31. * ICMP protocol
  32. *
  33. */
  34. /**
  35. * Identify ICMP echo protocol
  36. *
  37. * @v st_family Address family
  38. * @ret echo_protocol ICMP echo protocol, or NULL
  39. */
  40. static struct icmp_echo_protocol * icmp_echo_protocol ( sa_family_t family ) {
  41. struct icmp_echo_protocol *echo_protocol;
  42. for_each_table_entry ( echo_protocol, ICMP_ECHO_PROTOCOLS ) {
  43. if ( echo_protocol->family == family )
  44. return echo_protocol;
  45. }
  46. return NULL;
  47. }
  48. /**
  49. *
  50. * Determine debugging colour for ICMP debug messages
  51. *
  52. * @v st_peer Peer address
  53. * @ret col Debugging colour (for DBGC())
  54. */
  55. static uint32_t icmpcol ( struct sockaddr_tcpip *st_peer ) {
  56. return crc32_le ( 0, st_peer, sizeof ( *st_peer ) );
  57. }
  58. /**
  59. * Transmit ICMP echo packet
  60. *
  61. * @v iobuf I/O buffer
  62. * @v st_dest Destination socket address
  63. * @v echo_protocol ICMP echo protocol
  64. * @ret rc Return status code
  65. */
  66. static int icmp_tx_echo ( struct io_buffer *iobuf,
  67. struct sockaddr_tcpip *st_dest,
  68. struct icmp_echo_protocol *echo_protocol ) {
  69. struct icmp_echo *echo = iobuf->data;
  70. int rc;
  71. /* Set ICMP type and (re)calculate checksum */
  72. echo->icmp.chksum = 0;
  73. echo->icmp.chksum = tcpip_chksum ( echo, iob_len ( iobuf ) );
  74. /* Transmit packet */
  75. if ( ( rc = tcpip_tx ( iobuf, echo_protocol->tcpip_protocol, NULL,
  76. st_dest, NULL,
  77. ( echo_protocol->net_checksum ?
  78. &echo->icmp.chksum : NULL ) ) ) != 0 )
  79. return rc;
  80. return 0;
  81. }
  82. /**
  83. * Transmit ICMP echo request
  84. *
  85. * @v iobuf I/O buffer
  86. * @v st_dest Destination socket address
  87. * @ret rc Return status code
  88. */
  89. int icmp_tx_echo_request ( struct io_buffer *iobuf,
  90. struct sockaddr_tcpip *st_dest ) {
  91. struct icmp_echo *echo = iobuf->data;
  92. struct icmp_echo_protocol *echo_protocol;
  93. int rc;
  94. /* Identify ICMP echo protocol */
  95. echo_protocol = icmp_echo_protocol ( st_dest->st_family );
  96. if ( ! echo_protocol ) {
  97. DBGC ( icmpcol ( st_dest ), "ICMP TX echo request unknown "
  98. "address family %d\n", st_dest->st_family );
  99. free_iob ( iobuf );
  100. return -ENOTSUP;
  101. }
  102. /* Set type */
  103. echo->icmp.type = echo_protocol->request;
  104. /* Transmit request */
  105. DBGC ( icmpcol ( st_dest ), "ICMP TX echo request id %04x seq %04x\n",
  106. ntohs ( echo->ident ), ntohs ( echo->sequence ) );
  107. if ( ( rc = icmp_tx_echo ( iobuf, st_dest, echo_protocol ) ) != 0 )
  108. return rc;
  109. return 0;
  110. }
  111. /**
  112. * Transmit ICMP echo reply
  113. *
  114. * @v iobuf I/O buffer
  115. * @v st_dest Destination socket address
  116. * @ret rc Return status code
  117. */
  118. static int icmp_tx_echo_reply ( struct io_buffer *iobuf,
  119. struct sockaddr_tcpip *st_dest,
  120. struct icmp_echo_protocol *echo_protocol ) {
  121. struct icmp_echo *echo = iobuf->data;
  122. int rc;
  123. /* Set type */
  124. echo->icmp.type = echo_protocol->reply;
  125. /* Transmit reply */
  126. DBGC ( icmpcol ( st_dest ), "ICMP TX echo reply id %04x seq %04x\n",
  127. ntohs ( echo->ident ), ntohs ( echo->sequence ) );
  128. if ( ( rc = icmp_tx_echo ( iobuf, st_dest, echo_protocol ) ) != 0 )
  129. return rc;
  130. return 0;
  131. }
  132. /**
  133. * Process a received ICMP echo request
  134. *
  135. * @v iobuf I/O buffer
  136. * @v st_src Source socket address
  137. * @v echo_protocol ICMP echo protocol
  138. * @ret rc Return status code
  139. */
  140. int icmp_rx_echo_request ( struct io_buffer *iobuf,
  141. struct sockaddr_tcpip *st_src,
  142. struct icmp_echo_protocol *echo_protocol ) {
  143. struct icmp_echo *echo = iobuf->data;
  144. int rc;
  145. /* Sanity check */
  146. if ( iob_len ( iobuf ) < sizeof ( *echo ) ) {
  147. DBGC ( icmpcol ( st_src ), "ICMP RX echo request too short at "
  148. "%zd bytes (min %zd bytes)\n",
  149. iob_len ( iobuf ), sizeof ( *echo ) );
  150. free_iob ( iobuf );
  151. return -EINVAL;
  152. }
  153. DBGC ( icmpcol ( st_src ), "ICMP RX echo request id %04x seq %04x\n",
  154. ntohs ( echo->ident ), ntohs ( echo->sequence ) );
  155. /* Transmit echo reply */
  156. if ( ( rc = icmp_tx_echo_reply ( iobuf, st_src, echo_protocol ) ) != 0 )
  157. return rc;
  158. return 0;
  159. }
  160. /**
  161. * Process a received ICMP echo request
  162. *
  163. * @v iobuf I/O buffer
  164. * @v st_src Source socket address
  165. * @ret rc Return status code
  166. */
  167. int icmp_rx_echo_reply ( struct io_buffer *iobuf,
  168. struct sockaddr_tcpip *st_src ) {
  169. struct icmp_echo *echo = iobuf->data;
  170. int rc;
  171. /* Sanity check */
  172. if ( iob_len ( iobuf ) < sizeof ( *echo ) ) {
  173. DBGC ( icmpcol ( st_src ), "ICMP RX echo reply too short at "
  174. "%zd bytes (min %zd bytes)\n",
  175. iob_len ( iobuf ), sizeof ( *echo ) );
  176. free_iob ( iobuf );
  177. return -EINVAL;
  178. }
  179. DBGC ( icmpcol ( st_src ), "ICMP RX echo reply id %04x seq %04x\n",
  180. ntohs ( echo->ident ), ntohs ( echo->sequence ) );
  181. /* Deliver to ping protocol */
  182. if ( ( rc = ping_rx ( iobuf, st_src ) ) != 0 )
  183. return rc;
  184. return 0;
  185. }
  186. /**
  187. * Receive ping reply (when no ping protocol is present)
  188. *
  189. * @v iobuf I/O buffer
  190. * @v st_src Source socket address
  191. * @ret rc Return status code
  192. */
  193. __weak int ping_rx ( struct io_buffer *iobuf,
  194. struct sockaddr_tcpip *st_src __unused ) {
  195. free_iob ( iobuf );
  196. return 0;
  197. }