(Redoing check-in lost by SourceForge's failure.)
[people/xl0/gpxe.git] / src / proto / tcp.c
1 #include <string.h>
2 #include <assert.h>
3 #include <byteswap.h>
4 #include <gpxe/tcp.h>
5 #include "uip/uip.h"
6
7 /** @file
8  *
9  * TCP protocol
10  *
11  * The gPXE TCP stack is currently implemented on top of the uIP
12  * protocol stack.  This file provides wrappers around uIP so that
13  * higher-level protocol implementations do not need to talk directly
14  * to uIP (which has a somewhat baroque API).
15  *
16  * Basic operation is to create a #tcp_connection structure, call
17  * tcp_connect() and then call run_tcpip() in a loop until the
18  * operation has completed.  The TCP stack will call the various
19  * methods defined in the #tcp_operations structure in order to send
20  * and receive data.
21  *
22  * See hello.c for a trivial example of a TCP protocol using this
23  * API.
24  *
25  */
26
27 /**
28  * TCP transmit buffer
29  *
30  * When a tcp_operations::senddata() method is called, it is
31  * guaranteed to be able to use this buffer as temporary space for
32  * constructing the data to be sent.  For example, code such as
33  *
34  * @code
35  *
36  *     static void my_senddata ( struct tcp_connection *conn ) {
37  *         int len;
38  *
39  *         len = snprintf ( tcp_buffer, tcp_buflen, "FETCH %s\r\n", filename );
40  *         tcp_send ( conn, tcp_buffer + already_sent, len - already_sent );
41  *     }
42  *
43  * @endcode
44  *
45  * is allowed, and is probably the best way to deal with
46  * variably-sized data.
47  *
48  * Note that you cannot use this simple mechanism if you want to be
49  * able to construct single data blocks of more than #tcp_buflen
50  * bytes.
51  */
52 void *tcp_buffer = uip_buf + ( 40 + UIP_LLH_LEN );
53
54 /** Size of #tcp_buffer */
55 size_t tcp_buflen = UIP_BUFSIZE - ( 40 + UIP_LLH_LEN );
56
57 /**
58  * Open a TCP connection
59  *
60  * @v conn      TCP connection
61  * @ret 0       Success
62  * @ret <0      Failure
63  * 
64  * This sets up a new TCP connection to the remote host specified in
65  * tcp_connection::sin.  The actual SYN packet will not be sent out
66  * until run_tcpip() is called for the first time.
67  *
68  * @todo Use linked lists instead of a static buffer, and thereby
69  *       remove the only potential failure case, giving this function
70  *       a void return type.
71  */
72 int tcp_connect ( struct tcp_connection *conn ) {
73         struct uip_conn *uip_conn;
74         u16_t ipaddr[2];
75
76         assert ( conn->sin.sin_addr.s_addr != 0 );
77         assert ( conn->sin.sin_port != 0 );
78         assert ( conn->tcp_op != NULL );
79         assert ( sizeof ( uip_conn->appstate ) == sizeof ( conn ) );
80
81         * ( ( uint32_t * ) ipaddr ) = conn->sin.sin_addr.s_addr;
82         uip_conn = uip_connect ( ipaddr, conn->sin.sin_port );
83         if ( ! uip_conn )
84                 return -1;
85
86         *( ( void ** ) uip_conn->appstate ) = conn;
87         return 0;
88 }
89
90 /**
91  * Send data via a TCP connection
92  *
93  * @v conn      TCP connection
94  * @v data      Data to send
95  * @v len       Length of data
96  *
97  * Data will be automatically limited to the current TCP window size.
98  *
99  * If retransmission is required, the connection's
100  * tcp_operations::senddata() method will be called again in order to
101  * regenerate the data.
102  */
103 void tcp_send ( struct tcp_connection *conn __unused,
104                 const void *data, size_t len ) {
105
106         assert ( conn = *( ( void ** ) uip_conn->appstate ) );
107
108         if ( len > tcp_buflen )
109                 len = tcp_buflen;
110         memmove ( tcp_buffer, data, len );
111
112         uip_send ( tcp_buffer, len );
113 }
114
115 /**
116  * Close a TCP connection
117  *
118  * @v conn      TCP connection
119  */
120 void tcp_close ( struct tcp_connection *conn __unused ) {
121         assert ( conn = *( ( void ** ) uip_conn->appstate ) );
122         uip_close();
123 }
124
125 /**
126  * uIP TCP application call interface
127  *
128  * This is the entry point of gPXE from the point of view of the uIP
129  * protocol stack.  This function calls the appropriate methods from
130  * the connection's @tcp_operations table in order to process received
131  * data, transmit new data etc.
132  */
133 void uip_tcp_appcall ( void ) {
134         struct tcp_connection *conn = *( ( void ** ) uip_conn->appstate );
135         struct tcp_operations *op = conn->tcp_op;
136
137         assert ( conn->tcp_op->closed != NULL );
138         assert ( conn->tcp_op->connected != NULL );
139         assert ( conn->tcp_op->acked != NULL );
140         assert ( conn->tcp_op->newdata != NULL );
141         assert ( conn->tcp_op->senddata != NULL );
142
143         if ( uip_aborted() && op->aborted ) /* optional method */
144                 op->aborted ( conn );
145         if ( uip_timedout() && op->timedout ) /* optional method */
146                 op->timedout ( conn );
147         if ( uip_closed() && op->closed ) /* optional method */
148                 op->closed ( conn );
149         if ( uip_connected() )
150                 op->connected ( conn );
151         if ( uip_acked() )
152                 op->acked ( conn, uip_conn->len );
153         if ( uip_newdata() )
154                 op->newdata ( conn, ( void * ) uip_appdata, uip_len );
155         if ( uip_rexmit() || uip_newdata() || uip_acked() ||
156              uip_connected() || uip_poll() )
157                 op->senddata ( conn );
158 }
159
160 /* Present here to allow everything to link.  Will go into separate
161  * udp.c file
162  */
163 void uip_udp_appcall ( void ) {
164 }