Moved uIP wrapper out of prototester.c and into proto/tcp.c.
authorMichael Brown <mcb30@etherboot.org>
Thu, 23 Mar 2006 21:32:03 +0000 (21:32 +0000)
committerMichael Brown <mcb30@etherboot.org>
Thu, 23 Mar 2006 21:32:03 +0000 (21:32 +0000)
src/include/gpxe/tcp.h [new file with mode: 0644]
src/proto/tcp.c [new file with mode: 0644]
src/util/prototester.c

diff --git a/src/include/gpxe/tcp.h b/src/include/gpxe/tcp.h
new file mode 100644 (file)
index 0000000..c661114
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef _TCP_H
+#define _TCP_H
+
+/** @file
+ *
+ * TCP protocol
+ *
+ * This file defines the gPXE TCP API.
+ *
+ */
+
+#include <stddef.h>
+#include <gpxe/in.h>
+
+struct tcp_connection;
+
+/**
+ * TCP operations
+ *
+ */
+struct tcp_operations {
+       /**
+        * Connection aborted (RST received)
+        *
+        * @v conn      TCP connection
+        */
+       void ( * aborted ) ( struct tcp_connection *conn );
+       /**
+        * Connection timed out
+        *
+        * @v conn      TCP connection
+        */
+       void ( * timedout ) ( struct tcp_connection *conn );
+       /**
+        * Connection aborted (FIN received)
+        *
+        * @v conn      TCP connection
+        *
+        * Note that acked() and newdata() may be called after
+        * closed(), if the packet containing the FIN also
+        * acknowledged data or contained new data.
+        */
+       void ( * closed ) ( struct tcp_connection *conn );
+       /**
+        * Connection established (SYNACK received)
+        *
+        * @v conn      TCP connection
+        */
+       void ( * connected ) ( struct tcp_connection *conn );
+       /**
+        * Data acknowledged
+        *
+        * @v conn      TCP connection
+        * @v len       Length of acknowledged data
+        *
+        * @c len is guaranteed to not exceed the outstanding amount
+        * of unacknowledged data.
+        */
+       void ( * acked ) ( struct tcp_connection *conn, size_t len );
+       /**
+        * New data received
+        *
+        * @v conn      TCP connection
+        * @v data      Data
+        * @v len       Length of data
+        */
+       void ( * newdata ) ( struct tcp_connection *conn,
+                            void *data, size_t len );
+       /**
+        * Transmit data
+        *
+        * @v conn      TCP connection
+        *
+        * The application should transmit whatever it currently wants
+        * to send using tcp_send().  If retransmissions are required,
+        * senddata() will be called again and the application must
+        * regenerate the data.  The easiest way to implement this is
+        * to ensure that senddata() never changes the application's
+        * state.
+        */
+       void ( * senddata ) ( struct tcp_connection *conn );
+};
+
+/**
+ * A TCP connection
+ *
+ */
+struct tcp_connection {
+       /** Address of the remote end of the connection */
+       struct sockaddr_in sin;
+       /** Operations table for this connection */
+       struct tcp_operations *tcp_op;
+};
+
+extern int tcp_connect ( struct tcp_connection *conn );
+extern void tcp_send ( struct tcp_connection *conn, const void *data,
+                      size_t len );
+extern void tcp_close ( struct tcp_connection *conn );
+extern void init_tcpip ( void );
+extern void run_tcpip ( void );
+
+#endif /* _TCP_H */
diff --git a/src/proto/tcp.c b/src/proto/tcp.c
new file mode 100644 (file)
index 0000000..8c73201
--- /dev/null
@@ -0,0 +1,206 @@
+#include <string.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <gpxe/tcp.h>
+#include "uip/uip.h"
+#include "uip/uip_arp.h"
+
+/** @file
+ *
+ * TCP protocol
+ *
+ * The gPXE TCP stack is currently implemented on top of the uIP
+ * protocol stack.  This file provides wrappers around uIP so that
+ * higher-level protocol implementations do not need to talk directly
+ * to uIP (which has a somewhat baroque API).
+ *
+ * Basic operation is to create a #tcp_connection structure, call
+ * tcp_connect() and then call run_tcpip() in a loop until the
+ * operation has completed.  The TCP stack will call the various
+ * methods defined in the #tcp_operations structure in order to send
+ * and receive data.
+ *
+ * See hello.c for a trivial example of a TCP protocol using this
+ * API.
+ *
+ */
+
+/**
+ * Initialise TCP/IP stack
+ *
+ */
+void init_tcpip ( void ) {
+       uip_init();
+       uip_arp_init();
+}
+
+#define UIP_HLEN ( 40 + UIP_LLH_LEN )
+
+/**
+ * Transmit TCP data
+ *
+ * This is a wrapper around netdev_transmit().  It gathers up the
+ * packet produced by uIP, and then passes it to netdev_transmit() as
+ * a single buffer.
+ */
+static void uip_transmit ( void ) {
+       uip_arp_out();
+       if ( uip_len > UIP_HLEN ) {
+               memcpy ( uip_buf + UIP_HLEN, ( void * ) uip_appdata,
+                        uip_len - UIP_HLEN );
+       }
+       netdev_transmit ( uip_buf, uip_len );
+       uip_len = 0;
+}
+
+/**
+ * Run the TCP/IP stack
+ *
+ * Call this function in a loop in order to allow TCP/IP processing to
+ * take place.  This call takes the stack through a single iteration;
+ * it will typically be used in a loop such as
+ *
+ * @code
+ *
+ * struct tcp_connection *my_connection;
+ * ...
+ * tcp_connect ( my_connection );
+ * while ( ! my_connection->finished ) {
+ *   run_tcpip();
+ * }
+ *
+ * @endcode
+ *
+ * where @c my_connection->finished is set by one of the connection's
+ * #tcp_operations methods to indicate completion.
+ */
+void run_tcpip ( void ) {
+       void *data;
+       size_t len;
+       uint16_t type;
+       int i;
+       
+       if ( netdev_poll ( 1, &data, &len ) ) {
+               /* We have data */
+               memcpy ( uip_buf, data, len );
+               uip_len = len;
+               type = ntohs ( *( ( uint16_t * ) ( uip_buf + 12 ) ) );
+               if ( type == UIP_ETHTYPE_ARP ) {
+                       uip_arp_arpin();
+               } else {
+                       uip_arp_ipin();
+                       uip_input();
+               }
+               if ( uip_len > 0 )
+                       uip_transmit();
+       } else {
+               for ( i = 0 ; i < UIP_CONNS ; i++ ) {
+                       uip_periodic ( i );
+                       if ( uip_len > 0 )
+                               uip_transmit();
+               }
+       }
+}
+
+/**
+ * Open a TCP connection
+ *
+ * @v conn     TCP connection
+ * @ret 0      Success
+ * @ret <0     Failure
+ * 
+ * This sets up a new TCP connection to the remote host specified in
+ * tcp_connection::sin.  The actual SYN packet will not be sent out
+ * until run_tcpip() is called for the first time.
+ *
+ * @todo Use linked lists instead of a static buffer, and thereby
+ *       remove the only potential failure case, giving this function
+ *       a void return type.
+ */
+int tcp_connect ( struct tcp_connection *conn ) {
+       struct uip_conn *uip_conn;
+       u16_t ipaddr[2];
+
+       assert ( conn->sin.sin_addr.s_addr != 0 );
+       assert ( conn->sin.sin_port != 0 );
+       assert ( conn->tcp_op != NULL );
+       assert ( sizeof ( uip_conn->appstate ) == sizeof ( conn ) );
+
+       * ( ( uint32_t * ) ipaddr ) = conn->sin.sin_addr.s_addr;
+       uip_conn = uip_connect ( ipaddr, conn->sin.sin_port );
+       if ( ! uip_conn )
+               return -1;
+
+       *( ( void ** ) uip_conn->appstate ) = conn;
+       return 0;
+}
+
+/**
+ * Send data via a TCP connection
+ *
+ * @v conn     TCP connection
+ * @v data     Data to send
+ * @v len      Length of data
+ *
+ * Data will be automatically limited to the current TCP window size.
+ *
+ * If retransmission is required, the connection's
+ * tcp_operations::newdata() method will be called again in order to
+ * regenerate the data.
+ */
+void tcp_send ( struct tcp_connection *conn __unused,
+               const void *data, size_t len ) {
+       assert ( conn = *( ( void ** ) uip_conn->appstate ) );
+       uip_send ( ( void * ) data, len );
+}
+
+/**
+ * Close a TCP connection
+ *
+ * @v conn     TCP connection
+ */
+void tcp_close ( struct tcp_connection *conn __unused ) {
+       assert ( conn = *( ( void ** ) uip_conn->appstate ) );
+       uip_close();
+}
+
+/**
+ * uIP TCP application call interface
+ *
+ * This is the entry point of gPXE from the point of view of the uIP
+ * protocol stack.  This function calls the appropriate methods from
+ * the connection's @tcp_operations table in order to process received
+ * data, transmit new data etc.
+ */
+void uip_tcp_appcall ( void ) {
+       struct tcp_connection *conn = *( ( void ** ) uip_conn->appstate );
+       struct tcp_operations *op = conn->tcp_op;
+
+       assert ( conn->tcp_op->closed != NULL );
+       assert ( conn->tcp_op->connected != NULL );
+       assert ( conn->tcp_op->acked != NULL );
+       assert ( conn->tcp_op->newdata != NULL );
+       assert ( conn->tcp_op->senddata != NULL );
+
+       if ( uip_aborted() && op->aborted ) /* optional method */
+               op->aborted ( conn );
+       if ( uip_timedout() && op->timedout ) /* optional method */
+               op->timedout ( conn );
+       if ( uip_closed() && op->closed ) /* optional method */
+               op->closed ( conn );
+       if ( uip_connected() )
+               op->connected ( conn );
+       if ( uip_acked() )
+               op->acked ( conn, uip_conn->len );
+       if ( uip_newdata() )
+               op->newdata ( conn, ( void * ) uip_appdata, uip_len );
+       if ( uip_rexmit() || uip_newdata() || uip_acked() ||
+            uip_connected() || uip_poll() )
+               op->senddata ( conn );
+}
+
+/* Present here to allow everything to link.  Will go into separate
+ * udp.c file
+ */
+void uip_udp_appcall ( void ) {
+}
index b4a5bc9..f520d66 100644 (file)
@@ -8,11 +8,11 @@
 #include <sys/un.h>
 #include <net/if.h>
 #include <net/ethernet.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
 #include <getopt.h>
 #include <assert.h>
 
+#include <gpxe/tcp.h>
+
 typedef int irq_action_t;
 
 struct nic {
@@ -68,14 +68,14 @@ static inline void free_netdevice ( struct nic *nic ) {
        /* Do nothing */
 }
 
-static int netdev_poll ( int retrieve, void **data, size_t *len ) {
+int netdev_poll ( int retrieve, void **data, size_t *len ) {
        int rc = static_nic.nic_op->poll ( &static_nic, retrieve );
        *data = static_nic.packet;
        *len = static_nic.packetlen;
        return rc;
 }
 
-static void netdev_transmit ( const void *data, size_t len ) {
+void netdev_transmit ( const void *data, size_t len ) {
        uint16_t type = ntohs ( *( ( uint16_t * ) ( data + 12 ) ) );
        static_nic.nic_op->transmit ( &static_nic, data, type,
                                      len - ETH_HLEN,
@@ -245,137 +245,6 @@ static void hijack_disable ( struct hijack_device *hijack_dev ) {
        close ( hijack->fd );
 }
 
-/*****************************************************************************
- *
- * uIP wrapper layer
- *
- */
-
-#include "../proto/uip/uip.h"
-#include "../proto/uip/uip_arp.h"
-
-struct tcp_connection;
-
-struct tcp_operations {
-       void ( * aborted ) ( struct tcp_connection *conn );
-       void ( * timedout ) ( struct tcp_connection *conn );
-       void ( * closed ) ( struct tcp_connection *conn );
-       void ( * connected ) ( struct tcp_connection *conn );
-       void ( * acked ) ( struct tcp_connection *conn, size_t len );
-       void ( * newdata ) ( struct tcp_connection *conn,
-                            void *data, size_t len );
-       void ( * senddata ) ( struct tcp_connection *conn );
-};
-
-struct tcp_connection {
-       struct sockaddr_in sin;
-       struct tcp_operations *tcp_op;
-};
-
-int tcp_connect ( struct tcp_connection *conn ) {
-       struct uip_conn *uip_conn;
-       u16_t ipaddr[2];
-
-       assert ( conn->sin.sin_addr.s_addr != 0 );
-       assert ( conn->sin.sin_port != 0 );
-       assert ( conn->tcp_op != NULL );
-       assert ( sizeof ( uip_conn->appstate ) == sizeof ( conn ) );
-
-       * ( ( uint32_t * ) ipaddr ) = conn->sin.sin_addr.s_addr;
-       uip_conn = uip_connect ( ipaddr, conn->sin.sin_port );
-       if ( ! uip_conn )
-               return -1;
-
-       *( ( void ** ) uip_conn->appstate ) = conn;
-       return 0;
-}
-
-void tcp_send ( struct tcp_connection *conn, const void *data,
-                      size_t len ) {
-       assert ( conn = *( ( void ** ) uip_conn->appstate ) );
-       uip_send ( ( void * ) data, len );
-}
-
-void tcp_close ( struct tcp_connection *conn ) {
-       assert ( conn = *( ( void ** ) uip_conn->appstate ) );
-       uip_close();
-}
-
-void uip_tcp_appcall ( void ) {
-       struct tcp_connection *conn = *( ( void ** ) uip_conn->appstate );
-       struct tcp_operations *op = conn->tcp_op;
-
-       assert ( conn->tcp_op->closed != NULL );
-       assert ( conn->tcp_op->connected != NULL );
-       assert ( conn->tcp_op->acked != NULL );
-       assert ( conn->tcp_op->newdata != NULL );
-       assert ( conn->tcp_op->senddata != NULL );
-
-       if ( uip_aborted() && op->aborted ) /* optional method */
-               op->aborted ( conn );
-       if ( uip_timedout() && op->timedout ) /* optional method */
-               op->timedout ( conn );
-       if ( uip_closed() && op->closed ) /* optional method */
-               op->closed ( conn );
-       if ( uip_connected() )
-               op->connected ( conn );
-       if ( uip_acked() )
-               op->acked ( conn, uip_conn->len );
-       if ( uip_newdata() )
-               op->newdata ( conn, ( void * ) uip_appdata, uip_len );
-       if ( uip_rexmit() || uip_newdata() || uip_acked() ||
-            uip_connected() || uip_poll() )
-               op->senddata ( conn );
-}
-
-void uip_udp_appcall ( void ) {
-}
-
-static void init_tcpip ( void ) {
-       uip_init();
-       uip_arp_init();
-}
-
-#define UIP_HLEN ( 40 + UIP_LLH_LEN )
-
-static void uip_transmit ( void ) {
-       uip_arp_out();
-       if ( uip_len > UIP_HLEN ) {
-               memcpy ( uip_buf + UIP_HLEN, ( void * ) uip_appdata,
-                        uip_len - UIP_HLEN );
-       }
-       netdev_transmit ( uip_buf, uip_len );
-       uip_len = 0;
-}
-
-static void run_tcpip ( void ) {
-       void *data;
-       size_t len;
-       uint16_t type;
-       int i;
-       
-       if ( netdev_poll ( 1, &data, &len ) ) {
-               /* We have data */
-               memcpy ( uip_buf, data, len );
-               uip_len = len;
-               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();
-       } else {
-               for ( i = 0 ; i < UIP_CONNS ; i++ ) {
-                       uip_periodic ( i );
-                       if ( uip_len > 0 )
-                               uip_transmit();
-               }
-       }
-}
-
 /*****************************************************************************
  *
  * "Hello world" protocol tester