diff --git a/src/include/gpxe/ftp.h b/src/include/gpxe/ftp.h index f2db5a13..6063abe9 100644 --- a/src/include/gpxe/ftp.h +++ b/src/include/gpxe/ftp.h @@ -10,6 +10,12 @@ #include #include +/** + * FTP states + * + * These @b must be sequential, i.e. a successful FTP session must + * pass through each of these states in order. + */ enum ftp_state { FTP_CONNECT = 0, FTP_USER, diff --git a/src/include/gpxe/tcp.h b/src/include/gpxe/tcp.h index 9b7ecc80..699512bd 100644 --- a/src/include/gpxe/tcp.h +++ b/src/include/gpxe/tcp.h @@ -19,28 +19,24 @@ struct tcp_connection; * */ struct tcp_operations { - /** - * Connection aborted (RST received) + /* + * Connection closed * * @v conn TCP connection - */ - void ( * aborted ) ( struct tcp_connection *conn ); - /** - * Connection timed out + * @v status Error code, if any * - * @v conn TCP connection - */ - void ( * timedout ) ( struct tcp_connection *conn ); - /** - * Connection aborted (FIN received) - * - * @v conn TCP connection + * This is called when the connection is closed for any + * reason, including timeouts or aborts. The status code + * contains the negative error number, if the closure is due + * to an error. * * Note that acked() and newdata() may be called after * closed(), if the packet containing the FIN also - * acknowledged data or contained new data. + * acknowledged data or contained new data. Note also that + * connected() may not have been called before closed(), if + * the close is due to an error. */ - void ( * closed ) ( struct tcp_connection *conn ); + void ( * closed ) ( struct tcp_connection *conn, int status ); /** * Connection established (SYNACK received) * diff --git a/src/net/tcp.c b/src/net/tcp.c index 572e5a4f..ea26f019 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -131,18 +132,14 @@ 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 ) - op->aborted ( conn ); - if ( uip_timedout() && op->timedout ) - op->timedout ( conn ); - if ( uip_closed() && op->closed ) - op->closed ( conn ); + if ( op->closed ) { + if ( uip_aborted() ) + op->closed ( conn, -ECONNABORTED ); + if ( uip_timedout() ) + op->closed ( conn, -ETIMEDOUT ); + if ( uip_closed() ) + op->closed ( conn, 0 ); + } if ( uip_connected() && op->connected ) op->connected ( conn ); if ( uip_acked() && op->acked ) diff --git a/src/net/tcp/ftp.c b/src/net/tcp/ftp.c index dae1714a..46119cd7 100644 --- a/src/net/tcp/ftp.c +++ b/src/net/tcp/ftp.c @@ -12,6 +12,12 @@ * */ +/***************************************************************************** + * + * FTP control channel + * + */ + /** An FTP control channel string */ struct ftp_string { /** String format */ @@ -25,8 +31,18 @@ struct ftp_string { off_t data_offset; }; -#define ftp_string_offset( fieldname ) \ - offsetof ( struct ftp_request, fieldname ) +/** FTP control channel strings */ +static const struct ftp_string ftp_strings[] = { + [FTP_CONNECT] = { "", 0 }, + [FTP_USER] = { "USER anonymous\r\n", 0 }, + [FTP_PASS] = { "PASS etherboot@etherboot.org\r\n", 0 }, + [FTP_TYPE] = { "TYPE I\r\n", 0 }, + [FTP_PASV] = { "PASV\r\n", 0 }, + [FTP_RETR] = { "RETR %s\r\n", + offsetof ( struct ftp_request, filename ) }, + [FTP_QUIT] = { "QUIT\r\n", 0 }, + [FTP_DONE] = { "", 0 }, +}; /** * Get data associated with an FTP control channel string @@ -40,23 +56,23 @@ static inline const void * ftp_string_data ( struct ftp_request *ftp, return * ( ( void ** ) ( ( ( void * ) ftp ) + data_offset ) ); } -/** FTP control channel strings */ -const struct ftp_string ftp_strings[] = { - [FTP_CONNECT] = { "", 0 }, - [FTP_USER] = { "USER anonymous\r\n", 0 }, - [FTP_PASS] = { "PASS etherboot@etherboot.org\r\n", 0 }, - [FTP_TYPE] = { "TYPE I\r\n", 0 }, - [FTP_PASV] = { "PASV\r\n", 0 }, - [FTP_RETR] = { "RETR %s\r\n", ftp_string_offset ( filename ) }, - [FTP_QUIT] = { "QUIT\r\n", 0 }, - [FTP_DONE] = { "", 0 }, -}; - -static inline struct ftp_request * -tcp_to_ftp ( struct tcp_connection *conn ) { +/** + * Get FTP request from control TCP connection + * + * @v conn TCP connection + * @ret ftp FTP request + */ +static inline struct ftp_request * tcp_to_ftp ( struct tcp_connection *conn ) { return container_of ( conn, struct ftp_request, tcp ); } +/** + * Mark FTP request as complete + * + * @v ftp FTP request + * @v complete Completion indicator + * + */ static void ftp_complete ( struct ftp_request *ftp, int complete ) { ftp->complete = complete; tcp_close ( &ftp->tcp_data ); @@ -87,7 +103,7 @@ static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) { } /** - * Handle a response from an FTP server + * Handle an FTP control channel response * * @v ftp FTP request * @@ -132,6 +148,16 @@ static void ftp_reply ( struct ftp_request *ftp ) { ftp_complete ( ftp, -EPROTO ); } +/** + * Handle new data arriving on FTP control channel + * + * @v conn TCP connection + * @v data New data + * @v len Length of new data + * + * Data is collected until a complete line is received, at which point + * its information is passed to ftp_reply(). + */ static void ftp_newdata ( struct tcp_connection *conn, void *data, size_t len ) { struct ftp_request *ftp = tcp_to_ftp ( conn ); @@ -178,6 +204,11 @@ static void ftp_newdata ( struct tcp_connection *conn, ftp->recvsize = recvsize; } +/** + * Handle acknowledgement of data sent on FTP control channel + * + * @v conn TCP connection + */ static void ftp_acked ( struct tcp_connection *conn, size_t len ) { struct ftp_request *ftp = tcp_to_ftp ( conn ); @@ -185,6 +216,11 @@ static void ftp_acked ( struct tcp_connection *conn, size_t len ) { ftp->already_sent += len; } +/** + * Construct data to send on FTP control channel + * + * @v conn TCP connection + */ static void ftp_senddata ( struct tcp_connection *conn ) { struct ftp_request *ftp = tcp_to_ftp ( conn ); const struct ftp_string *string; @@ -200,50 +236,72 @@ static void ftp_senddata ( struct tcp_connection *conn ) { len - ftp->already_sent ); } -static void ftp_aborted ( struct tcp_connection *conn ) { +/** + * Handle control channel being closed + * + * @v conn TCP connection + * + * When the control channel is closed, the data channel must also be + * closed, if it is currently open. + */ +static void ftp_closed ( struct tcp_connection *conn, int status ) { struct ftp_request *ftp = tcp_to_ftp ( conn ); - ftp_complete ( ftp, -ECONNABORTED ); -} - -static void ftp_timedout ( struct tcp_connection *conn ) { - struct ftp_request *ftp = tcp_to_ftp ( conn ); - - ftp_complete ( ftp, -ETIMEDOUT ); -} - -static void ftp_closed ( struct tcp_connection *conn ) { - struct ftp_request *ftp = tcp_to_ftp ( conn ); - - ftp_complete ( ftp, 1 ); + ftp_complete ( ftp, status ? status : 1 ); } +/** FTP control channel operations */ static struct tcp_operations ftp_tcp_operations = { - .aborted = ftp_aborted, - .timedout = ftp_timedout, .closed = ftp_closed, .acked = ftp_acked, .newdata = ftp_newdata, .senddata = ftp_senddata, }; +/***************************************************************************** + * + * FTP control channel + * + */ + +/** + * Get FTP request from data TCP connection + * + * @v conn TCP connection + * @ret ftp FTP request + */ static inline struct ftp_request * tcp_to_ftp_data ( struct tcp_connection *conn ) { return container_of ( conn, struct ftp_request, tcp_data ); } -static void ftp_data_aborted ( struct tcp_connection *conn ) { +/** + * Handle data channel being closed + * + * @v conn TCP connection + * + * When the data channel is closed, the control channel should be left + * alone; the server will send a completion message via the control + * channel which we'll pick up. + * + * If the data channel is closed due to an error, we abort the request. + */ +static void ftp_data_closed ( struct tcp_connection *conn, int status ) { struct ftp_request *ftp = tcp_to_ftp_data ( conn ); - ftp_complete ( ftp, -ECONNABORTED ); -} - -static void ftp_data_timedout ( struct tcp_connection *conn ) { - struct ftp_request *ftp = tcp_to_ftp_data ( conn ); - - ftp_complete ( ftp, -ETIMEDOUT ); + if ( status ) + ftp_complete ( ftp, status ); } +/** + * Handle new data arriving on the FTP data channel + * + * @v conn TCP connection + * @v data New data + * @v len Length of new data + * + * Data is handed off to the callback registered in the FTP request. + */ static void ftp_data_newdata ( struct tcp_connection *conn, void *data, size_t len ) { struct ftp_request *ftp = tcp_to_ftp_data ( conn ); @@ -251,9 +309,9 @@ static void ftp_data_newdata ( struct tcp_connection *conn, ftp->callback ( data, len ); } +/** FTP data channel operations */ static struct tcp_operations ftp_data_tcp_operations = { - .aborted = ftp_data_aborted, - .timedout = ftp_data_timedout, + .closed = ftp_data_closed, .newdata = ftp_data_newdata, }; diff --git a/src/net/tcp/hello.c b/src/net/tcp/hello.c index 2407e686..baaf8c76 100644 --- a/src/net/tcp/hello.c +++ b/src/net/tcp/hello.c @@ -13,7 +13,7 @@ * message (hello_request::message). Any data received from the * server will be passed to the callback function, * hello_request::callback(), and once the connection has been closed, - * hello_request::complete will be set to 1. + * hello_request::complete will be set to a non-zero value. * * To use this code, do something like: * @@ -49,24 +49,10 @@ tcp_to_hello ( struct tcp_connection *conn ) { return container_of ( conn, struct hello_request, tcp ); } -static void hello_aborted ( struct tcp_connection *conn ) { +static void hello_closed ( struct tcp_connection *conn, int status ) { struct hello_request *hello = tcp_to_hello ( conn ); - printf ( "Connection aborted\n" ); - hello->complete = 1; -} - -static void hello_timedout ( struct tcp_connection *conn ) { - struct hello_request *hello = tcp_to_hello ( conn ); - - printf ( "Connection timed out\n" ); - hello->complete = 1; -} - -static void hello_closed ( struct tcp_connection *conn ) { - struct hello_request *hello = tcp_to_hello ( conn ); - - hello->complete = 1; + hello->complete = ( status ? status : 1 ); } static void hello_connected ( struct tcp_connection *conn ) { @@ -113,8 +99,6 @@ static void hello_senddata ( struct tcp_connection *conn ) { } static struct tcp_operations hello_tcp_operations = { - .aborted = hello_aborted, - .timedout = hello_timedout, .closed = hello_closed, .connected = hello_connected, .acked = hello_acked, diff --git a/src/proto/iscsi.c b/src/proto/iscsi.c index 1a808b00..f4fc91a7 100644 --- a/src/proto/iscsi.c +++ b/src/proto/iscsi.c @@ -251,17 +251,7 @@ tcp_to_iscsi ( struct tcp_connection *conn ) { return container_of ( conn, struct iscsi_session, tcp ); } -static void iscsi_aborted ( struct tcp_connection *conn ) { - struct iscsi_session *iscsi = tcp_to_iscsi ( conn ); - -} - -static void iscsi_timedout ( struct tcp_connection *conn ) { - struct iscsi_session *iscsi = tcp_to_iscsi ( conn ); - -} - -static void iscsi_closed ( struct tcp_connection *conn ) { +static void iscsi_closed ( struct tcp_connection *conn, int status ) { struct iscsi_session *iscsi = tcp_to_iscsi ( conn ); } @@ -523,8 +513,6 @@ static void iscsi_newdata ( struct tcp_connection *conn, void *data, /** iSCSI TCP operations */ static struct tcp_operations iscsi_tcp_operations = { - .aborted = iscsi_aborted, - .timedout = iscsi_timedout, .closed = iscsi_closed, .connected = iscsi_connected, .acked = iscsi_acked,