7 #include <sys/socket.h>
10 #include <net/ethernet.h>
15 #include <gpxe/hello.h>
17 typedef int irq_action_t;
20 struct nic_operations *nic_op;
21 unsigned char *node_addr;
22 unsigned char *packet;
23 unsigned int packetlen;
24 void *priv_data; /* driver private data */
27 struct nic_operations {
28 int ( *connect ) ( struct nic * );
29 int ( *poll ) ( struct nic *, int retrieve );
30 void ( *transmit ) ( struct nic *, const char *,
31 unsigned int, unsigned int, const char * );
32 void ( *irq ) ( struct nic *, irq_action_t );
35 /*****************************************************************************
41 #include "../proto/uip/uip_arp.h"
43 static unsigned char node_addr[ETH_ALEN];
44 static unsigned char packet[ETH_FRAME_LEN];
45 struct nic static_nic = {
46 .node_addr = node_addr,
50 /* Must be a macro because priv_data[] is of variable size */
51 #define alloc_netdevice( priv_size ) ( { \
52 static char priv_data[priv_size]; \
53 static_nic.priv_data = priv_data; \
56 static int register_netdevice ( struct nic *nic ) {
57 struct uip_eth_addr hwaddr;
59 memcpy ( &hwaddr, nic->node_addr, sizeof ( hwaddr ) );
60 uip_setethaddr ( hwaddr );
64 static inline void unregister_netdevice ( struct nic *nic ) {
68 static inline void free_netdevice ( struct nic *nic ) {
72 int netdev_poll ( int retrieve, void **data, size_t *len ) {
73 int rc = static_nic.nic_op->poll ( &static_nic, retrieve );
74 *data = static_nic.packet;
75 *len = static_nic.packetlen;
79 void netdev_transmit ( const void *data, size_t len ) {
80 uint16_t type = ntohs ( *( ( uint16_t * ) ( data + 12 ) ) );
81 static_nic.nic_op->transmit ( &static_nic, data, type,
86 /*****************************************************************************
88 * Hijack device interface
90 * This requires a hijack daemon to be running
98 struct hijack_device {
103 static inline void hijack_set_drvdata ( struct hijack_device *hijack_dev,
105 hijack_dev->priv = data;
108 static inline void * hijack_get_drvdata ( struct hijack_device *hijack_dev ) {
109 return hijack_dev->priv;
112 static int hijack_poll ( struct nic *nic, int retrieve ) {
113 struct hijack *hijack = nic->priv_data;
121 FD_SET ( hijack->fd, &fdset );
123 tv.tv_usec = 500; /* 500us to avoid hogging CPU */
124 ready = select ( ( hijack->fd + 1 ), &fdset, NULL, NULL, &tv );
126 fprintf ( stderr, "select() failed: %s\n",
127 strerror ( errno ) );
133 /* Return if we're not retrieving data yet */
138 len = read ( hijack->fd, nic->packet, ETH_FRAME_LEN );
140 fprintf ( stderr, "read() failed: %s\n",
141 strerror ( errno ) );
144 nic->packetlen = len;
149 static void hijack_transmit ( struct nic *nic, const char *dest,
150 unsigned int type, unsigned int size,
151 const char *packet ) {
152 struct hijack *hijack = nic->priv_data;
153 unsigned int nstype = htons ( type );
154 unsigned int total_size = ETH_HLEN + size;
155 char txbuf[ total_size ];
157 /* Build packet header */
158 memcpy ( txbuf, dest, ETH_ALEN );
159 memcpy ( txbuf + ETH_ALEN, nic->node_addr, ETH_ALEN );
160 memcpy ( txbuf + 2 * ETH_ALEN, &nstype, 2 );
161 memcpy ( txbuf + ETH_HLEN, packet, size );
164 if ( write ( hijack->fd, txbuf, total_size ) != total_size ) {
165 fprintf ( stderr, "write() failed: %s\n",
166 strerror ( errno ) );
170 static int hijack_connect ( struct nic *nic ) {
174 static void hijack_irq ( struct nic *nic, irq_action_t action ) {
178 static struct nic_operations hijack_operations = {
179 .connect = hijack_connect,
180 .transmit = hijack_transmit,
185 int hijack_probe ( struct hijack_device *hijack_dev ) {
187 struct hijack *hijack;
188 struct sockaddr_un sun;
191 nic = alloc_netdevice ( sizeof ( *hijack ) );
193 fprintf ( stderr, "alloc_netdevice() failed\n" );
196 hijack = nic->priv_data;
197 memset ( hijack, 0, sizeof ( *hijack ) );
200 hijack->fd = socket ( PF_UNIX, SOCK_SEQPACKET, 0 );
201 if ( hijack->fd < 0 ) {
202 fprintf ( stderr, "socket() failed: %s\n",
203 strerror ( errno ) );
207 /* Connect to hijack daemon */
208 sun.sun_family = AF_UNIX;
209 snprintf ( sun.sun_path, sizeof ( sun.sun_path ), "/var/run/hijack-%s",
211 if ( connect ( hijack->fd, ( struct sockaddr * ) &sun,
212 sizeof ( sun ) ) < 0 ) {
213 fprintf ( stderr, "could not connect to %s: %s\n",
214 sun.sun_path, strerror ( errno ) );
218 /* Generate MAC address */
219 srand ( time ( NULL ) );
220 for ( i = 0 ; i < ETH_ALEN ; i++ ) {
221 nic->node_addr[i] = ( rand() & 0xff );
223 nic->node_addr[0] &= 0xfe; /* clear multicast bit */
224 nic->node_addr[0] |= 0x02; /* set "locally-assigned" bit */
226 nic->nic_op = &hijack_operations;
227 if ( register_netdevice ( nic ) < 0 )
230 hijack_set_drvdata ( hijack_dev, nic );
234 if ( hijack->fd >= 0 )
235 close ( hijack->fd );
236 free_netdevice ( nic );
241 static void hijack_disable ( struct hijack_device *hijack_dev ) {
242 struct nic *nic = hijack_get_drvdata ( hijack_dev );
243 struct hijack *hijack = nic->priv_data;
245 unregister_netdevice ( nic );
246 close ( hijack->fd );
249 /*****************************************************************************
251 * "Hello world" protocol tester
255 struct hello_options {
256 struct sockaddr_in server;
260 static void hello_usage ( char **argv ) {
262 "Usage: %s [global options] hello [hello-specific options]\n"
264 "hello-specific options:\n"
265 " -h|--host Host IP address\n"
266 " -p|--port Port number\n"
267 " -m|--message Message to send\n",
271 static int hello_parse_options ( int argc, char **argv,
272 struct hello_options *options ) {
273 static struct option long_options[] = {
274 { "host", 1, NULL, 'h' },
275 { "port", 1, NULL, 'p' },
276 { "message", 1, NULL, 'm' },
282 /* Set default options */
283 memset ( options, 0, sizeof ( *options ) );
284 inet_aton ( "192.168.0.1", &options->server.sin_addr );
285 options->server.sin_port = htons ( 80 );
286 options->message = "Hello world!";
288 /* Parse command-line options */
290 int option_index = 0;
292 c = getopt_long ( argc, argv, "h:p:", long_options,
299 if ( inet_aton ( optarg,
300 &options->server.sin_addr ) == 0 ) {
301 fprintf ( stderr, "Invalid IP address %s\n",
307 options->server.sin_port =
308 htons ( strtoul ( optarg, &endptr, 0 ) );
309 if ( *endptr != '\0' ) {
310 fprintf ( stderr, "Invalid port %s\n",
316 options->message = optarg;
319 /* Unrecognised option */
322 fprintf ( stderr, "Unrecognised option '-%c'\n", c );
327 /* Check there are no remaining arguments */
328 if ( optind != argc ) {
329 hello_usage ( argv );
336 static void test_hello_callback ( char *data, size_t len ) {
340 for ( i = 0 ; i < len ; i++ ) {
344 } else if ( ( c == '\n' ) || ( c >= 32 ) || ( c <= 126 ) ) {
352 static int test_hello ( int argc, char **argv ) {
353 struct hello_options options;
354 struct hello_request hello;
356 /* Parse hello-specific options */
357 if ( hello_parse_options ( argc, argv, &options ) < 0 )
360 /* Construct hello request */
361 memset ( &hello, 0, sizeof ( hello ) );
362 hello.tcp.sin = options.server;
363 hello.message = options.message;
364 hello.callback = test_hello_callback;
365 fprintf ( stderr, "Saying \"%s\" to %s:%d\n", hello.message,
366 inet_ntoa ( hello.tcp.sin.sin_addr ),
367 ntohs ( hello.tcp.sin.sin_port ) );
369 /* Issue hello request and run to completion */
370 hello_connect ( &hello );
371 while ( ! hello.complete ) {
378 /*****************************************************************************
384 struct protocol_test {
386 int ( *exec ) ( int argc, char **argv );
389 static struct protocol_test tests[] = {
390 { "hello", test_hello },
393 #define NUM_TESTS ( sizeof ( tests ) / sizeof ( tests[0] ) )
395 static void list_tests ( void ) {
398 for ( i = 0 ; i < NUM_TESTS ; i++ ) {
399 printf ( "%s\n", tests[i].name );
403 static struct protocol_test * get_test_from_name ( const char *name ) {
406 for ( i = 0 ; i < NUM_TESTS ; i++ ) {
407 if ( strcmp ( name, tests[i].name ) == 0 )
414 /*****************************************************************************
416 * Parse command-line options
420 struct tester_options {
421 char interface[IF_NAMESIZE];
424 static void usage ( char **argv ) {
426 "Usage: %s [global options] <test> [test-specific options]\n"
429 " -h|--help Print this help message\n"
430 " -i|--interface intf Use specified network interface\n"
431 " -l|--list List available tests\n"
433 "Use \"%s <test> -h\" to view test-specific options\n",
437 static int parse_options ( int argc, char **argv,
438 struct tester_options *options ) {
439 static struct option long_options[] = {
440 { "interface", 1, NULL, 'i' },
441 { "list", 0, NULL, 'l' },
442 { "help", 0, NULL, 'h' },
447 /* Set default options */
448 memset ( options, 0, sizeof ( *options ) );
449 strncpy ( options->interface, "eth0", sizeof ( options->interface ) );
451 /* Parse command-line options */
453 int option_index = 0;
455 c = getopt_long ( argc, argv, "+i:hl", long_options,
462 strncpy ( options->interface, optarg,
463 sizeof ( options->interface ) );
472 /* Unrecognised option */
475 fprintf ( stderr, "Unrecognised option '-%c'\n", c );
480 /* Check there is a test specified */
481 if ( optind == argc ) {
489 /*****************************************************************************
495 int main ( int argc, char **argv ) {
496 struct tester_options options;
497 struct protocol_test *test;
498 struct hijack_device hijack_dev;
500 /* Parse command-line options */
501 if ( parse_options ( argc, argv, &options ) < 0 )
505 test = get_test_from_name ( argv[optind] );
507 fprintf ( stderr, "Unrecognised test \"%s\"\n", argv[optind] );
512 /* Initialise the protocol stack */
515 /* Open the hijack device */
516 hijack_dev.name = options.interface;
517 if ( ! hijack_probe ( &hijack_dev ) )
521 if ( test->exec ( argc, argv ) < 0 )
524 /* Close the hijack device */
525 hijack_disable ( &hijack_dev );