Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

prototester.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <time.h>
  7. #include <sys/socket.h>
  8. #include <sys/un.h>
  9. #include <net/if.h>
  10. #include <net/ethernet.h>
  11. #include <getopt.h>
  12. #include <assert.h>
  13. #include <gpxe/ip.h>
  14. #include <gpxe/tcp.h>
  15. #include <gpxe/hello.h>
  16. typedef int irq_action_t;
  17. struct nic {
  18. struct nic_operations *nic_op;
  19. unsigned char *node_addr;
  20. unsigned char *packet;
  21. unsigned int packetlen;
  22. void *priv_data; /* driver private data */
  23. };
  24. struct nic_operations {
  25. int ( *connect ) ( struct nic * );
  26. int ( *poll ) ( struct nic *, int retrieve );
  27. void ( *transmit ) ( struct nic *, const char *,
  28. unsigned int, unsigned int, const char * );
  29. void ( *irq ) ( struct nic *, irq_action_t );
  30. };
  31. /*****************************************************************************
  32. *
  33. * Net device layer
  34. *
  35. */
  36. #include "../proto/uip/uip_arp.h"
  37. static unsigned char node_addr[ETH_ALEN];
  38. static unsigned char packet[ETH_FRAME_LEN];
  39. struct nic static_nic = {
  40. .node_addr = node_addr,
  41. .packet = packet,
  42. };
  43. /* Must be a macro because priv_data[] is of variable size */
  44. #define alloc_netdevice( priv_size ) ( { \
  45. static char priv_data[priv_size]; \
  46. static_nic.priv_data = priv_data; \
  47. &static_nic; } )
  48. static int register_netdevice ( struct nic *nic ) {
  49. struct uip_eth_addr hwaddr;
  50. memcpy ( &hwaddr, nic->node_addr, sizeof ( hwaddr ) );
  51. uip_setethaddr ( hwaddr );
  52. return 0;
  53. }
  54. static inline void unregister_netdevice ( struct nic *nic ) {
  55. /* Do nothing */
  56. }
  57. static inline void free_netdevice ( struct nic *nic ) {
  58. /* Do nothing */
  59. }
  60. int netdev_poll ( int retrieve, void **data, size_t *len ) {
  61. int rc = static_nic.nic_op->poll ( &static_nic, retrieve );
  62. *data = static_nic.packet;
  63. *len = static_nic.packetlen;
  64. return rc;
  65. }
  66. void netdev_transmit ( const void *data, size_t len ) {
  67. uint16_t type = ntohs ( *( ( uint16_t * ) ( data + 12 ) ) );
  68. static_nic.nic_op->transmit ( &static_nic, data, type,
  69. len - ETH_HLEN,
  70. data + ETH_HLEN );
  71. }
  72. /*****************************************************************************
  73. *
  74. * Hijack device interface
  75. *
  76. * This requires a hijack daemon to be running
  77. *
  78. */
  79. struct hijack {
  80. int fd;
  81. };
  82. struct hijack_device {
  83. char *name;
  84. void *priv;
  85. };
  86. static inline void hijack_set_drvdata ( struct hijack_device *hijack_dev,
  87. void *data ) {
  88. hijack_dev->priv = data;
  89. }
  90. static inline void * hijack_get_drvdata ( struct hijack_device *hijack_dev ) {
  91. return hijack_dev->priv;
  92. }
  93. static int hijack_poll ( struct nic *nic, int retrieve ) {
  94. struct hijack *hijack = nic->priv_data;
  95. fd_set fdset;
  96. struct timeval tv;
  97. int ready;
  98. ssize_t len;
  99. /* Poll for data */
  100. FD_ZERO ( &fdset );
  101. FD_SET ( hijack->fd, &fdset );
  102. tv.tv_sec = 0;
  103. tv.tv_usec = 500; /* 500us to avoid hogging CPU */
  104. ready = select ( ( hijack->fd + 1 ), &fdset, NULL, NULL, &tv );
  105. if ( ready < 0 ) {
  106. fprintf ( stderr, "select() failed: %s\n",
  107. strerror ( errno ) );
  108. return 0;
  109. }
  110. if ( ready == 0 )
  111. return 0;
  112. /* Return if we're not retrieving data yet */
  113. if ( ! retrieve )
  114. return 1;
  115. /* Fetch data */
  116. len = read ( hijack->fd, nic->packet, ETH_FRAME_LEN );
  117. if ( len < 0 ) {
  118. fprintf ( stderr, "read() failed: %s\n",
  119. strerror ( errno ) );
  120. return 0;
  121. }
  122. nic->packetlen = len;
  123. return 1;
  124. }
  125. static void hijack_transmit ( struct nic *nic, const char *dest,
  126. unsigned int type, unsigned int size,
  127. const char *packet ) {
  128. struct hijack *hijack = nic->priv_data;
  129. unsigned int nstype = htons ( type );
  130. unsigned int total_size = ETH_HLEN + size;
  131. char txbuf[ total_size ];
  132. /* Build packet header */
  133. memcpy ( txbuf, dest, ETH_ALEN );
  134. memcpy ( txbuf + ETH_ALEN, nic->node_addr, ETH_ALEN );
  135. memcpy ( txbuf + 2 * ETH_ALEN, &nstype, 2 );
  136. memcpy ( txbuf + ETH_HLEN, packet, size );
  137. /* Transmit data */
  138. if ( write ( hijack->fd, txbuf, total_size ) != total_size ) {
  139. fprintf ( stderr, "write() failed: %s\n",
  140. strerror ( errno ) );
  141. }
  142. }
  143. static int hijack_connect ( struct nic *nic ) {
  144. return 1;
  145. }
  146. static void hijack_irq ( struct nic *nic, irq_action_t action ) {
  147. /* Do nothing */
  148. }
  149. static struct nic_operations hijack_operations = {
  150. .connect = hijack_connect,
  151. .transmit = hijack_transmit,
  152. .poll = hijack_poll,
  153. .irq = hijack_irq,
  154. };
  155. int hijack_probe ( struct hijack_device *hijack_dev ) {
  156. struct nic *nic;
  157. struct hijack *hijack;
  158. struct sockaddr_un sun;
  159. int i;
  160. nic = alloc_netdevice ( sizeof ( *hijack ) );
  161. if ( ! nic ) {
  162. fprintf ( stderr, "alloc_netdevice() failed\n" );
  163. goto err_alloc;
  164. }
  165. hijack = nic->priv_data;
  166. memset ( hijack, 0, sizeof ( *hijack ) );
  167. /* Create socket */
  168. hijack->fd = socket ( PF_UNIX, SOCK_SEQPACKET, 0 );
  169. if ( hijack->fd < 0 ) {
  170. fprintf ( stderr, "socket() failed: %s\n",
  171. strerror ( errno ) );
  172. goto err;
  173. }
  174. /* Connect to hijack daemon */
  175. sun.sun_family = AF_UNIX;
  176. snprintf ( sun.sun_path, sizeof ( sun.sun_path ), "/var/run/hijack-%s",
  177. hijack_dev->name );
  178. if ( connect ( hijack->fd, ( struct sockaddr * ) &sun,
  179. sizeof ( sun ) ) < 0 ) {
  180. fprintf ( stderr, "could not connect to %s: %s\n",
  181. sun.sun_path, strerror ( errno ) );
  182. goto err;
  183. }
  184. /* Generate MAC address */
  185. srand ( time ( NULL ) );
  186. for ( i = 0 ; i < ETH_ALEN ; i++ ) {
  187. nic->node_addr[i] = ( rand() & 0xff );
  188. }
  189. nic->node_addr[0] &= 0xfe; /* clear multicast bit */
  190. nic->node_addr[0] |= 0x02; /* set "locally-assigned" bit */
  191. nic->nic_op = &hijack_operations;
  192. if ( register_netdevice ( nic ) < 0 )
  193. goto err;
  194. hijack_set_drvdata ( hijack_dev, nic );
  195. return 1;
  196. err:
  197. if ( hijack->fd >= 0 )
  198. close ( hijack->fd );
  199. free_netdevice ( nic );
  200. err_alloc:
  201. return 0;
  202. }
  203. static void hijack_disable ( struct hijack_device *hijack_dev ) {
  204. struct nic *nic = hijack_get_drvdata ( hijack_dev );
  205. struct hijack *hijack = nic->priv_data;
  206. unregister_netdevice ( nic );
  207. close ( hijack->fd );
  208. }
  209. /*****************************************************************************
  210. *
  211. * "Hello world" protocol tester
  212. *
  213. */
  214. struct hello_options {
  215. struct sockaddr_in server;
  216. const char *message;
  217. };
  218. static void hello_usage ( char **argv ) {
  219. fprintf ( stderr,
  220. "Usage: %s [global options] hello [hello-specific options]\n"
  221. "\n"
  222. "hello-specific options:\n"
  223. " -h|--host Host IP address\n"
  224. " -p|--port Port number\n"
  225. " -m|--message Message to send\n",
  226. argv[0] );
  227. }
  228. static int hello_parse_options ( int argc, char **argv,
  229. struct hello_options *options ) {
  230. static struct option long_options[] = {
  231. { "host", 1, NULL, 'h' },
  232. { "port", 1, NULL, 'p' },
  233. { "message", 1, NULL, 'm' },
  234. { },
  235. };
  236. int c;
  237. char *endptr;
  238. /* Set default options */
  239. memset ( options, 0, sizeof ( *options ) );
  240. inet_aton ( "192.168.0.1", &options->server.sin_addr );
  241. options->server.sin_port = htons ( 80 );
  242. options->message = "Hello world!";
  243. /* Parse command-line options */
  244. while ( 1 ) {
  245. int option_index = 0;
  246. c = getopt_long ( argc, argv, "h:p:", long_options,
  247. &option_index );
  248. if ( c < 0 )
  249. break;
  250. switch ( c ) {
  251. case 'h':
  252. if ( inet_aton ( optarg,
  253. &options->server.sin_addr ) == 0 ) {
  254. fprintf ( stderr, "Invalid IP address %s\n",
  255. optarg );
  256. return -1;
  257. }
  258. break;
  259. case 'p':
  260. options->server.sin_port =
  261. htons ( strtoul ( optarg, &endptr, 0 ) );
  262. if ( *endptr != '\0' ) {
  263. fprintf ( stderr, "Invalid port %s\n",
  264. optarg );
  265. return -1;
  266. }
  267. break;
  268. case 'm':
  269. options->message = optarg;
  270. break;
  271. case '?':
  272. /* Unrecognised option */
  273. return -1;
  274. default:
  275. fprintf ( stderr, "Unrecognised option '-%c'\n", c );
  276. return -1;
  277. }
  278. }
  279. /* Check there are no remaining arguments */
  280. if ( optind != argc ) {
  281. hello_usage ( argv );
  282. return -1;
  283. }
  284. return optind;
  285. }
  286. static void test_hello_callback ( char *data, size_t len ) {
  287. int i;
  288. char c;
  289. for ( i = 0 ; i < len ; i++ ) {
  290. c = data[i];
  291. if ( c == '\r' ) {
  292. /* Print nothing */
  293. } else if ( ( c == '\n' ) || ( c >= 32 ) || ( c <= 126 ) ) {
  294. putchar ( c );
  295. } else {
  296. putchar ( '.' );
  297. }
  298. }
  299. }
  300. static int test_hello ( int argc, char **argv ) {
  301. struct hello_options options;
  302. struct hello_request hello;
  303. /* Parse hello-specific options */
  304. if ( hello_parse_options ( argc, argv, &options ) < 0 )
  305. return -1;
  306. /* Construct hello request */
  307. memset ( &hello, 0, sizeof ( hello ) );
  308. hello.tcp.sin = options.server;
  309. hello.message = options.message;
  310. hello.callback = test_hello_callback;
  311. fprintf ( stderr, "Saying \"%s\" to %s:%d\n", hello.message,
  312. inet_ntoa ( hello.tcp.sin.sin_addr ),
  313. ntohs ( hello.tcp.sin.sin_port ) );
  314. /* Issue hello request and run to completion */
  315. hello_connect ( &hello );
  316. while ( ! hello.complete ) {
  317. run_tcpip ();
  318. }
  319. return 0;
  320. }
  321. /*****************************************************************************
  322. *
  323. * Protocol tester
  324. *
  325. */
  326. struct protocol_test {
  327. const char *name;
  328. int ( *exec ) ( int argc, char **argv );
  329. };
  330. static struct protocol_test tests[] = {
  331. { "hello", test_hello },
  332. };
  333. #define NUM_TESTS ( sizeof ( tests ) / sizeof ( tests[0] ) )
  334. static void list_tests ( void ) {
  335. int i;
  336. for ( i = 0 ; i < NUM_TESTS ; i++ ) {
  337. printf ( "%s\n", tests[i].name );
  338. }
  339. }
  340. static struct protocol_test * get_test_from_name ( const char *name ) {
  341. int i;
  342. for ( i = 0 ; i < NUM_TESTS ; i++ ) {
  343. if ( strcmp ( name, tests[i].name ) == 0 )
  344. return &tests[i];
  345. }
  346. return NULL;
  347. }
  348. /*****************************************************************************
  349. *
  350. * Parse command-line options
  351. *
  352. */
  353. struct tester_options {
  354. char interface[IF_NAMESIZE];
  355. struct in_addr in_addr;
  356. };
  357. static void usage ( char **argv ) {
  358. fprintf ( stderr,
  359. "Usage: %s [global options] <test> [test-specific options]\n"
  360. "\n"
  361. "Global options:\n"
  362. " -h|--help Print this help message\n"
  363. " -i|--interface intf Use specified network interface\n"
  364. " -f|--from ip-address Use specified local IP address\n"
  365. " -l|--list List available tests\n"
  366. "\n"
  367. "Use \"%s <test> -h\" to view test-specific options\n",
  368. argv[0], argv[0] );
  369. }
  370. static int parse_options ( int argc, char **argv,
  371. struct tester_options *options ) {
  372. static struct option long_options[] = {
  373. { "interface", 1, NULL, 'i' },
  374. { "from", 1, NULL, 'f' },
  375. { "list", 0, NULL, 'l' },
  376. { "help", 0, NULL, 'h' },
  377. { },
  378. };
  379. int c;
  380. /* Set default options */
  381. memset ( options, 0, sizeof ( *options ) );
  382. strncpy ( options->interface, "eth0", sizeof ( options->interface ) );
  383. inet_aton ( "192.168.0.2", &options->in_addr );
  384. /* Parse command-line options */
  385. while ( 1 ) {
  386. int option_index = 0;
  387. c = getopt_long ( argc, argv, "+i:f:hl", long_options,
  388. &option_index );
  389. if ( c < 0 )
  390. break;
  391. switch ( c ) {
  392. case 'i':
  393. strncpy ( options->interface, optarg,
  394. sizeof ( options->interface ) );
  395. break;
  396. case 'f':
  397. if ( inet_aton ( optarg, &options->in_addr ) == 0 ) {
  398. fprintf ( stderr, "Invalid IP address %s\n",
  399. optarg );
  400. return -1;
  401. }
  402. break;
  403. case 'l':
  404. list_tests ();
  405. return -1;
  406. case 'h':
  407. usage ( argv );
  408. return -1;
  409. case '?':
  410. /* Unrecognised option */
  411. return -1;
  412. default:
  413. fprintf ( stderr, "Unrecognised option '-%c'\n", c );
  414. return -1;
  415. }
  416. }
  417. /* Check there is a test specified */
  418. if ( optind == argc ) {
  419. usage ( argv );
  420. return -1;
  421. }
  422. return optind;
  423. }
  424. /*****************************************************************************
  425. *
  426. * Main program
  427. *
  428. */
  429. int main ( int argc, char **argv ) {
  430. struct tester_options options;
  431. struct protocol_test *test;
  432. struct hijack_device hijack_dev;
  433. /* Parse command-line options */
  434. if ( parse_options ( argc, argv, &options ) < 0 )
  435. exit ( 1 );
  436. /* Identify test */
  437. test = get_test_from_name ( argv[optind] );
  438. if ( ! test ) {
  439. fprintf ( stderr, "Unrecognised test \"%s\"\n", argv[optind] );
  440. exit ( 1 );
  441. }
  442. optind++;
  443. /* Initialise the protocol stack */
  444. init_tcpip();
  445. set_ipaddr ( options.in_addr );
  446. /* Open the hijack device */
  447. hijack_dev.name = options.interface;
  448. if ( ! hijack_probe ( &hijack_dev ) )
  449. exit ( 1 );
  450. /* Run the test */
  451. if ( test->exec ( argc, argv ) < 0 )
  452. exit ( 1 );
  453. /* Close the hijack device */
  454. hijack_disable ( &hijack_dev );
  455. return 0;
  456. }