aboutsummaryrefslogtreecommitdiffstats
path: root/src/util
diff options
context:
space:
mode:
authorMichael Brown <mcb30@etherboot.org>2006-03-22 02:23:20 +0000
committerMichael Brown <mcb30@etherboot.org>2006-03-22 02:23:20 +0000
commitc32e83ad8d06ab545ac89b6ebdefeb8d5afa035e (patch)
tree3f1bd3de5b320928d4b101500aa885ded23ec9f8 /src/util
parentbb37bd47f873241ad0a329896f6da4f1d7cedcab (diff)
downloadipxe-c32e83ad8d06ab545ac89b6ebdefeb8d5afa035e.tar.gz
Skeleton version: contains device driver (connecting to network via
hijack daemon) and a functional but very ugly and very primitive wrapper around uIP. This passes proof-of-concept testing; it successfully initiates a TCP connection and responds to pings.
Diffstat (limited to 'src/util')
-rw-r--r--src/util/prototester.c338
1 files changed, 338 insertions, 0 deletions
diff --git a/src/util/prototester.c b/src/util/prototester.c
new file mode 100644
index 000000000..ae2989798
--- /dev/null
+++ b/src/util/prototester.c
@@ -0,0 +1,338 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <getopt.h>
+
+typedef int irq_action_t;
+
+struct nic {
+ struct nic_operations *nic_op;
+ unsigned char *node_addr;
+ unsigned char *packet;
+ unsigned int packetlen;
+ void *priv_data; /* driver private data */
+};
+
+struct nic_operations {
+ int ( *connect ) ( struct nic * );
+ int ( *poll ) ( struct nic *, int retrieve );
+ void ( *transmit ) ( struct nic *, const char *,
+ unsigned int, unsigned int, const char * );
+ void ( *irq ) ( struct nic *, irq_action_t );
+};
+
+/*****************************************************************************
+ *
+ * Hijack device interface
+ *
+ * This requires a hijack daemon to be running
+ *
+ */
+
+struct hijack {
+ int fd;
+};
+
+struct hijack_device {
+ char *name;
+};
+
+static int hijack_poll ( struct nic *nic, int retrieve ) {
+ struct hijack *hijack = nic->priv_data;
+ fd_set fdset;
+ struct timeval tv;
+ int ready;
+ ssize_t len;
+
+ /* Poll for data */
+ FD_ZERO ( &fdset );
+ FD_SET ( hijack->fd, &fdset );
+ tv.tv_sec = 0;
+ tv.tv_usec = 500; /* 500us to avoid hogging CPU */
+ ready = select ( ( hijack->fd + 1 ), &fdset, NULL, NULL, &tv );
+ if ( ready < 0 ) {
+ fprintf ( stderr, "select() failed: %s\n",
+ strerror ( errno ) );
+ return 0;
+ }
+ if ( ready == 0 )
+ return 0;
+
+ /* Return if we're not retrieving data yet */
+ if ( ! retrieve )
+ return 1;
+
+ /* Fetch data */
+ len = read ( hijack->fd, nic->packet, ETH_FRAME_LEN );
+ if ( len < 0 ) {
+ fprintf ( stderr, "read() failed: %s\n",
+ strerror ( errno ) );
+ return 0;
+ }
+ nic->packetlen = len;
+
+ return 1;
+}
+
+static void hijack_transmit ( struct nic *nic, const char *dest,
+ unsigned int type, unsigned int size,
+ const char *packet ) {
+ struct hijack *hijack = nic->priv_data;
+ unsigned int nstype = htons ( type );
+ unsigned int total_size = ETH_HLEN + size;
+ char txbuf[ total_size ];
+
+ /* Build packet header */
+ memcpy ( txbuf, dest, ETH_ALEN );
+ memcpy ( txbuf + ETH_ALEN, nic->node_addr, ETH_ALEN );
+ memcpy ( txbuf + 2 * ETH_ALEN, &nstype, 2 );
+ memcpy ( txbuf + ETH_HLEN, packet, size );
+
+ /* Transmit data */
+ if ( write ( hijack->fd, txbuf, total_size ) != total_size ) {
+ fprintf ( stderr, "write() failed: %s\n",
+ strerror ( errno ) );
+ }
+}
+
+static int hijack_connect ( struct nic *nic ) {
+ return 1;
+}
+
+static void hijack_irq ( struct nic *nic, irq_action_t action ) {
+ /* Do nothing */
+}
+
+static struct nic_operations hijack_operations = {
+ .connect = hijack_connect,
+ .transmit = hijack_transmit,
+ .poll = hijack_poll,
+ .irq = hijack_irq,
+};
+
+static int hijack_probe ( struct nic *nic, struct hijack_device *hijack_dev ) {
+ static struct hijack hijack;
+ struct sockaddr_un sun;
+ int i;
+
+ memset ( &hijack, 0, sizeof ( hijack ) );
+
+ /* Create socket */
+ hijack.fd = socket ( PF_UNIX, SOCK_SEQPACKET, 0 );
+ if ( hijack.fd < 0 ) {
+ fprintf ( stderr, "socket() failed: %s\n",
+ strerror ( errno ) );
+ goto err;
+ }
+
+ /* Connect to hijack daemon */
+ sun.sun_family = AF_UNIX;
+ snprintf ( sun.sun_path, sizeof ( sun.sun_path ), "/var/run/hijack-%s",
+ hijack_dev->name );
+ if ( connect ( hijack.fd, ( struct sockaddr * ) &sun,
+ sizeof ( sun ) ) < 0 ) {
+ fprintf ( stderr, "could not connect to %s: %s\n",
+ sun.sun_path, strerror ( errno ) );
+ goto err;
+ }
+
+ /* Generate MAC address */
+ srand ( time ( NULL ) );
+ for ( i = 0 ; i < ETH_ALEN ; i++ ) {
+ nic->node_addr[i] = ( rand() & 0xff );
+ }
+ nic->node_addr[0] &= 0xfe; /* clear multicast bit */
+ nic->node_addr[0] |= 0x02; /* set "locally-assigned" bit */
+
+ nic->priv_data = &hijack;
+ nic->nic_op = &hijack_operations;
+ return 1;
+
+ err:
+ if ( hijack.fd >= 0 )
+ close ( hijack.fd );
+ return 0;
+}
+
+static void hijack_disable ( struct nic *nic,
+ struct hijack_device *hijack_dev ) {
+ struct hijack *hijack = nic->priv_data;
+
+ close ( hijack->fd );
+}
+
+/*****************************************************************************
+ *
+ * Parse command-line options
+ *
+ */
+
+struct tester_options {
+ char interface[IF_NAMESIZE];
+};
+
+static void usage ( char **argv ) {
+ fprintf ( stderr,
+ "Usage: %s [options]\n"
+ "\n"
+ "Options:\n"
+ " -h|--help Print this help message\n"
+ " -i|--interface intf Use specified network interface\n",
+ argv[0] );
+}
+
+static int parse_options ( int argc, char **argv,
+ struct tester_options *options ) {
+ static struct option long_options[] = {
+ { "interface", 1, NULL, 'i' },
+ { "help", 0, NULL, 'h' },
+ { },
+ };
+ int c;
+
+ /* Set default options */
+ memset ( options, 0, sizeof ( *options ) );
+ strncpy ( options->interface, "eth0", sizeof ( options->interface ) );
+
+ /* Parse command-line options */
+ while ( 1 ) {
+ int option_index = 0;
+
+ c = getopt_long ( argc, argv, "i:h", long_options,
+ &option_index );
+ if ( c < 0 )
+ break;
+
+ switch ( c ) {
+ case 'i':
+ strncpy ( options->interface, optarg,
+ sizeof ( options->interface ) );
+ break;
+ case 'h':
+ usage( argv );
+ return -1;
+ case '?':
+ /* Unrecognised option */
+ return -1;
+ default:
+ fprintf ( stderr, "Unrecognised option '-%c'\n", c );
+ return -1;
+ }
+ }
+
+ /* Check there's nothing left over on the command line */
+ if ( optind != argc ) {
+ usage ( argv );
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * uIP wrapper layer
+ *
+ */
+
+#include "../proto/uip/uip.h"
+#include "../proto/uip/uip_arp.h"
+
+static int done;
+
+void UIP_APPCALL ( void ) {
+ printf ( "appcall\n" );
+}
+
+void udp_appcall ( void ) {
+}
+
+static void uip_transmit ( struct nic *nic ) {
+ uip_arp_out();
+ nic->nic_op->transmit ( nic, ( char * ) uip_buf,
+ ntohs ( *( ( uint16_t * ) ( uip_buf + 12 ) ) ),
+ uip_len - ETH_HLEN,
+ ( char * ) uip_buf + ETH_HLEN );
+ uip_len = 0;
+}
+
+static void run_stack ( struct nic *nic ) {
+ struct uip_eth_addr hwaddr;
+ u16_t ipaddr[2];
+ uint16_t type;
+ int i;
+
+ uip_init();
+ uip_arp_init();
+ memcpy ( &hwaddr, nic->node_addr, sizeof ( hwaddr ) );
+ uip_setethaddr ( hwaddr );
+
+ uip_ipaddr(ipaddr, 192,168,0,1);
+ uip_connect(ipaddr, HTONS(80));
+
+ done = 0;
+ while ( ! done ) {
+ if ( nic->nic_op->poll ( nic, 1 ) ) {
+ /* We have data */
+ memcpy ( uip_buf, nic->packet, nic->packetlen );
+ uip_len = nic->packetlen;
+ type = ntohs ( *( ( uint16_t * ) ( uip_buf + 12 ) ) );
+ if ( type == ETHERTYPE_ARP ) {
+ uip_arp_arpin();
+ } else {
+ uip_arp_ipin();
+ uip_input();
+ }
+ if ( uip_len > 0 )
+ uip_transmit ( nic );
+ } else {
+ for ( i = 0 ; i < UIP_CONNS ; i++ ) {
+ uip_periodic ( i );
+ if ( uip_len > 0 )
+ uip_transmit ( nic );
+ }
+ }
+ }
+}
+
+/*****************************************************************************
+ *
+ * Main program
+ *
+ */
+
+int main ( int argc, char **argv ) {
+ struct tester_options options;
+ struct hijack_device hijack_dev;
+ static unsigned char node_addr[ETH_ALEN];
+ static unsigned char packet[ETH_FRAME_LEN];
+ struct nic nic = {
+ .node_addr = node_addr,
+ .packet = packet,
+ };
+
+ /* Parse command-line options */
+ if ( parse_options ( argc, argv, &options ) < 0 )
+ exit ( 1 );
+
+ /* Open the hijack device */
+ hijack_dev.name = options.interface;
+ if ( ! hijack_probe ( &nic, &hijack_dev ) )
+ exit ( 1 );
+
+ /* Run the stack to completion */
+ run_stack ( &nic );
+
+ /* Close the hijack device */
+ hijack_disable ( &nic, &hijack_dev );
+
+ return 0;
+}