7 #include <sys/socket.h>
10 #include <net/ethernet.h>
16 #include <gpxe/hello.h>
18 typedef int irq_action_t;
21 struct nic_operations *nic_op;
22 unsigned char *node_addr;
23 unsigned char *packet;
24 unsigned int packetlen;
25 void *priv_data; /* driver private data */
28 struct nic_operations {
29 int ( *connect ) ( struct nic * );
30 int ( *poll ) ( struct nic *, int retrieve );
31 void ( *transmit ) ( struct nic *, const char *,
32 unsigned int, unsigned int, const char * );
33 void ( *irq ) ( struct nic *, irq_action_t );
36 /*****************************************************************************
42 #include "../proto/uip/uip_arp.h"
44 static unsigned char node_addr[ETH_ALEN];
45 static unsigned char packet[ETH_FRAME_LEN];
46 struct nic static_nic = {
47 .node_addr = node_addr,
51 /* Must be a macro because priv_data[] is of variable size */
52 #define alloc_netdevice( priv_size ) ( { \
53 static char priv_data[priv_size]; \
54 static_nic.priv_data = priv_data; \
57 static int register_netdevice ( struct nic *nic ) {
58 struct uip_eth_addr hwaddr;
60 memcpy ( &hwaddr, nic->node_addr, sizeof ( hwaddr ) );
61 uip_setethaddr ( hwaddr );
65 static inline void unregister_netdevice ( struct nic *nic ) {
69 static inline void free_netdevice ( struct nic *nic ) {
73 int netdev_poll ( int retrieve, void **data, size_t *len ) {
74 int rc = static_nic.nic_op->poll ( &static_nic, retrieve );
75 *data = static_nic.packet;
76 *len = static_nic.packetlen;
80 void netdev_transmit ( const void *data, size_t len ) {
81 uint16_t type = ntohs ( *( ( uint16_t * ) ( data + 12 ) ) );
82 static_nic.nic_op->transmit ( &static_nic, data, type,
87 /*****************************************************************************
89 * Hijack device interface
91 * This requires a hijack daemon to be running
99 struct hijack_device {
104 static inline void hijack_set_drvdata ( struct hijack_device *hijack_dev,
106 hijack_dev->priv = data;
109 static inline void * hijack_get_drvdata ( struct hijack_device *hijack_dev ) {
110 return hijack_dev->priv;
113 static int hijack_poll ( struct nic *nic, int retrieve ) {
114 struct hijack *hijack = nic->priv_data;
122 FD_SET ( hijack->fd, &fdset );
124 tv.tv_usec = 500; /* 500us to avoid hogging CPU */
125 ready = select ( ( hijack->fd + 1 ), &fdset, NULL, NULL, &tv );
127 fprintf ( stderr, "select() failed: %s\n",
128 strerror ( errno ) );
134 /* Return if we're not retrieving data yet */
139 len = read ( hijack->fd, nic->packet, ETH_FRAME_LEN );
141 fprintf ( stderr, "read() failed: %s\n",
142 strerror ( errno ) );
145 nic->packetlen = len;
150 static void hijack_transmit ( struct nic *nic, const char *dest,
151 unsigned int type, unsigned int size,
152 const char *packet ) {
153 struct hijack *hijack = nic->priv_data;
154 unsigned int nstype = htons ( type );
155 unsigned int total_size = ETH_HLEN + size;
156 char txbuf[ total_size ];
158 /* Build packet header */
159 memcpy ( txbuf, dest, ETH_ALEN );
160 memcpy ( txbuf + ETH_ALEN, nic->node_addr, ETH_ALEN );
161 memcpy ( txbuf + 2 * ETH_ALEN, &nstype, 2 );
162 memcpy ( txbuf + ETH_HLEN, packet, size );
165 if ( write ( hijack->fd, txbuf, total_size ) != total_size ) {
166 fprintf ( stderr, "write() failed: %s\n",
167 strerror ( errno ) );
171 static int hijack_connect ( struct nic *nic ) {
175 static void hijack_irq ( struct nic *nic, irq_action_t action ) {
179 static struct nic_operations hijack_operations = {
180 .connect = hijack_connect,
181 .transmit = hijack_transmit,
186 int hijack_probe ( struct hijack_device *hijack_dev ) {
188 struct hijack *hijack;
189 struct sockaddr_un sun;
192 nic = alloc_netdevice ( sizeof ( *hijack ) );
194 fprintf ( stderr, "alloc_netdevice() failed\n" );
197 hijack = nic->priv_data;
198 memset ( hijack, 0, sizeof ( *hijack ) );
201 hijack->fd = socket ( PF_UNIX, SOCK_SEQPACKET, 0 );
202 if ( hijack->fd < 0 ) {
203 fprintf ( stderr, "socket() failed: %s\n",
204 strerror ( errno ) );
208 /* Connect to hijack daemon */
209 sun.sun_family = AF_UNIX;
210 snprintf ( sun.sun_path, sizeof ( sun.sun_path ), "/var/run/hijack-%s",
212 if ( connect ( hijack->fd, ( struct sockaddr * ) &sun,
213 sizeof ( sun ) ) < 0 ) {
214 fprintf ( stderr, "could not connect to %s: %s\n",
215 sun.sun_path, strerror ( errno ) );
219 /* Generate MAC address */
220 srand ( time ( NULL ) );
221 for ( i = 0 ; i < ETH_ALEN ; i++ ) {
222 nic->node_addr[i] = ( rand() & 0xff );
224 nic->node_addr[0] &= 0xfe; /* clear multicast bit */
225 nic->node_addr[0] |= 0x02; /* set "locally-assigned" bit */
227 nic->nic_op = &hijack_operations;
228 if ( register_netdevice ( nic ) < 0 )
231 hijack_set_drvdata ( hijack_dev, nic );
235 if ( hijack->fd >= 0 )
236 close ( hijack->fd );
237 free_netdevice ( nic );
242 static void hijack_disable ( struct hijack_device *hijack_dev ) {
243 struct nic *nic = hijack_get_drvdata ( hijack_dev );
244 struct hijack *hijack = nic->priv_data;
246 unregister_netdevice ( nic );
247 close ( hijack->fd );
250 /*****************************************************************************
252 * "Hello world" protocol tester
256 struct hello_options {
257 struct sockaddr_in server;
261 static void hello_usage ( char **argv ) {
263 "Usage: %s [global options] hello [hello-specific options]\n"
265 "hello-specific options:\n"
266 " -h|--host Host IP address\n"
267 " -p|--port Port number\n"
268 " -m|--message Message to send\n",
272 static int hello_parse_options ( int argc, char **argv,
273 struct hello_options *options ) {
274 static struct option long_options[] = {
275 { "host", 1, NULL, 'h' },
276 { "port", 1, NULL, 'p' },
277 { "message", 1, NULL, 'm' },
283 /* Set default options */
284 memset ( options, 0, sizeof ( *options ) );
285 inet_aton ( "192.168.0.1", &options->server.sin_addr );
286 options->server.sin_port = htons ( 80 );
287 options->message = "Hello world!";
289 /* Parse command-line options */
291 int option_index = 0;
293 c = getopt_long ( argc, argv, "h:p:", long_options,
300 if ( inet_aton ( optarg,
301 &options->server.sin_addr ) == 0 ) {
302 fprintf ( stderr, "Invalid IP address %s\n",
308 options->server.sin_port =
309 htons ( strtoul ( optarg, &endptr, 0 ) );
310 if ( *endptr != '\0' ) {
311 fprintf ( stderr, "Invalid port %s\n",
317 options->message = optarg;
320 /* Unrecognised option */
323 fprintf ( stderr, "Unrecognised option '-%c'\n", c );
328 /* Check there are no remaining arguments */
329 if ( optind != argc ) {
330 hello_usage ( argv );
337 static void test_hello_callback ( char *data, size_t len ) {
341 for ( i = 0 ; i < len ; i++ ) {
345 } else if ( ( c == '\n' ) || ( c >= 32 ) || ( c <= 126 ) ) {
353 static int test_hello ( int argc, char **argv ) {
354 struct hello_options options;
355 struct hello_request hello;
357 /* Parse hello-specific options */
358 if ( hello_parse_options ( argc, argv, &options ) < 0 )
361 /* Construct hello request */
362 memset ( &hello, 0, sizeof ( hello ) );
363 hello.tcp.sin = options.server;
364 hello.message = options.message;
365 hello.callback = test_hello_callback;
366 fprintf ( stderr, "Saying \"%s\" to %s:%d\n", hello.message,
367 inet_ntoa ( hello.tcp.sin.sin_addr ),
368 ntohs ( hello.tcp.sin.sin_port ) );
370 /* Issue hello request and run to completion */
371 hello_connect ( &hello );
372 while ( ! hello.complete ) {
379 /*****************************************************************************
385 struct protocol_test {
387 int ( *exec ) ( int argc, char **argv );
390 static struct protocol_test tests[] = {
391 { "hello", test_hello },
394 #define NUM_TESTS ( sizeof ( tests ) / sizeof ( tests[0] ) )
396 static void list_tests ( void ) {
399 for ( i = 0 ; i < NUM_TESTS ; i++ ) {
400 printf ( "%s\n", tests[i].name );
404 static struct protocol_test * get_test_from_name ( const char *name ) {
407 for ( i = 0 ; i < NUM_TESTS ; i++ ) {
408 if ( strcmp ( name, tests[i].name ) == 0 )
415 /*****************************************************************************
417 * Parse command-line options
421 struct tester_options {
422 char interface[IF_NAMESIZE];
423 struct in_addr in_addr;
426 static void usage ( char **argv ) {
428 "Usage: %s [global options] <test> [test-specific options]\n"
431 " -h|--help Print this help message\n"
432 " -i|--interface intf Use specified network interface\n"
433 " -f|--from ip-address Use specified local IP address\n"
434 " -l|--list List available tests\n"
436 "Use \"%s <test> -h\" to view test-specific options\n",
440 static int parse_options ( int argc, char **argv,
441 struct tester_options *options ) {
442 static struct option long_options[] = {
443 { "interface", 1, NULL, 'i' },
444 { "from", 1, NULL, 'f' },
445 { "list", 0, NULL, 'l' },
446 { "help", 0, NULL, 'h' },
451 /* Set default options */
452 memset ( options, 0, sizeof ( *options ) );
453 strncpy ( options->interface, "eth0", sizeof ( options->interface ) );
454 inet_aton ( "192.168.0.2", &options->in_addr );
456 /* Parse command-line options */
458 int option_index = 0;
460 c = getopt_long ( argc, argv, "+i:f:hl", long_options,
467 strncpy ( options->interface, optarg,
468 sizeof ( options->interface ) );
471 if ( inet_aton ( optarg, &options->in_addr ) == 0 ) {
472 fprintf ( stderr, "Invalid IP address %s\n",
484 /* Unrecognised option */
487 fprintf ( stderr, "Unrecognised option '-%c'\n", c );
492 /* Check there is a test specified */
493 if ( optind == argc ) {
501 /*****************************************************************************
507 int main ( int argc, char **argv ) {
508 struct tester_options options;
509 struct protocol_test *test;
510 struct hijack_device hijack_dev;
512 /* Parse command-line options */
513 if ( parse_options ( argc, argv, &options ) < 0 )
517 test = get_test_from_name ( argv[optind] );
519 fprintf ( stderr, "Unrecognised test \"%s\"\n", argv[optind] );
524 /* Initialise the protocol stack */
526 set_ipaddr ( options.in_addr );
528 /* Open the hijack device */
529 hijack_dev.name = options.interface;
530 if ( ! hijack_probe ( &hijack_dev ) )
534 if ( test->exec ( argc, argv ) < 0 )
537 /* Close the hijack device */
538 hijack_disable ( &hijack_dev );