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.

prototester.c 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  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 <netinet/in.h>
  12. #include <arpa/inet.h>
  13. #include <getopt.h>
  14. #include <assert.h>
  15. typedef int irq_action_t;
  16. struct nic {
  17. struct nic_operations *nic_op;
  18. unsigned char *node_addr;
  19. unsigned char *packet;
  20. unsigned int packetlen;
  21. void *priv_data; /* driver private data */
  22. };
  23. struct nic_operations {
  24. int ( *connect ) ( struct nic * );
  25. int ( *poll ) ( struct nic *, int retrieve );
  26. void ( *transmit ) ( struct nic *, const char *,
  27. unsigned int, unsigned int, const char * );
  28. void ( *irq ) ( struct nic *, irq_action_t );
  29. };
  30. /*****************************************************************************
  31. *
  32. * Net device layer
  33. *
  34. */
  35. #include "../proto/uip/uip_arp.h"
  36. static unsigned char node_addr[ETH_ALEN];
  37. static unsigned char packet[ETH_FRAME_LEN];
  38. struct nic static_nic = {
  39. .node_addr = node_addr,
  40. .packet = packet,
  41. };
  42. /* Must be a macro because priv_data[] is of variable size */
  43. #define alloc_netdevice( priv_size ) ( { \
  44. static char priv_data[priv_size]; \
  45. static_nic.priv_data = priv_data; \
  46. &static_nic; } )
  47. static int register_netdevice ( struct nic *nic ) {
  48. struct uip_eth_addr hwaddr;
  49. memcpy ( &hwaddr, nic->node_addr, sizeof ( hwaddr ) );
  50. uip_setethaddr ( hwaddr );
  51. return 0;
  52. }
  53. static inline void unregister_netdevice ( struct nic *nic ) {
  54. /* Do nothing */
  55. }
  56. static inline void free_netdevice ( struct nic *nic ) {
  57. /* Do nothing */
  58. }
  59. static int netdev_poll ( int retrieve, void **data, size_t *len ) {
  60. int rc = static_nic.nic_op->poll ( &static_nic, retrieve );
  61. *data = static_nic.packet;
  62. *len = static_nic.packetlen;
  63. return rc;
  64. }
  65. static void netdev_transmit ( const void *data, size_t len ) {
  66. uint16_t type = ntohs ( *( ( uint16_t * ) ( data + 12 ) ) );
  67. static_nic.nic_op->transmit ( &static_nic, data, type,
  68. len - ETH_HLEN,
  69. data + ETH_HLEN );
  70. }
  71. /*****************************************************************************
  72. *
  73. * Hijack device interface
  74. *
  75. * This requires a hijack daemon to be running
  76. *
  77. */
  78. struct hijack {
  79. int fd;
  80. };
  81. struct hijack_device {
  82. char *name;
  83. void *priv;
  84. };
  85. static inline void hijack_set_drvdata ( struct hijack_device *hijack_dev,
  86. void *data ) {
  87. hijack_dev->priv = data;
  88. }
  89. static inline void * hijack_get_drvdata ( struct hijack_device *hijack_dev ) {
  90. return hijack_dev->priv;
  91. }
  92. static int hijack_poll ( struct nic *nic, int retrieve ) {
  93. struct hijack *hijack = nic->priv_data;
  94. fd_set fdset;
  95. struct timeval tv;
  96. int ready;
  97. ssize_t len;
  98. /* Poll for data */
  99. FD_ZERO ( &fdset );
  100. FD_SET ( hijack->fd, &fdset );
  101. tv.tv_sec = 0;
  102. tv.tv_usec = 500; /* 500us to avoid hogging CPU */
  103. ready = select ( ( hijack->fd + 1 ), &fdset, NULL, NULL, &tv );
  104. if ( ready < 0 ) {
  105. fprintf ( stderr, "select() failed: %s\n",
  106. strerror ( errno ) );
  107. return 0;
  108. }
  109. if ( ready == 0 )
  110. return 0;
  111. /* Return if we're not retrieving data yet */
  112. if ( ! retrieve )
  113. return 1;
  114. /* Fetch data */
  115. len = read ( hijack->fd, nic->packet, ETH_FRAME_LEN );
  116. if ( len < 0 ) {
  117. fprintf ( stderr, "read() failed: %s\n",
  118. strerror ( errno ) );
  119. return 0;
  120. }
  121. nic->packetlen = len;
  122. return 1;
  123. }
  124. static void hijack_transmit ( struct nic *nic, const char *dest,
  125. unsigned int type, unsigned int size,
  126. const char *packet ) {
  127. struct hijack *hijack = nic->priv_data;
  128. unsigned int nstype = htons ( type );
  129. unsigned int total_size = ETH_HLEN + size;
  130. char txbuf[ total_size ];
  131. /* Build packet header */
  132. memcpy ( txbuf, dest, ETH_ALEN );
  133. memcpy ( txbuf + ETH_ALEN, nic->node_addr, ETH_ALEN );
  134. memcpy ( txbuf + 2 * ETH_ALEN, &nstype, 2 );
  135. memcpy ( txbuf + ETH_HLEN, packet, size );
  136. /* Transmit data */
  137. if ( write ( hijack->fd, txbuf, total_size ) != total_size ) {
  138. fprintf ( stderr, "write() failed: %s\n",
  139. strerror ( errno ) );
  140. }
  141. }
  142. static int hijack_connect ( struct nic *nic ) {
  143. return 1;
  144. }
  145. static void hijack_irq ( struct nic *nic, irq_action_t action ) {
  146. /* Do nothing */
  147. }
  148. static struct nic_operations hijack_operations = {
  149. .connect = hijack_connect,
  150. .transmit = hijack_transmit,
  151. .poll = hijack_poll,
  152. .irq = hijack_irq,
  153. };
  154. int hijack_probe ( struct hijack_device *hijack_dev ) {
  155. struct nic *nic;
  156. struct hijack *hijack;
  157. struct sockaddr_un sun;
  158. int i;
  159. nic = alloc_netdevice ( sizeof ( *hijack ) );
  160. if ( ! nic ) {
  161. fprintf ( stderr, "alloc_netdevice() failed\n" );
  162. goto err_alloc;
  163. }
  164. hijack = nic->priv_data;
  165. memset ( hijack, 0, sizeof ( *hijack ) );
  166. /* Create socket */
  167. hijack->fd = socket ( PF_UNIX, SOCK_SEQPACKET, 0 );
  168. if ( hijack->fd < 0 ) {
  169. fprintf ( stderr, "socket() failed: %s\n",
  170. strerror ( errno ) );
  171. goto err;
  172. }
  173. /* Connect to hijack daemon */
  174. sun.sun_family = AF_UNIX;
  175. snprintf ( sun.sun_path, sizeof ( sun.sun_path ), "/var/run/hijack-%s",
  176. hijack_dev->name );
  177. if ( connect ( hijack->fd, ( struct sockaddr * ) &sun,
  178. sizeof ( sun ) ) < 0 ) {
  179. fprintf ( stderr, "could not connect to %s: %s\n",
  180. sun.sun_path, strerror ( errno ) );
  181. goto err;
  182. }
  183. /* Generate MAC address */
  184. srand ( time ( NULL ) );
  185. for ( i = 0 ; i < ETH_ALEN ; i++ ) {
  186. nic->node_addr[i] = ( rand() & 0xff );
  187. }
  188. nic->node_addr[0] &= 0xfe; /* clear multicast bit */
  189. nic->node_addr[0] |= 0x02; /* set "locally-assigned" bit */
  190. nic->nic_op = &hijack_operations;
  191. if ( register_netdevice ( nic ) < 0 )
  192. goto err;
  193. hijack_set_drvdata ( hijack_dev, nic );
  194. return 1;
  195. err:
  196. if ( hijack->fd >= 0 )
  197. close ( hijack->fd );
  198. free_netdevice ( nic );
  199. err_alloc:
  200. return 0;
  201. }
  202. static void hijack_disable ( struct hijack_device *hijack_dev ) {
  203. struct nic *nic = hijack_get_drvdata ( hijack_dev );
  204. struct hijack *hijack = nic->priv_data;
  205. unregister_netdevice ( nic );
  206. close ( hijack->fd );
  207. }
  208. /*****************************************************************************
  209. *
  210. * uIP wrapper layer
  211. *
  212. */
  213. #include "../proto/uip/uip.h"
  214. #include "../proto/uip/uip_arp.h"
  215. struct tcp_connection;
  216. struct tcp_operations {
  217. void ( * aborted ) ( struct tcp_connection *conn );
  218. void ( * timedout ) ( struct tcp_connection *conn );
  219. void ( * closed ) ( struct tcp_connection *conn );
  220. void ( * connected ) ( struct tcp_connection *conn );
  221. void ( * acked ) ( struct tcp_connection *conn, size_t len );
  222. void ( * newdata ) ( struct tcp_connection *conn );
  223. void ( * senddata ) ( struct tcp_connection *conn );
  224. };
  225. struct tcp_connection {
  226. struct sockaddr_in sin;
  227. struct tcp_operations *tcp_op;
  228. };
  229. static int tcp_connect ( struct tcp_connection *conn ) {
  230. struct uip_conn *uip_conn;
  231. u16_t ipaddr[2];
  232. assert ( conn->sin.sin_addr.s_addr != 0 );
  233. assert ( conn->sin.sin_port != 0 );
  234. assert ( conn->tcp_op != NULL );
  235. assert ( sizeof ( uip_conn->appstate ) == sizeof ( conn ) );
  236. * ( ( uint32_t * ) ipaddr ) = conn->sin.sin_addr.s_addr;
  237. uip_conn = uip_connect ( ipaddr, conn->sin.sin_port );
  238. if ( ! uip_conn )
  239. return -1;
  240. *( ( void ** ) uip_conn->appstate ) = conn;
  241. return 0;
  242. }
  243. static void tcp_send ( struct tcp_connection *conn, const void *data,
  244. size_t len ) {
  245. assert ( conn = *( ( void ** ) uip_conn->appstate ) );
  246. uip_send ( ( void * ) data, len );
  247. }
  248. static void tcp_close ( struct tcp_connection *conn ) {
  249. assert ( conn = *( ( void ** ) uip_conn->appstate ) );
  250. uip_close();
  251. }
  252. void uip_tcp_appcall ( void ) {
  253. struct tcp_connection *conn = *( ( void ** ) uip_conn->appstate );
  254. struct tcp_operations *op = conn->tcp_op;
  255. assert ( conn->tcp_op->closed != NULL );
  256. assert ( conn->tcp_op->connected != NULL );
  257. assert ( conn->tcp_op->acked != NULL );
  258. assert ( conn->tcp_op->newdata != NULL );
  259. assert ( conn->tcp_op->senddata != NULL );
  260. if ( uip_aborted() && op->aborted ) /* optional method */
  261. op->aborted ( conn );
  262. if ( uip_timedout() && op->timedout ) /* optional method */
  263. op->timedout ( conn );
  264. if ( uip_closed() && op->closed ) /* optional method */
  265. op->closed ( conn );
  266. if ( uip_connected() )
  267. op->connected ( conn );
  268. if ( uip_acked() )
  269. op->acked ( conn, uip_conn->len );
  270. if ( uip_newdata() )
  271. op->newdata ( conn );
  272. if ( uip_rexmit() || uip_newdata() || uip_acked() ||
  273. uip_connected() || uip_poll() )
  274. op->senddata ( conn );
  275. }
  276. void uip_udp_appcall ( void ) {
  277. }
  278. static void init_tcpip ( void ) {
  279. uip_init();
  280. uip_arp_init();
  281. }
  282. #define UIP_HLEN ( 40 + UIP_LLH_LEN )
  283. static void uip_transmit ( void ) {
  284. uip_arp_out();
  285. if ( uip_len > UIP_HLEN ) {
  286. memcpy ( uip_buf + UIP_HLEN, ( void * ) uip_appdata,
  287. uip_len - UIP_HLEN );
  288. }
  289. netdev_transmit ( uip_buf, uip_len );
  290. uip_len = 0;
  291. }
  292. static void run_tcpip ( void ) {
  293. void *data;
  294. size_t len;
  295. uint16_t type;
  296. int i;
  297. if ( netdev_poll ( 1, &data, &len ) ) {
  298. /* We have data */
  299. memcpy ( uip_buf, data, len );
  300. uip_len = len;
  301. type = ntohs ( *( ( uint16_t * ) ( uip_buf + 12 ) ) );
  302. if ( type == ETHERTYPE_ARP ) {
  303. uip_arp_arpin();
  304. } else {
  305. uip_arp_ipin();
  306. uip_input();
  307. }
  308. if ( uip_len > 0 )
  309. uip_transmit();
  310. } else {
  311. for ( i = 0 ; i < UIP_CONNS ; i++ ) {
  312. uip_periodic ( i );
  313. if ( uip_len > 0 )
  314. uip_transmit();
  315. }
  316. }
  317. }
  318. /*****************************************************************************
  319. *
  320. * "Hello world" protocol tester
  321. *
  322. */
  323. #include <stddef.h>
  324. #define container_of(ptr, type, member) ({ \
  325. const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  326. (type *)( (char *)__mptr - offsetof(type,member) );})
  327. enum hello_state {
  328. HELLO_SENDING_MESSAGE = 0,
  329. HELLO_SENDING_ENDL,
  330. };
  331. struct hello_request {
  332. struct tcp_connection tcp;
  333. const char *message;
  334. enum hello_state state;
  335. int remaining;
  336. void ( *callback ) ( struct hello_request *hello );
  337. int complete;
  338. };
  339. static inline struct hello_request *
  340. tcp_to_hello ( struct tcp_connection *conn ) {
  341. return container_of ( conn, struct hello_request, tcp );
  342. }
  343. static void hello_aborted ( struct tcp_connection *conn ) {
  344. struct hello_request *hello = tcp_to_hello ( conn );
  345. printf ( "Connection aborted\n" );
  346. hello->complete = 1;
  347. }
  348. static void hello_timedout ( struct tcp_connection *conn ) {
  349. struct hello_request *hello = tcp_to_hello ( conn );
  350. printf ( "Connection timed out\n" );
  351. hello->complete = 1;
  352. }
  353. static void hello_closed ( struct tcp_connection *conn ) {
  354. struct hello_request *hello = tcp_to_hello ( conn );
  355. hello->complete = 1;
  356. }
  357. static void hello_connected ( struct tcp_connection *conn ) {
  358. struct hello_request *hello = tcp_to_hello ( conn );
  359. }
  360. static void hello_acked ( struct tcp_connection *conn, size_t len ) {
  361. struct hello_request *hello = tcp_to_hello ( conn );
  362. hello->message += len;
  363. hello->remaining -= len;
  364. if ( hello->remaining <= 0 ) {
  365. switch ( hello->state ) {
  366. case HELLO_SENDING_MESSAGE:
  367. hello->state = HELLO_SENDING_ENDL;
  368. hello->message = "\r\n";
  369. hello->remaining = 2;
  370. break;
  371. case HELLO_SENDING_ENDL:
  372. tcp_close ( conn );
  373. break;
  374. default:
  375. assert ( 0 );
  376. }
  377. }
  378. }
  379. static void hello_newdata ( struct tcp_connection *conn ) {
  380. struct hello_request *hello = tcp_to_hello ( conn );
  381. }
  382. static void hello_senddata ( struct tcp_connection *conn ) {
  383. struct hello_request *hello = tcp_to_hello ( conn );
  384. tcp_send ( conn, hello->message, hello->remaining );
  385. }
  386. static struct tcp_operations hello_tcp_operations = {
  387. .aborted = hello_aborted,
  388. .timedout = hello_timedout,
  389. .closed = hello_closed,
  390. .connected = hello_connected,
  391. .acked = hello_acked,
  392. .newdata = hello_newdata,
  393. .senddata = hello_senddata,
  394. };
  395. static int hello_connect ( struct hello_request *hello ) {
  396. hello->tcp.tcp_op = &hello_tcp_operations;
  397. hello->remaining = strlen ( hello->message );
  398. return tcp_connect ( &hello->tcp );
  399. }
  400. struct hello_options {
  401. struct sockaddr_in server;
  402. const char *message;
  403. };
  404. static void hello_usage ( char **argv ) {
  405. fprintf ( stderr,
  406. "Usage: %s [global options] hello [hello-specific options]\n"
  407. "\n"
  408. "hello-specific options:\n"
  409. " -h|--host Host IP address\n"
  410. " -p|--port Port number\n"
  411. " -m|--message Message to send\n",
  412. argv[0] );
  413. }
  414. static int hello_parse_options ( int argc, char **argv,
  415. struct hello_options *options ) {
  416. static struct option long_options[] = {
  417. { "host", 1, NULL, 'h' },
  418. { "port", 1, NULL, 'p' },
  419. { "message", 1, NULL, 'm' },
  420. { },
  421. };
  422. int c;
  423. char *endptr;
  424. /* Set default options */
  425. memset ( options, 0, sizeof ( *options ) );
  426. inet_aton ( "192.168.0.1", &options->server.sin_addr );
  427. options->server.sin_port = htons ( 80 );
  428. options->message = "Hello world!";
  429. /* Parse command-line options */
  430. while ( 1 ) {
  431. int option_index = 0;
  432. c = getopt_long ( argc, argv, "h:p:", long_options,
  433. &option_index );
  434. if ( c < 0 )
  435. break;
  436. switch ( c ) {
  437. case 'h':
  438. if ( inet_aton ( optarg,
  439. &options->server.sin_addr ) == 0 ) {
  440. fprintf ( stderr, "Invalid IP address %s\n",
  441. optarg );
  442. return -1;
  443. }
  444. break;
  445. case 'p':
  446. options->server.sin_port =
  447. htons ( strtoul ( optarg, &endptr, 0 ) );
  448. if ( *endptr != '\0' ) {
  449. fprintf ( stderr, "Invalid port %s\n",
  450. optarg );
  451. return -1;
  452. }
  453. break;
  454. case 'm':
  455. options->message = optarg;
  456. break;
  457. case '?':
  458. /* Unrecognised option */
  459. return -1;
  460. default:
  461. fprintf ( stderr, "Unrecognised option '-%c'\n", c );
  462. return -1;
  463. }
  464. }
  465. /* Check there are no remaining arguments */
  466. if ( optind != argc ) {
  467. hello_usage ( argv );
  468. return -1;
  469. }
  470. return optind;
  471. }
  472. static void test_hello_callback ( struct hello_request *hello ) {
  473. }
  474. static int test_hello ( int argc, char **argv ) {
  475. struct hello_options options;
  476. struct hello_request hello;
  477. /* Parse hello-specific options */
  478. if ( hello_parse_options ( argc, argv, &options ) < 0 )
  479. return -1;
  480. /* Construct hello request */
  481. memset ( &hello, 0, sizeof ( hello ) );
  482. hello.tcp.sin = options.server;
  483. hello.message = options.message;
  484. hello.callback = test_hello_callback;
  485. fprintf ( stderr, "Saying \"%s\" to %s:%d\n", hello.message,
  486. inet_ntoa ( hello.tcp.sin.sin_addr ),
  487. ntohs ( hello.tcp.sin.sin_port ) );
  488. /* Issue hello request and run to completion */
  489. hello_connect ( &hello );
  490. while ( ! hello.complete ) {
  491. run_tcpip ();
  492. }
  493. return 0;
  494. }
  495. /*****************************************************************************
  496. *
  497. * Protocol tester
  498. *
  499. */
  500. struct protocol_test {
  501. const char *name;
  502. int ( *exec ) ( int argc, char **argv );
  503. };
  504. static struct protocol_test tests[] = {
  505. { "hello", test_hello },
  506. };
  507. #define NUM_TESTS ( sizeof ( tests ) / sizeof ( tests[0] ) )
  508. static void list_tests ( void ) {
  509. int i;
  510. for ( i = 0 ; i < NUM_TESTS ; i++ ) {
  511. printf ( "%s\n", tests[i].name );
  512. }
  513. }
  514. static struct protocol_test * get_test_from_name ( const char *name ) {
  515. int i;
  516. for ( i = 0 ; i < NUM_TESTS ; i++ ) {
  517. if ( strcmp ( name, tests[i].name ) == 0 )
  518. return &tests[i];
  519. }
  520. return NULL;
  521. }
  522. /*****************************************************************************
  523. *
  524. * Parse command-line options
  525. *
  526. */
  527. struct tester_options {
  528. char interface[IF_NAMESIZE];
  529. };
  530. static void usage ( char **argv ) {
  531. fprintf ( stderr,
  532. "Usage: %s [global options] <test> [test-specific options]\n"
  533. "\n"
  534. "Global options:\n"
  535. " -h|--help Print this help message\n"
  536. " -i|--interface intf Use specified network interface\n"
  537. " -l|--list List available tests\n"
  538. "\n"
  539. "Use \"%s <test> -h\" to view test-specific options\n",
  540. argv[0], argv[0] );
  541. }
  542. static int parse_options ( int argc, char **argv,
  543. struct tester_options *options ) {
  544. static struct option long_options[] = {
  545. { "interface", 1, NULL, 'i' },
  546. { "list", 0, NULL, 'l' },
  547. { "help", 0, NULL, 'h' },
  548. { },
  549. };
  550. int c;
  551. /* Set default options */
  552. memset ( options, 0, sizeof ( *options ) );
  553. strncpy ( options->interface, "eth0", sizeof ( options->interface ) );
  554. /* Parse command-line options */
  555. while ( 1 ) {
  556. int option_index = 0;
  557. c = getopt_long ( argc, argv, "+i:hl", long_options,
  558. &option_index );
  559. if ( c < 0 )
  560. break;
  561. switch ( c ) {
  562. case 'i':
  563. strncpy ( options->interface, optarg,
  564. sizeof ( options->interface ) );
  565. break;
  566. case 'l':
  567. list_tests ();
  568. return -1;
  569. case 'h':
  570. usage ( argv );
  571. return -1;
  572. case '?':
  573. /* Unrecognised option */
  574. return -1;
  575. default:
  576. fprintf ( stderr, "Unrecognised option '-%c'\n", c );
  577. return -1;
  578. }
  579. }
  580. /* Check there is a test specified */
  581. if ( optind == argc ) {
  582. usage ( argv );
  583. return -1;
  584. }
  585. return optind;
  586. }
  587. /*****************************************************************************
  588. *
  589. * Main program
  590. *
  591. */
  592. int main ( int argc, char **argv ) {
  593. struct tester_options options;
  594. struct protocol_test *test;
  595. struct hijack_device hijack_dev;
  596. /* Parse command-line options */
  597. if ( parse_options ( argc, argv, &options ) < 0 )
  598. exit ( 1 );
  599. /* Identify test */
  600. test = get_test_from_name ( argv[optind] );
  601. if ( ! test ) {
  602. fprintf ( stderr, "Unrecognised test \"%s\"\n", argv[optind] );
  603. exit ( 1 );
  604. }
  605. optind++;
  606. /* Initialise the protocol stack */
  607. init_tcpip();
  608. /* Open the hijack device */
  609. hijack_dev.name = options.interface;
  610. if ( ! hijack_probe ( &hijack_dev ) )
  611. exit ( 1 );
  612. /* Run the test */
  613. if ( test->exec ( argc, argv ) < 0 )
  614. exit ( 1 );
  615. /* Close the hijack device */
  616. hijack_disable ( &hijack_dev );
  617. return 0;
  618. }