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

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