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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /*
  2. * Copyright (C) 2010 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 <stdint.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <stdio.h>
  28. #include <errno.h>
  29. #include <byteswap.h>
  30. #include <ipxe/iobuf.h>
  31. #include <ipxe/netdevice.h>
  32. #include <ipxe/if_ether.h>
  33. #include <ipxe/keys.h>
  34. #include <ipxe/console.h>
  35. #include <usr/ifmgmt.h>
  36. #include <usr/lotest.h>
  37. /** @file
  38. *
  39. * Loopback testing
  40. *
  41. */
  42. /** Current loopback test receiver */
  43. static struct net_device *lotest_receiver;
  44. /** Loopback testing received packets */
  45. static LIST_HEAD ( lotest_queue );
  46. /**
  47. * Process received packet
  48. *
  49. * @v iobuf I/O buffer
  50. * @v netdev Network device
  51. * @v ll_dest Link-layer destination address
  52. * @v ll_source Link-layer source address
  53. * @v flags Packet flags
  54. * @ret rc Return status code
  55. */
  56. static int lotest_rx ( struct io_buffer *iobuf,
  57. struct net_device *netdev,
  58. const void *ll_dest __unused,
  59. const void *ll_source __unused,
  60. unsigned int flags __unused ) {
  61. /* Add to received packet queue if currently performing a test */
  62. if ( netdev == lotest_receiver ) {
  63. list_add_tail ( &iobuf->list, &lotest_queue );
  64. } else {
  65. free_iob ( iobuf );
  66. }
  67. return 0;
  68. }
  69. /**
  70. * Dequeue received packet
  71. *
  72. * @ret iobuf I/O buffer, or NULL
  73. */
  74. static struct io_buffer * lotest_dequeue ( void ) {
  75. struct io_buffer *iobuf;
  76. /* Remove first packet (if any) from received packet queue */
  77. iobuf = list_first_entry ( &lotest_queue, struct io_buffer, list );
  78. if ( ! iobuf )
  79. return NULL;
  80. list_del ( &iobuf->list );
  81. return iobuf;
  82. }
  83. /**
  84. * Transcribe network-layer address
  85. *
  86. * @v net_addr Network-layer address
  87. * @ret string Human-readable transcription of address
  88. */
  89. static const char * lotest_ntoa ( const void *net_addr __unused ) {
  90. return "<INVALID>";
  91. }
  92. /**
  93. * Loopback test network-layer protocol
  94. *
  95. * Using a dedicated network-layer protocol avoids problems caused by
  96. * cards supporting features such as IPv4 checksum offload trying to
  97. * interpret the (randomly generated) network-layer content.
  98. */
  99. static struct net_protocol lotest_protocol __net_protocol = {
  100. .name = "LOTEST",
  101. .rx = lotest_rx,
  102. .ntoa = lotest_ntoa,
  103. .net_proto = htons ( 0x6950 ), /* Not a genuine protocol number */
  104. .net_addr_len = 0,
  105. };
  106. /**
  107. * Discard all received loopback test packets
  108. *
  109. */
  110. static void lotest_flush ( void ) {
  111. struct io_buffer *iobuf;
  112. while ( ( iobuf = lotest_dequeue() ) != NULL )
  113. free_iob ( iobuf );
  114. }
  115. /**
  116. * Wait for packet to be received
  117. *
  118. * @v data Expected data
  119. * @v len Expected data length
  120. * @ret rc Return status code
  121. */
  122. static int loopback_wait ( void *data, size_t len ) {
  123. struct io_buffer *iobuf;
  124. /* Poll until packet arrives */
  125. while ( 1 ) {
  126. /* Check for cancellation */
  127. if ( iskey() && ( getchar() == CTRL_C ) )
  128. return -ECANCELED;
  129. /* Poll network devices */
  130. net_poll();
  131. /* Dequeue packet, if available */
  132. iobuf = lotest_dequeue();
  133. if ( ! iobuf )
  134. continue;
  135. /* Check packet length */
  136. if ( iob_len ( iobuf ) != len ) {
  137. printf ( "\nLength mismatch: sent %zd, received %zd",
  138. len, iob_len ( iobuf ) );
  139. DBG ( "\nSent:\n" );
  140. DBG_HDA ( 0, data, len );
  141. DBG ( "Received:\n" );
  142. DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
  143. free_iob ( iob_disown ( iobuf ) );
  144. return -EINVAL;
  145. }
  146. /* Check packet content */
  147. if ( memcmp ( iobuf->data, data, len ) != 0 ) {
  148. printf ( "\nContent mismatch" );
  149. DBG ( "\nSent:\n" );
  150. DBG_HDA ( 0, data, len );
  151. DBG ( "Received:\n" );
  152. DBG_HDA ( 0, iobuf->data, iob_len ( iobuf ) );
  153. free_iob ( iob_disown ( iobuf ) );
  154. return -EINVAL;
  155. }
  156. /* Discard packet and return */
  157. free_iob ( iob_disown ( iobuf ) );
  158. return 0;
  159. }
  160. }
  161. /**
  162. * Perform loopback test between two network devices
  163. *
  164. * @v sender Sending network device
  165. * @v receiver Received network device
  166. * @v mtu Packet size (excluding link-layer headers)
  167. * @v broadcast Use broadcast link-layer address
  168. * @ret rc Return status code
  169. */
  170. int loopback_test ( struct net_device *sender, struct net_device *receiver,
  171. size_t mtu, int broadcast ) {
  172. uint8_t *buf;
  173. uint32_t *seq;
  174. struct io_buffer *iobuf;
  175. const void *ll_dest;
  176. unsigned int i;
  177. unsigned int successes;
  178. int rc;
  179. /* Open network devices */
  180. if ( ( rc = ifopen ( sender ) ) != 0 )
  181. return rc;
  182. if ( ( rc = ifopen ( receiver ) ) != 0 )
  183. return rc;
  184. /* Wait for link-up */
  185. if ( ( rc = iflinkwait ( sender, 0 ) ) != 0 )
  186. return rc;
  187. if ( ( rc = iflinkwait ( receiver, 0 ) ) != 0 )
  188. return rc;
  189. /* Allocate data buffer */
  190. if ( mtu < sizeof ( *seq ) )
  191. mtu = sizeof ( *seq );
  192. buf = malloc ( mtu );
  193. if ( ! buf )
  194. return -ENOMEM;
  195. seq = ( ( void * ) buf );
  196. /* Determine destination address */
  197. ll_dest = ( broadcast ? sender->ll_broadcast : receiver->ll_addr );
  198. /* Print initial statistics */
  199. printf ( "Performing %sloopback test from %s to %s with %zd byte MTU\n",
  200. ( broadcast ? "broadcast " : "" ), sender->name,
  201. receiver->name, mtu );
  202. ifstat ( sender );
  203. ifstat ( receiver );
  204. /* Start loopback test */
  205. lotest_flush();
  206. lotest_receiver = receiver;
  207. /* Perform loopback test */
  208. for ( successes = 0 ; ; successes++ ) {
  209. /* Print running total */
  210. printf ( "\r%d", successes );
  211. /* Generate random packet */
  212. *seq = htonl ( successes );
  213. for ( i = sizeof ( *seq ) ; i < mtu ; i++ )
  214. buf[i] = random();
  215. iobuf = alloc_iob ( MAX_LL_HEADER_LEN + mtu );
  216. if ( ! iobuf ) {
  217. printf ( "\nFailed to allocate I/O buffer" );
  218. rc = -ENOMEM;
  219. break;
  220. }
  221. iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
  222. memcpy ( iob_put ( iobuf, mtu ), buf, mtu );
  223. /* Transmit packet */
  224. if ( ( rc = net_tx ( iob_disown ( iobuf ), sender,
  225. &lotest_protocol, ll_dest,
  226. sender->ll_addr ) ) != 0 ) {
  227. printf ( "\nFailed to transmit packet: %s",
  228. strerror ( rc ) );
  229. break;
  230. }
  231. /* Wait for received packet */
  232. if ( ( rc = loopback_wait ( buf, mtu ) ) != 0 )
  233. break;
  234. }
  235. printf ( "\n");
  236. /* Stop loopback testing */
  237. lotest_receiver = NULL;
  238. lotest_flush();
  239. /* Dump final statistics */
  240. ifstat ( sender );
  241. ifstat ( receiver );
  242. /* Free buffer */
  243. free ( buf );
  244. return 0;
  245. }