diff --git a/src/include/gpxe/ftp.h b/src/include/gpxe/ftp.h index 64e8d4e4..41eca8ca 100644 --- a/src/include/gpxe/ftp.h +++ b/src/include/gpxe/ftp.h @@ -9,7 +9,7 @@ #include #include -#include +#include struct buffer; @@ -57,10 +57,10 @@ struct ftp_request { char status_text[4]; /** Passive-mode parameters, as text */ char passive_text[24]; /* "aaa,bbb,ccc,ddd,eee,fff" */ - /** TCP application for the control channel */ - struct tcp_application tcp; - /** TCP application for the data channel */ - struct tcp_application tcp_data; + /** Stream application for the control channel */ + struct stream_application stream; + /** Stream application for the data channel */ + struct stream_application stream_data; }; extern int ftp_get ( struct uri *uri, struct buffer *buffer, diff --git a/src/include/gpxe/http.h b/src/include/gpxe/http.h index 3cfc888a..911a7485 100644 --- a/src/include/gpxe/http.h +++ b/src/include/gpxe/http.h @@ -8,7 +8,7 @@ */ #include -#include +#include #include #include #include @@ -43,8 +43,8 @@ struct http_request { /** Server address */ struct sockaddr server; - /** TCP application for this request */ - struct tcp_application tcp; + /** Stream application for this request */ + struct stream_application stream; /** Number of bytes already sent */ size_t tx_offset; /** RX state */ diff --git a/src/include/gpxe/iscsi.h b/src/include/gpxe/iscsi.h index 74560649..62b789c2 100644 --- a/src/include/gpxe/iscsi.h +++ b/src/include/gpxe/iscsi.h @@ -8,7 +8,7 @@ */ #include -#include +#include #include #include #include @@ -489,7 +489,7 @@ struct iscsi_session { /** Initiator IQN */ const char *initiator_iqn; /** Target address */ - struct sockaddr_tcpip target; + struct sockaddr target; /** Target IQN */ const char *target_iqn; /** Logical Unit Number (LUN) */ @@ -499,8 +499,8 @@ struct iscsi_session { /** Password */ const char *password; - /** TCP application for this session */ - struct tcp_application tcp; + /** Stream application for this session */ + struct stream_application stream; /** Session status * * This is the bitwise-OR of zero or more ISCSI_STATUS_XXX diff --git a/src/include/gpxe/stream.h b/src/include/gpxe/stream.h index 8d1c5f5d..545bfae7 100644 --- a/src/include/gpxe/stream.h +++ b/src/include/gpxe/stream.h @@ -125,7 +125,7 @@ struct stream_connection_operations { * application's senddata() method. */ int ( * send ) ( struct stream_connection *conn, - void *data, size_t len ); + const void *data, size_t len ); /** * Notify connection that data is available to send * @@ -167,6 +167,9 @@ struct stream_connection { struct stream_connection_operations *op; }; +extern void stream_associate ( struct stream_application *app, + struct stream_connection *conn ); + extern void stream_connected ( struct stream_connection *conn ); extern void stream_closed ( struct stream_connection *conn, int rc ); extern void stream_senddata ( struct stream_connection *conn, @@ -181,7 +184,7 @@ extern int stream_connect ( struct stream_application *app, struct sockaddr *peer ); extern void stream_close ( struct stream_application *app ); extern int stream_send ( struct stream_application *app, - void *data, size_t len ); + const void *data, size_t len ); extern int stream_kick ( struct stream_application *app ); #endif /* _GPXE_STREAM_H */ diff --git a/src/include/gpxe/tcp.h b/src/include/gpxe/tcp.h index f618ae32..576898e8 100644 --- a/src/include/gpxe/tcp.h +++ b/src/include/gpxe/tcp.h @@ -11,6 +11,7 @@ #include "latch.h" #include +#include /** * A TCP header @@ -252,105 +253,7 @@ struct tcp_mss_option { */ #define TCP_MSL ( 2 * 60 * TICKS_PER_SEC ) -struct tcp_application; - -/** - * TCP operations - * - */ -struct tcp_operations { - /* - * Connection closed - * - * @v app TCP application - * @v status Error code, if any - * - * 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. - * - * When closed() is called, the application no longer has a - * valid TCP connection. Note that connected() may not have - * been called before closed(), if the close is due to an - * error during connection setup. - */ - void ( * closed ) ( struct tcp_application *app, int status ); - /** - * Connection established - * - * @v app TCP application - */ - void ( * connected ) ( struct tcp_application *app ); - /** - * Data acknowledged - * - * @v app TCP application - * @v len Length of acknowledged data - * - * @c len is guaranteed to not exceed the outstanding amount - * of unacknowledged data. - */ - void ( * acked ) ( struct tcp_application *app, size_t len ); - /** - * New data received - * - * @v app TCP application - * @v data Data - * @v len Length of data - */ - void ( * newdata ) ( struct tcp_application *app, - void *data, size_t len ); - /** - * Transmit data - * - * @v app TCP application - * @v buf Temporary data buffer - * @v len Length of temporary data buffer - * - * 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. - * - * The application may use the temporary data buffer to - * construct the data to be sent. Note that merely filling - * the buffer will do nothing; the application must call - * tcp_send() in order to actually transmit the data. Use of - * the buffer is not compulsory; the application may call - * tcp_send() on any block of data. - */ - void ( * senddata ) ( struct tcp_application *app, void *buf, - size_t len ); -}; - -struct tcp_connection; - -/** - * A TCP application - * - * This data structure represents an application with a TCP connection. - */ -struct tcp_application { - /** TCP connection data - * - * This is filled in by TCP calls that initiate a connection, - * and reset to NULL when the connection is closed. - */ - struct tcp_connection *conn; - /** TCP connection operations table */ - struct tcp_operations *tcp_op; -}; - -extern int tcp_connect ( struct tcp_application *app, - struct sockaddr_tcpip *peer, - uint16_t local_port ); -extern void tcp_close ( struct tcp_application *app ); -extern int tcp_senddata ( struct tcp_application *app ); -extern int tcp_send ( struct tcp_application *app, const void *data, - size_t len ); +extern int tcp_open ( struct stream_application *app ); extern struct tcpip_protocol tcp_protocol; diff --git a/src/net/stream.c b/src/net/stream.c index 92e00d73..e255d850 100644 --- a/src/net/stream.c +++ b/src/net/stream.c @@ -25,8 +25,26 @@ #include #include #include +#include #include +/** + * Associate application with connection + * + * @v app Stream application + * @v conn Stream connection + */ +void stream_associate ( struct stream_application *app, + struct stream_connection *conn ) { + + DBGC ( app, "Stream %p associating with connection %p\n", app, conn ); + + assert ( conn->app == NULL ); + assert ( app->conn == NULL ); + conn->app = app; + app->conn = conn; +} + /** * Connection established * @@ -45,7 +63,8 @@ void stream_connected ( struct stream_connection *conn ) { } /* Hand off to application */ - app->op->connected ( app ); + if ( app->op->connected ) + app->op->connected ( app ); } /** @@ -66,8 +85,13 @@ void stream_closed ( struct stream_connection *conn, int rc ) { return; } + /* Disassociate application from connection */ + app->conn = NULL; + conn->app = NULL; + /* Hand off to application */ - app->op->closed ( app, rc ); + if ( app->op->closed ) + app->op->closed ( app, rc ); } /** @@ -91,7 +115,8 @@ void stream_senddata ( struct stream_connection *conn, } /* Hand off to application */ - app->op->senddata ( app, data, len ); + if ( app->op->senddata ) + app->op->senddata ( app, data, len ); } /** @@ -116,7 +141,8 @@ void stream_acked ( struct stream_connection *conn, size_t len ) { } /* Hand off to application */ - app->op->acked ( app, len ); + if ( app->op->acked ) + app->op->acked ( app, len ); } /** @@ -140,7 +166,8 @@ void stream_newdata ( struct stream_connection *conn, } /* Hand off to application */ - app->op->newdata ( app, data, len ); + if ( app->op->newdata ) + app->op->newdata ( app, data, len ); } /** @@ -163,6 +190,8 @@ int stream_bind ( struct stream_application *app, struct sockaddr *local ) { } /* Hand off to connection */ + if ( ! conn->op->bind ) + return -ENOTSUP; if ( ( rc = conn->op->bind ( conn, local ) ) != 0 ) { DBGC ( app, "Stream %p failed to bind: %s\n", app, strerror ( rc ) ); @@ -192,6 +221,8 @@ int stream_connect ( struct stream_application *app, struct sockaddr *peer ) { } /* Hand off to connection */ + if ( ! conn->op->connect ) + return -ENOTSUP; if ( ( rc = conn->op->connect ( conn, peer ) ) != 0 ) { DBGC ( app, "Stream %p failed to connect: %s\n", app, strerror ( rc ) ); @@ -217,7 +248,13 @@ void stream_close ( struct stream_application *app ) { return; } + /* Disassociate application from connection */ + app->conn = NULL; + conn->app = NULL; + /* Hand off to connection */ + if ( ! conn->op->close ) + return; conn->op->close ( conn ); } @@ -232,7 +269,8 @@ void stream_close ( struct stream_application *app ) { * This method should be called only in the context of an * application's senddata() method. */ -int stream_send ( struct stream_application *app, void *data, size_t len ) { +int stream_send ( struct stream_application *app, + const void *data, size_t len ) { struct stream_connection *conn = app->conn; int rc; @@ -245,6 +283,8 @@ int stream_send ( struct stream_application *app, void *data, size_t len ) { } /* Hand off to connection */ + if ( ! conn->op->send ) + return -ENOTSUP; if ( ( rc = conn->op->send ( conn, data, len ) ) != 0 ) { DBGC ( app, "Stream %p failed to send %zd bytes: %s\n", app, len, strerror ( rc ) ); @@ -273,6 +313,8 @@ int stream_kick ( struct stream_application *app ) { } /* Hand off to connection */ + if ( ! conn->op->send ) + return -ENOTSUP; if ( ( rc = conn->op->kick ( conn ) ) != 0 ) { DBGC ( app, "Stream %p failed to kick connection: %s\n", app, strerror ( rc ) ); diff --git a/src/net/tcp.c b/src/net/tcp.c index 2c2f0b33..056c3e3c 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -17,22 +18,22 @@ * */ +struct tcp_connection; static void tcp_expired ( struct retry_timer *timer, int over ); -static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ); +static int tcp_senddata_conn ( struct tcp_connection *tcp, int force_send ); +static struct stream_connection_operations tcp_op; /** * A TCP connection * * This data structure represents the internal state of a TCP - * connection. It is kept separate from @c struct @c tcp_application - * because the internal state is still required for some time after - * the application closes the connection. + * connection. */ struct tcp_connection { + /** The stream connection */ + struct stream_connection stream; /** List of TCP connections */ struct list_head list; - /** The associated TCP application, if any */ - struct tcp_application *app; /** Remote socket address */ struct sockaddr_tcpip peer; @@ -108,17 +109,17 @@ tcp_state ( int state ) { /** * Dump TCP state transition * - * @v conn TCP connection + * @v tcp TCP connection */ static inline __attribute__ (( always_inline )) void -tcp_dump_state ( struct tcp_connection *conn ) { +tcp_dump_state ( struct tcp_connection *tcp ) { - if ( conn->tcp_state != conn->prev_tcp_state ) { - DBGC ( conn, "TCP %p transitioned from %s to %s\n", conn, - tcp_state ( conn->prev_tcp_state ), - tcp_state ( conn->tcp_state ) ); + if ( tcp->tcp_state != tcp->prev_tcp_state ) { + DBGC ( tcp, "TCP %p transitioned from %s to %s\n", tcp, + tcp_state ( tcp->prev_tcp_state ), + tcp_state ( tcp->tcp_state ) ); } - conn->prev_tcp_state = conn->tcp_state; + tcp->prev_tcp_state = tcp->tcp_state; } /** @@ -127,17 +128,17 @@ tcp_dump_state ( struct tcp_connection *conn ) { * @v flags TCP flags */ static inline __attribute__ (( always_inline )) void -tcp_dump_flags ( struct tcp_connection *conn, unsigned int flags ) { +tcp_dump_flags ( struct tcp_connection *tcp, unsigned int flags ) { if ( flags & TCP_RST ) - DBGC ( conn, " RST" ); + DBGC ( tcp, " RST" ); if ( flags & TCP_SYN ) - DBGC ( conn, " SYN" ); + DBGC ( tcp, " SYN" ); if ( flags & TCP_PSH ) - DBGC ( conn, " PSH" ); + DBGC ( tcp, " PSH" ); if ( flags & TCP_FIN ) - DBGC ( conn, " FIN" ); + DBGC ( tcp, " FIN" ); if ( flags & TCP_ACK ) - DBGC ( conn, " ACK" ); + DBGC ( tcp, " ACK" ); } /** @@ -148,105 +149,68 @@ tcp_dump_flags ( struct tcp_connection *conn, unsigned int flags ) { * Allocates TCP connection and adds it to the TCP connection list. */ static struct tcp_connection * alloc_tcp ( void ) { - struct tcp_connection *conn; + struct tcp_connection *tcp; - conn = malloc ( sizeof ( *conn ) ); - if ( conn ) { - DBGC ( conn, "TCP %p allocated\n", conn ); - memset ( conn, 0, sizeof ( *conn ) ); - conn->tcp_state = conn->prev_tcp_state = TCP_CLOSED; - conn->snd_seq = random(); - conn->timer.expired = tcp_expired; - list_add ( &conn->list, &tcp_conns ); + tcp = malloc ( sizeof ( *tcp ) ); + if ( tcp ) { + DBGC ( tcp, "TCP %p allocated\n", tcp ); + memset ( tcp, 0, sizeof ( *tcp ) ); + tcp->tcp_state = tcp->prev_tcp_state = TCP_CLOSED; + tcp->snd_seq = random(); + tcp->timer.expired = tcp_expired; + tcp->stream.op = &tcp_op; + list_add ( &tcp->list, &tcp_conns ); } - return conn; + return tcp; } /** * Free TCP connection * - * @v conn TCP connection + * @v tcp TCP connection * * Removes connection from TCP connection list and frees the data * structure. */ -static void free_tcp ( struct tcp_connection *conn ) { +static void free_tcp ( struct tcp_connection *tcp ) { - assert ( conn ); - assert ( conn->tcp_state == TCP_CLOSED ); - assert ( conn->app == NULL ); + assert ( tcp ); + assert ( tcp->tcp_state == TCP_CLOSED ); - stop_timer ( &conn->timer ); - list_del ( &conn->list ); - free ( conn ); - DBGC ( conn, "TCP %p freed\n", conn ); -} - -/** - * Associate TCP connection with application - * - * @v conn TCP connection - * @v app TCP application - */ -static void tcp_associate ( struct tcp_connection *conn, - struct tcp_application *app ) { - assert ( conn->app == NULL ); - assert ( app->conn == NULL ); - conn->app = app; - app->conn = conn; - DBGC ( conn, "TCP %p associated with application %p\n", conn, app ); -} - -/** - * Disassociate TCP connection from application - * - * @v conn TCP connection - */ -static void tcp_disassociate ( struct tcp_connection *conn ) { - struct tcp_application *app = conn->app; - - if ( app ) { - assert ( app->conn == conn ); - conn->app = NULL; - app->conn = NULL; - DBGC ( conn, "TCP %p disassociated from application %p\n", - conn, app ); - } + stop_timer ( &tcp->timer ); + list_del ( &tcp->list ); + free ( tcp ); + DBGC ( tcp, "TCP %p freed\n", tcp ); } /** * Abort TCP connection * - * @v conn TCP connection + * @v tcp TCP connection * @v send_rst Send a RST after closing * @v rc Reason code */ -static void tcp_abort ( struct tcp_connection *conn, int send_rst, int rc ) { - struct tcp_application *app = conn->app; +static void tcp_abort ( struct tcp_connection *tcp, int send_rst, int rc ) { /* Transition to CLOSED */ - conn->tcp_state = TCP_CLOSED; - tcp_dump_state ( conn ); + tcp->tcp_state = TCP_CLOSED; + tcp_dump_state ( tcp ); /* Send RST if requested to do so */ if ( send_rst ) - tcp_senddata_conn ( conn, 1 ); + tcp_senddata_conn ( tcp, 1 ); - /* Break association between application and connection */ - tcp_disassociate ( conn ); + /* Close stream */ + stream_closed ( &tcp->stream, rc ); /* Free the connection */ - free_tcp ( conn ); - - /* Notify application */ - if ( app && app->tcp_op->closed ) - app->tcp_op->closed ( app, rc ); + free_tcp ( tcp ); } /** * Transmit any outstanding data * - * @v conn TCP connection + * @v tcp TCP connection * @v force_send Force sending of packet * * Transmits any outstanding data on the connection. If the @@ -257,8 +221,7 @@ static void tcp_abort ( struct tcp_connection *conn, int send_rst, int rc ) { * will have been started if necessary, and so the stack will * eventually attempt to retransmit the failed packet. */ -static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) { - struct tcp_application *app = conn->app; +static int tcp_senddata_conn ( struct tcp_connection *tcp, int force_send ) { struct pk_buff *pkb; struct tcp_header *tcphdr; struct tcp_mss_option *mssopt; @@ -272,7 +235,7 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) { /* Allocate space to the TX buffer */ pkb = alloc_pkb ( MAX_PKB_LEN ); if ( ! pkb ) { - DBGC ( conn, "TCP %p could not allocate data buffer\n", conn ); + DBGC ( tcp, "TCP %p could not allocate data buffer\n", tcp ); /* Start the retry timer so that we attempt to * retransmit this packet later. (Start it * unconditionally, since without a packet buffer we @@ -280,7 +243,7 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) { * be able to tell whether or not we have something * that actually needs to be retransmitted). */ - start_timer ( &conn->timer ); + start_timer ( &tcp->timer ); return -ENOMEM; } pkb_reserve ( pkb, MAX_HDR_LEN ); @@ -288,28 +251,28 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) { /* If we are connected, call the senddata() method, which may * call tcp_send() to queue up a data payload. */ - if ( TCP_CAN_SEND_DATA ( conn->tcp_state ) && - app && app->tcp_op->senddata ) { - conn->tx_pkb = pkb; - app->tcp_op->senddata ( app, pkb->data, pkb_tailroom ( pkb ) ); - conn->tx_pkb = NULL; + if ( TCP_CAN_SEND_DATA ( tcp->tcp_state ) ) { + tcp->tx_pkb = pkb; + stream_senddata ( &tcp->stream, pkb->data, + pkb_tailroom ( pkb ) ); + tcp->tx_pkb = NULL; } /* Truncate payload length to fit transmit window */ len = pkb_len ( pkb ); - if ( len > conn->snd_win ) - len = conn->snd_win; + if ( len > tcp->snd_win ) + len = tcp->snd_win; /* Calculate amount of sequence space that this transmission * consumes. (SYN or FIN consume one byte, and we can never * send both at once). */ seq_len = len; - flags = TCP_FLAGS_SENDING ( conn->tcp_state ); + flags = TCP_FLAGS_SENDING ( tcp->tcp_state ); assert ( ! ( ( flags & TCP_SYN ) && ( flags & TCP_FIN ) ) ); if ( flags & ( TCP_SYN | TCP_FIN ) ) seq_len++; - conn->snd_sent = seq_len; + tcp->snd_sent = seq_len; /* If we have nothing to transmit, drop the packet */ if ( ( seq_len == 0 ) && ! force_send ) { @@ -322,7 +285,7 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) { * retransmission timer. */ if ( seq_len ) - start_timer ( &conn->timer ); + start_timer ( &tcp->timer ); /* Estimate window size */ window = freemem; @@ -340,25 +303,25 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) { } tcphdr = pkb_push ( pkb, sizeof ( *tcphdr ) ); memset ( tcphdr, 0, sizeof ( *tcphdr ) ); - tcphdr->src = conn->local_port; - tcphdr->dest = conn->peer.st_port; - tcphdr->seq = htonl ( conn->snd_seq ); - tcphdr->ack = htonl ( conn->rcv_ack ); + tcphdr->src = tcp->local_port; + tcphdr->dest = tcp->peer.st_port; + tcphdr->seq = htonl ( tcp->snd_seq ); + tcphdr->ack = htonl ( tcp->rcv_ack ); tcphdr->hlen = ( ( payload - pkb->data ) << 2 ); tcphdr->flags = flags; tcphdr->win = htons ( window ); tcphdr->csum = tcpip_chksum ( pkb->data, pkb_len ( pkb ) ); /* Dump header */ - DBGC ( conn, "TCP %p TX %d->%d %08lx..%08lx %08lx %4zd", - conn, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ), + DBGC ( tcp, "TCP %p TX %d->%d %08lx..%08lx %08lx %4zd", + tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ), ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) + seq_len ), ntohl ( tcphdr->ack ), len ); - tcp_dump_flags ( conn, tcphdr->flags ); - DBGC ( conn, "\n" ); + tcp_dump_flags ( tcp, tcphdr->flags ); + DBGC ( tcp, "\n" ); /* Transmit packet */ - rc = tcpip_tx ( pkb, &tcp_protocol, &conn->peer, NULL, &tcphdr->csum ); + rc = tcpip_tx ( pkb, &tcp_protocol, &tcp->peer, NULL, &tcphdr->csum ); /* If we got -ENETUNREACH, kill the connection immediately * because there is no point retrying. This isn't strictly @@ -367,11 +330,11 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) { * RST packets transmitted on connection abort, to avoid a * potential infinite loop. */ - if ( ( ! ( conn->tcp_state & TCP_STATE_SENT ( TCP_RST ) ) ) && + if ( ( ! ( tcp->tcp_state & TCP_STATE_SENT ( TCP_RST ) ) ) && ( rc == -ENETUNREACH ) ) { - DBGC ( conn, "TCP %p aborting after TX failed: %s\n", - conn, strerror ( rc ) ); - tcp_abort ( conn, 0, rc ); + DBGC ( tcp, "TCP %p aborting after TX failed: %s\n", + tcp, strerror ( rc ) ); + tcp_abort ( tcp, 0, rc ); } return rc; @@ -380,28 +343,23 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) { /** * Transmit any outstanding data * - * @v conn TCP connection + * @v stream TCP stream * * This function allocates space to the transmit buffer and invokes * the senddata() callback function, to allow the application to * transmit new data. */ -int tcp_senddata ( struct tcp_application *app ) { - struct tcp_connection *conn = app->conn; +static int tcp_kick ( struct stream_connection *stream ) { + struct tcp_connection *tcp = + container_of ( stream, struct tcp_connection, stream ); - /* Check connection actually exists */ - if ( ! conn ) { - DBG ( "TCP app %p has no connection\n", app ); - return -ENOTCONN; - } - - return tcp_senddata_conn ( conn, 0 ); + return tcp_senddata_conn ( tcp, 0 ); } /** * Transmit data * - * @v app TCP application + * @v stream TCP stream * @v data Data to be sent * @v len Length of the data * @ret rc Return status code @@ -410,21 +368,17 @@ int tcp_senddata ( struct tcp_application *app ) { * can be called only in the context of an application's senddata() * method. */ -int tcp_send ( struct tcp_application *app, const void *data, size_t len ) { - struct tcp_connection *conn = app->conn; +static int tcp_send ( struct stream_connection *stream, + const void *data, size_t len ) { + struct tcp_connection *tcp = + container_of ( stream, struct tcp_connection, stream ); struct pk_buff *pkb; - /* Check connection actually exists */ - if ( ! conn ) { - DBG ( "TCP app %p has no connection\n", app ); - return -ENOTCONN; - } - /* Check that we have a packet buffer to fill */ - pkb = conn->tx_pkb; + pkb = tcp->tx_pkb; if ( ! pkb ) { - DBG ( "TCP app %p tried to send data outside of the " - "senddata() method\n", app ); + DBGC ( tcp, "TCP %p tried to send data outside of the " + "senddata() method\n", tcp ); return -EINVAL; } @@ -445,30 +399,30 @@ int tcp_send ( struct tcp_application *app, const void *data, size_t len ) { * @v over Failure indicator */ static void tcp_expired ( struct retry_timer *timer, int over ) { - struct tcp_connection *conn = + struct tcp_connection *tcp = container_of ( timer, struct tcp_connection, timer ); - int graceful_close = TCP_CLOSED_GRACEFULLY ( conn->tcp_state ); + int graceful_close = TCP_CLOSED_GRACEFULLY ( tcp->tcp_state ); - DBGC ( conn, "TCP %p timer %s in %s\n", conn, - ( over ? "expired" : "fired" ), tcp_state ( conn->tcp_state ) ); + DBGC ( tcp, "TCP %p timer %s in %s\n", tcp, + ( over ? "expired" : "fired" ), tcp_state ( tcp->tcp_state ) ); - assert ( ( conn->tcp_state == TCP_SYN_SENT ) || - ( conn->tcp_state == TCP_SYN_RCVD ) || - ( conn->tcp_state == TCP_ESTABLISHED ) || - ( conn->tcp_state == TCP_FIN_WAIT_1 ) || - ( conn->tcp_state == TCP_TIME_WAIT ) || - ( conn->tcp_state == TCP_CLOSE_WAIT ) || - ( conn->tcp_state == TCP_CLOSING_OR_LAST_ACK ) ); + assert ( ( tcp->tcp_state == TCP_SYN_SENT ) || + ( tcp->tcp_state == TCP_SYN_RCVD ) || + ( tcp->tcp_state == TCP_ESTABLISHED ) || + ( tcp->tcp_state == TCP_FIN_WAIT_1 ) || + ( tcp->tcp_state == TCP_TIME_WAIT ) || + ( tcp->tcp_state == TCP_CLOSE_WAIT ) || + ( tcp->tcp_state == TCP_CLOSING_OR_LAST_ACK ) ); if ( over || graceful_close ) { /* If we have finally timed out and given up, or if * this is the result of a graceful close, terminate * the connection */ - tcp_abort ( conn, 1, -ETIMEDOUT ); + tcp_abort ( tcp, 1, -ETIMEDOUT ); } else { /* Otherwise, retransmit the packet */ - tcp_senddata_conn ( conn, 0 ); + tcp_senddata_conn ( tcp, 0 ); } } @@ -478,7 +432,7 @@ static void tcp_expired ( struct retry_timer *timer, int over ) { * @v in_tcphdr TCP header of incoming packet * @ret rc Return status code */ -static int tcp_send_reset ( struct tcp_connection *conn, +static int tcp_send_reset ( struct tcp_connection *tcp, struct tcp_header *in_tcphdr ) { struct pk_buff *pkb; struct tcp_header *tcphdr; @@ -486,7 +440,7 @@ static int tcp_send_reset ( struct tcp_connection *conn, /* Allocate space for dataless TX buffer */ pkb = alloc_pkb ( MAX_HDR_LEN ); if ( ! pkb ) { - DBGC ( conn, "TCP %p could not allocate data buffer\n", conn ); + DBGC ( tcp, "TCP %p could not allocate data buffer\n", tcp ); return -ENOMEM; } pkb_reserve ( pkb, MAX_HDR_LEN ); @@ -504,15 +458,15 @@ static int tcp_send_reset ( struct tcp_connection *conn, tcphdr->csum = tcpip_chksum ( pkb->data, pkb_len ( pkb ) ); /* Dump header */ - DBGC ( conn, "TCP %p TX %d->%d %08lx..%08lx %08lx %4zd", - conn, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ), + DBGC ( tcp, "TCP %p TX %d->%d %08lx..%08lx %08lx %4zd", + tcp, ntohs ( tcphdr->src ), ntohs ( tcphdr->dest ), ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) ), ntohl ( tcphdr->ack ), 0 ); - tcp_dump_flags ( conn, tcphdr->flags ); - DBGC ( conn, "\n" ); + tcp_dump_flags ( tcp, tcphdr->flags ); + DBGC ( tcp, "\n" ); /* Transmit packet */ - return tcpip_tx ( pkb, &tcp_protocol, &conn->peer, + return tcpip_tx ( pkb, &tcp_protocol, &tcp->peer, NULL, &tcphdr->csum ); } @@ -520,14 +474,14 @@ static int tcp_send_reset ( struct tcp_connection *conn, * Identify TCP connection by local port number * * @v local_port Local port (in network-endian order) - * @ret conn TCP connection, or NULL + * @ret tcp TCP connection, or NULL */ static struct tcp_connection * tcp_demux ( uint16_t local_port ) { - struct tcp_connection *conn; + struct tcp_connection *tcp; - list_for_each_entry ( conn, &tcp_conns, list ) { - if ( conn->local_port == local_port ) - return conn; + list_for_each_entry ( tcp, &tcp_conns, list ) { + if ( tcp->local_port == local_port ) + return tcp; } return NULL; } @@ -535,32 +489,30 @@ static struct tcp_connection * tcp_demux ( uint16_t local_port ) { /** * Handle TCP received SYN * - * @v conn TCP connection + * @v tcp TCP connection * @v seq SEQ value (in host-endian order) * @ret rc Return status code */ -static int tcp_rx_syn ( struct tcp_connection *conn, uint32_t seq ) { - struct tcp_application *app = conn->app; +static int tcp_rx_syn ( struct tcp_connection *tcp, uint32_t seq ) { /* Synchronise sequence numbers on first SYN */ - if ( ! ( conn->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) - conn->rcv_ack = seq; + if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) + tcp->rcv_ack = seq; /* Ignore duplicate SYN */ - if ( ( conn->rcv_ack - seq ) > 0 ) + if ( ( tcp->rcv_ack - seq ) > 0 ) return 0; /* Mark SYN as received and start sending ACKs with each packet */ - conn->tcp_state |= ( TCP_STATE_SENT ( TCP_ACK ) | + tcp->tcp_state |= ( TCP_STATE_SENT ( TCP_ACK ) | TCP_STATE_RCVD ( TCP_SYN ) ); /* Acknowledge SYN */ - conn->rcv_ack++; + tcp->rcv_ack++; /* Notify application of established connection, if applicable */ - if ( ( conn->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) && - app && app->tcp_op->connected ) - app->tcp_op->connected ( app ); + if ( ( tcp->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) ) + stream_connected ( &tcp->stream ); return 0; } @@ -568,24 +520,23 @@ static int tcp_rx_syn ( struct tcp_connection *conn, uint32_t seq ) { /** * Handle TCP received ACK * - * @v conn TCP connection + * @v tcp TCP connection * @v ack ACK value (in host-endian order) * @v win WIN value (in host-endian order) * @ret rc Return status code */ -static int tcp_rx_ack ( struct tcp_connection *conn, uint32_t ack, +static int tcp_rx_ack ( struct tcp_connection *tcp, uint32_t ack, uint32_t win ) { - struct tcp_application *app = conn->app; - size_t ack_len = ( ack - conn->snd_seq ); + size_t ack_len = ( ack - tcp->snd_seq ); size_t len; unsigned int acked_flags = 0; /* Ignore duplicate or out-of-range ACK */ - if ( ack_len > conn->snd_sent ) { - DBGC ( conn, "TCP %p received ACK for [%08lx,%08lx), " - "sent only [%08lx,%08lx)\n", conn, conn->snd_seq, - ( conn->snd_seq + ack_len ), conn->snd_seq, - ( conn->snd_seq + conn->snd_sent ) ); + if ( ack_len > tcp->snd_sent ) { + DBGC ( tcp, "TCP %p received ACK for [%08lx,%08lx), " + "sent only [%08lx,%08lx)\n", tcp, tcp->snd_seq, + ( tcp->snd_seq + ack_len ), tcp->snd_seq, + ( tcp->snd_seq + tcp->snd_sent ) ); return -EINVAL; } @@ -595,34 +546,34 @@ static int tcp_rx_ack ( struct tcp_connection *conn, uint32_t ack, * the last outstanding sequence point.) */ len = ack_len; - if ( ack_len == conn->snd_sent ) { - acked_flags = ( TCP_FLAGS_SENDING ( conn->tcp_state ) & + if ( ack_len == tcp->snd_sent ) { + acked_flags = ( TCP_FLAGS_SENDING ( tcp->tcp_state ) & ( TCP_SYN | TCP_FIN ) ); if ( acked_flags ) len--; } /* Update SEQ and sent counters, and window size */ - conn->snd_seq = ack; - conn->snd_sent = 0; - conn->snd_win = win; + tcp->snd_seq = ack; + tcp->snd_sent = 0; + tcp->snd_win = win; /* Stop the retransmission timer */ - stop_timer ( &conn->timer ); + stop_timer ( &tcp->timer ); /* Notify application of acknowledged data, if any */ - if ( len && app && app->tcp_op->acked ) - app->tcp_op->acked ( app, len ); + if ( len ) + stream_acked ( &tcp->stream, len ); /* Mark SYN/FIN as acknowledged if applicable. */ if ( acked_flags ) - conn->tcp_state |= TCP_STATE_ACKED ( acked_flags ); + tcp->tcp_state |= TCP_STATE_ACKED ( acked_flags ); /* Notify application of established connection, if applicable */ if ( ( acked_flags & TCP_SYN ) && - ( conn->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) && - app && app->tcp_op->connected ) - app->tcp_op->connected ( app ); + ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) { + stream_connected ( &tcp->stream ); + } return 0; } @@ -630,30 +581,28 @@ static int tcp_rx_ack ( struct tcp_connection *conn, uint32_t ack, /** * Handle TCP received data * - * @v conn TCP connection + * @v tcp TCP connection * @v seq SEQ value (in host-endian order) * @v data Data buffer * @v len Length of data buffer * @ret rc Return status code */ -static int tcp_rx_data ( struct tcp_connection *conn, uint32_t seq, +static int tcp_rx_data ( struct tcp_connection *tcp, uint32_t seq, void *data, size_t len ) { - struct tcp_application *app = conn->app; size_t already_rcvd; /* Ignore duplicate data */ - already_rcvd = ( conn->rcv_ack - seq ); + already_rcvd = ( tcp->rcv_ack - seq ); if ( already_rcvd >= len ) return 0; data += already_rcvd; len -= already_rcvd; /* Acknowledge new data */ - conn->rcv_ack += len; + tcp->rcv_ack += len; /* Notify application */ - if ( app && app->tcp_op->newdata ) - app->tcp_op->newdata ( app, data, len ); + stream_newdata ( &tcp->stream, data, len ); return 0; } @@ -661,28 +610,23 @@ static int tcp_rx_data ( struct tcp_connection *conn, uint32_t seq, /** * Handle TCP received FIN * - * @v conn TCP connection + * @v tcp TCP connection * @v seq SEQ value (in host-endian order) * @ret rc Return status code */ -static int tcp_rx_fin ( struct tcp_connection *conn, uint32_t seq ) { - struct tcp_application *app = conn->app; +static int tcp_rx_fin ( struct tcp_connection *tcp, uint32_t seq ) { /* Ignore duplicate FIN */ - if ( ( conn->rcv_ack - seq ) > 0 ) + if ( ( tcp->rcv_ack - seq ) > 0 ) return 0; /* Mark FIN as received, acknowledge it, and send our own FIN */ - conn->tcp_state |= ( TCP_STATE_RCVD ( TCP_FIN ) | + tcp->tcp_state |= ( TCP_STATE_RCVD ( TCP_FIN ) | TCP_STATE_SENT ( TCP_FIN ) ); - conn->rcv_ack++; + tcp->rcv_ack++; - /* Break association with application */ - tcp_disassociate ( conn ); - - /* Notify application */ - if ( app && app->tcp_op->closed ) - app->tcp_op->closed ( app, 0 ); + /* Close stream */ + stream_closed ( &tcp->stream, 0 ); return 0; } @@ -690,27 +634,27 @@ static int tcp_rx_fin ( struct tcp_connection *conn, uint32_t seq ) { /** * Handle TCP received RST * - * @v conn TCP connection + * @v tcp TCP connection * @v seq SEQ value (in host-endian order) * @ret rc Return status code */ -static int tcp_rx_rst ( struct tcp_connection *conn, uint32_t seq ) { +static int tcp_rx_rst ( struct tcp_connection *tcp, uint32_t seq ) { /* Accept RST only if it falls within the window. If we have * not yet received a SYN, then we have no window to test * against, so fall back to checking that our SYN has been * ACKed. */ - if ( conn->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) { - if ( ( conn->rcv_ack - seq ) > 0 ) + if ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) { + if ( ( tcp->rcv_ack - seq ) > 0 ) return 0; } else { - if ( ! ( conn->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) ) + if ( ! ( tcp->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) ) return 0; } /* Abort connection without sending a RST */ - tcp_abort ( conn, 0, -ECONNRESET ); + tcp_abort ( tcp, 0, -ECONNRESET ); return -ECONNRESET; } @@ -729,7 +673,7 @@ static int tcp_rx ( struct pk_buff *pkb, struct sockaddr_tcpip *st_dest __unused, uint16_t pshdr_csum ) { struct tcp_header *tcphdr = pkb->data; - struct tcp_connection *conn; + struct tcp_connection *tcp; unsigned int hlen; uint16_t csum; uint32_t start_seq; @@ -770,7 +714,7 @@ static int tcp_rx ( struct pk_buff *pkb, } /* Parse parameters from header and strip header */ - conn = tcp_demux ( tcphdr->dest ); + tcp = tcp_demux ( tcphdr->dest ); start_seq = seq = ntohl ( tcphdr->seq ); ack = ntohl ( tcphdr->ack ); win = ntohs ( tcphdr->win ); @@ -779,65 +723,65 @@ static int tcp_rx ( struct pk_buff *pkb, len = pkb_len ( pkb ); /* Dump header */ - DBGC ( conn, "TCP %p RX %d<-%d %08lx %08lx..%08lx %4zd", - conn, ntohs ( tcphdr->dest ), ntohs ( tcphdr->src ), + DBGC ( tcp, "TCP %p RX %d<-%d %08lx %08lx..%08lx %4zd", + tcp, ntohs ( tcphdr->dest ), ntohs ( tcphdr->src ), ntohl ( tcphdr->ack ), ntohl ( tcphdr->seq ), ( ntohl ( tcphdr->seq ) + len + ( ( tcphdr->flags & ( TCP_SYN | TCP_FIN ) ) ? 1 : 0 ) ), len); - tcp_dump_flags ( conn, tcphdr->flags ); - DBGC ( conn, "\n" ); + tcp_dump_flags ( tcp, tcphdr->flags ); + DBGC ( tcp, "\n" ); /* If no connection was found, send RST */ - if ( ! conn ) { - tcp_send_reset ( conn, tcphdr ); + if ( ! tcp ) { + tcp_send_reset ( tcp, tcphdr ); rc = -ENOTCONN; goto done; } /* Handle ACK, if present */ if ( flags & TCP_ACK ) { - if ( ( rc = tcp_rx_ack ( conn, ack, win ) ) != 0 ) { - tcp_send_reset ( conn, tcphdr ); + if ( ( rc = tcp_rx_ack ( tcp, ack, win ) ) != 0 ) { + tcp_send_reset ( tcp, tcphdr ); goto done; } } /* Handle SYN, if present */ if ( flags & TCP_SYN ) { - tcp_rx_syn ( conn, seq ); + tcp_rx_syn ( tcp, seq ); seq++; } /* Handle RST, if present */ if ( flags & TCP_RST ) { - if ( ( rc = tcp_rx_rst ( conn, seq ) ) != 0 ) + if ( ( rc = tcp_rx_rst ( tcp, seq ) ) != 0 ) goto done; } /* Handle new data, if any */ - tcp_rx_data ( conn, seq, data, len ); + tcp_rx_data ( tcp, seq, data, len ); seq += len; /* Handle FIN, if present */ if ( flags & TCP_FIN ) { - tcp_rx_fin ( conn, seq ); + tcp_rx_fin ( tcp, seq ); seq++; } /* Dump out any state change as a result of the received packet */ - tcp_dump_state ( conn ); + tcp_dump_state ( tcp ); /* Send out any pending data. If peer is expecting an ACK for * this packet then force sending a reply. */ - tcp_senddata_conn ( conn, ( start_seq != seq ) ); + tcp_senddata_conn ( tcp, ( start_seq != seq ) ); /* If this packet was the last we expect to receive, set up * timer to expire and cause the connection to be freed. */ - if ( TCP_CLOSED_GRACEFULLY ( conn->tcp_state ) ) { - conn->timer.timeout = ( 2 * TCP_MSL ); - start_timer ( &conn->timer ); + if ( TCP_CLOSED_GRACEFULLY ( tcp->tcp_state ) ) { + tcp->timer.timeout = ( 2 * TCP_MSL ); + start_timer ( &tcp->timer ); } rc = 0; @@ -850,61 +794,136 @@ static int tcp_rx ( struct pk_buff *pkb, /** * Bind TCP connection to local port * - * @v conn TCP connection - * @v local_port Local port (in network byte order), or 0 + * @v stream TCP stream + * @v local Local address * @ret rc Return status code * - * This function adds the connection to the list of registered TCP - * connections. If the local port is 0, the connection is assigned an - * available port between 1024 and 65535. + * Only the port portion of the local address is used. If the local + * port is 0, the connection is assigned an available port between + * 1024 and 65535. */ -static int tcp_bind ( struct tcp_connection *conn, uint16_t local_port ) { +static int tcp_bind ( struct stream_connection *stream, + struct sockaddr *local ) { + struct tcp_connection *tcp = + container_of ( stream, struct tcp_connection, stream ); + struct sockaddr_tcpip *st = ( ( struct sockaddr_tcpip * ) local ); struct tcp_connection *existing; + struct sockaddr_tcpip try; static uint16_t try_port = 1024; + uint16_t local_port = st->st_port; /* If no port specified, find the first available port */ if ( ! local_port ) { for ( ; try_port ; try_port++ ) { if ( try_port < 1024 ) continue; - if ( tcp_bind ( conn, htons ( try_port ) ) == 0 ) + try.st_port = htons ( try_port ); + if ( tcp_bind ( stream, + ( struct sockaddr * ) &try ) == 0 ) { return 0; + } } - DBGC ( conn, "TCP %p could not bind: no free ports\n", conn ); + DBGC ( tcp, "TCP %p could not bind: no free ports\n", tcp ); return -EADDRINUSE; } /* Attempt bind to local port */ list_for_each_entry ( existing, &tcp_conns, list ) { if ( existing->local_port == local_port ) { - DBGC ( conn, "TCP %p could not bind: port %d in use\n", - conn, ntohs ( local_port ) ); + DBGC ( tcp, "TCP %p could not bind: port %d in use\n", + tcp, ntohs ( local_port ) ); return -EADDRINUSE; } } - conn->local_port = local_port; + tcp->local_port = local_port; - DBGC ( conn, "TCP %p bound to port %d\n", conn, ntohs ( local_port ) ); + DBGC ( tcp, "TCP %p bound to port %d\n", tcp, ntohs ( local_port ) ); return 0; } /** * Connect to a remote server * - * @v app TCP application + * @v stream TCP stream * @v peer Remote socket address - * @v local_port Local port number (in network byte order), or 0 * @ret rc Return status code * * This function initiates a TCP connection to the socket address specified in * peer. It sends a SYN packet to peer. When the connection is established, the * TCP stack calls the connected() callback function. */ -int tcp_connect ( struct tcp_application *app, struct sockaddr_tcpip *peer, - uint16_t local_port ) { - struct tcp_connection *conn; +static int tcp_connect ( struct stream_connection *stream, + struct sockaddr *peer ) { + struct tcp_connection *tcp = + container_of ( stream, struct tcp_connection, stream ); + struct sockaddr_tcpip *st = ( ( struct sockaddr_tcpip * ) peer ); + struct sockaddr_tcpip local; int rc; + /* Bind to local port if not already bound */ + if ( ! tcp->local_port ) { + local.st_port = 0; + if ( ( rc = tcp_bind ( stream, + ( struct sockaddr * ) &local ) ) != 0 ){ + return rc; + } + } + + /* Bind to peer */ + memcpy ( &tcp->peer, st, sizeof ( tcp->peer ) ); + + /* Transition to TCP_SYN_SENT and send the SYN */ + tcp->tcp_state = TCP_SYN_SENT; + tcp_dump_state ( tcp ); + tcp_senddata_conn ( tcp, 0 ); + + return 0; +} + +/** + * Close the connection + * + * @v stream TCP stream + * + * The TCP connection will persist until the state machine has + * returned to the TCP_CLOSED state. + */ +static void tcp_close ( struct stream_connection *stream ) { + struct tcp_connection *tcp = + container_of ( stream, struct tcp_connection, stream ); + + /* If we have not yet received a SYN (i.e. we are in CLOSED, + * LISTEN or SYN_SENT), just delete the connection + */ + if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) { + tcp->tcp_state = TCP_CLOSED; + tcp_dump_state ( tcp ); + free_tcp ( tcp ); + return; + } + + /* If we have not had our SYN acknowledged (i.e. we are in + * SYN_RCVD), pretend that it has been acknowledged so that we + * can send a FIN without breaking things. + */ + if ( ! ( tcp->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) ) + tcp_rx_ack ( tcp, ( tcp->snd_seq + 1 ), 0 ); + + /* Send a FIN to initiate the close */ + tcp->tcp_state |= TCP_STATE_SENT ( TCP_FIN ); + tcp_dump_state ( tcp ); + tcp_senddata_conn ( tcp, 0 ); +} + +/** + * Open TCP connection + * + * @v app Stream application + * @ret rc Return status code + */ +int tcp_open ( struct stream_application *app ) { + struct tcp_connection *tcp; + /* Application must not already have an open connection */ if ( app->conn ) { DBG ( "TCP app %p already open on %p\n", app, app->conn ); @@ -912,72 +931,26 @@ int tcp_connect ( struct tcp_application *app, struct sockaddr_tcpip *peer, } /* Allocate connection state storage and add to connection list */ - conn = alloc_tcp(); - if ( ! conn ) { + tcp = alloc_tcp(); + if ( ! tcp ) { DBG ( "TCP app %p could not allocate connection\n", app ); return -ENOMEM; } - /* Bind to peer and to local port */ - memcpy ( &conn->peer, peer, sizeof ( conn->peer ) ); - if ( ( rc = tcp_bind ( conn, local_port ) ) != 0 ) { - free_tcp ( conn ); - return rc; - } - - /* Associate with application */ - tcp_associate ( conn, app ); - - /* Transition to TCP_SYN_SENT and send the SYN */ - conn->tcp_state = TCP_SYN_SENT; - tcp_dump_state ( conn ); - tcp_senddata_conn ( conn, 0 ); + /* Associate application with connection */ + stream_associate ( app, &tcp->stream ); return 0; } -/** - * Close the connection - * - * @v app TCP application - * - * The association between the application and the TCP connection is - * immediately severed, and the TCP application data structure can be - * reused or freed immediately. The TCP connection will persist until - * the state machine has returned to the TCP_CLOSED state. - */ -void tcp_close ( struct tcp_application *app ) { - struct tcp_connection *conn = app->conn; - - /* If no connection exists, do nothing */ - if ( ! conn ) - return; - - /* Break association between application and connection */ - tcp_disassociate ( conn ); - - /* If we have not yet received a SYN (i.e. we are in CLOSED, - * LISTEN or SYN_SENT), just delete the connection - */ - if ( ! ( conn->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) { - conn->tcp_state = TCP_CLOSED; - tcp_dump_state ( conn ); - free_tcp ( conn ); - return; - } - - /* If we have not had our SYN acknowledged (i.e. we are in - * SYN_RCVD), pretend that it has been acknowledged so that we - * can send a FIN without breaking things. - */ - if ( ! ( conn->tcp_state & TCP_STATE_ACKED ( TCP_SYN ) ) ) - tcp_rx_ack ( conn, ( conn->snd_seq + 1 ), 0 ); - - /* Send a FIN to initiate the close */ - conn->tcp_state |= TCP_STATE_SENT ( TCP_FIN ); - tcp_dump_state ( conn ); - tcp_senddata_conn ( conn, 0 ); -} +/** TCP stream operations */ +static struct stream_connection_operations tcp_op = { + .bind = tcp_bind, + .connect = tcp_connect, + .close = tcp_close, + .send = tcp_send, + .kick = tcp_kick, +}; /** TCP protocol */ struct tcpip_protocol tcp_protocol __tcpip_protocol = { diff --git a/src/net/tcp/ftp.c b/src/net/tcp/ftp.c index 78567884..061240c3 100644 --- a/src/net/tcp/ftp.c +++ b/src/net/tcp/ftp.c @@ -4,10 +4,12 @@ #include #include #include +#include #include #include #include #include +#include #include /** @file @@ -40,13 +42,14 @@ static const char * ftp_strings[] = { }; /** - * Get FTP request from control TCP application + * Get FTP request from control stream application * - * @v app TCP application + * @v app Stream application * @ret ftp FTP request */ -static inline struct ftp_request * tcp_to_ftp ( struct tcp_application *app ) { - return container_of ( app, struct ftp_request, tcp ); +static inline struct ftp_request * +stream_to_ftp ( struct stream_application *app ) { + return container_of ( app, struct ftp_request, stream ); } /** @@ -59,9 +62,9 @@ static void ftp_done ( struct ftp_request *ftp, int rc ) { DBGC ( ftp, "FTP %p completed with status %d\n", ftp, rc ); - /* Close both TCP connections */ - tcp_close ( &ftp->tcp ); - tcp_close ( &ftp->tcp_data ); + /* Close both stream connections */ + stream_close ( &ftp->stream ); + stream_close ( &ftp->stream_data ); /* Mark asynchronous operation as complete */ async_done ( &ftp->async, rc ); @@ -70,9 +73,9 @@ static void ftp_done ( struct ftp_request *ftp, int rc ) { /** * Parse FTP byte sequence value * - * @v text Text string - * @v value Value buffer - * @v len Length of value buffer + * @v text Text string + * @v value Value buffer + * @v len Length of value buffer * * This parses an FTP byte sequence value (e.g. the "aaa,bbb,ccc,ddd" * form for IP addresses in PORT commands) into a byte sequence. @c @@ -93,7 +96,7 @@ static void ftp_parse_value ( char **text, uint8_t *value, size_t len ) { /** * Handle an FTP control channel response * - * @v ftp FTP request + * @v ftp FTP request * * This is called once we have received a complete response line. */ @@ -121,7 +124,7 @@ static void ftp_reply ( struct ftp_request *ftp ) { char *ptr = ftp->passive_text; union { struct sockaddr_in sin; - struct sockaddr_tcpip st; + struct sockaddr sa; } sa; int rc; @@ -130,7 +133,14 @@ static void ftp_reply ( struct ftp_request *ftp ) { sizeof ( sa.sin.sin_addr ) ); ftp_parse_value ( &ptr, ( uint8_t * ) &sa.sin.sin_port, sizeof ( sa.sin.sin_port ) ); - if ( ( rc = tcp_connect ( &ftp->tcp_data, &sa.st, 0 ) ) != 0 ){ + if ( ( rc = tcp_open ( &ftp->stream_data ) ) != 0 ) { + DBGC ( ftp, "FTP %p could not open data connection\n", + ftp ); + ftp_done ( ftp, rc ); + return; + } + if ( ( rc = stream_connect ( &ftp->stream_data, + &sa.sa ) ) != 0 ){ DBGC ( ftp, "FTP %p could not make data connection\n", ftp ); ftp_done ( ftp, rc ); @@ -154,16 +164,16 @@ static void ftp_reply ( struct ftp_request *ftp ) { /** * Handle new data arriving on FTP control channel * - * @v app TCP application - * @v data New data - * @v len Length of new data + * @v app Stream application + * @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_application *app, +static void ftp_newdata ( struct stream_application *app, void *data, size_t len ) { - struct ftp_request *ftp = tcp_to_ftp ( app ); + struct ftp_request *ftp = stream_to_ftp ( app ); char *recvbuf = ftp->recvbuf; size_t recvsize = ftp->recvsize; char c; @@ -210,10 +220,10 @@ static void ftp_newdata ( struct tcp_application *app, /** * Handle acknowledgement of data sent on FTP control channel * - * @v app TCP application + * @v app Stream application */ -static void ftp_acked ( struct tcp_application *app, size_t len ) { - struct ftp_request *ftp = tcp_to_ftp ( app ); +static void ftp_acked ( struct stream_application *app, size_t len ) { + struct ftp_request *ftp = stream_to_ftp ( app ); /* Mark off ACKed portion of the currently-transmitted data */ ftp->already_sent += len; @@ -222,31 +232,31 @@ static void ftp_acked ( struct tcp_application *app, size_t len ) { /** * Construct data to send on FTP control channel * - * @v app TCP application - * @v buf Temporary data buffer - * @v len Length of temporary data buffer + * @v app Stream application + * @v buf Temporary data buffer + * @v len Length of temporary data buffer */ -static void ftp_senddata ( struct tcp_application *app, +static void ftp_senddata ( struct stream_application *app, void *buf, size_t len ) { - struct ftp_request *ftp = tcp_to_ftp ( app ); + struct ftp_request *ftp = stream_to_ftp ( app ); /* Send the as-yet-unACKed portion of the string for the * current state. */ len = snprintf ( buf, len, ftp_strings[ftp->state], ftp->uri->path ); - tcp_send ( app, buf + ftp->already_sent, len - ftp->already_sent ); + stream_send ( app, buf + ftp->already_sent, len - ftp->already_sent ); } /** * Handle control channel being closed * - * @v app TCP application + * @v app Stream application * * When the control channel is closed, the data channel must also be * closed, if it is currently open. */ -static void ftp_closed ( struct tcp_application *app, int rc ) { - struct ftp_request *ftp = tcp_to_ftp ( app ); +static void ftp_closed ( struct stream_application *app, int rc ) { + struct ftp_request *ftp = stream_to_ftp ( app ); DBGC ( ftp, "FTP %p control connection closed: %s\n", ftp, strerror ( rc ) ); @@ -256,7 +266,7 @@ static void ftp_closed ( struct tcp_application *app, int rc ) { } /** FTP control channel operations */ -static struct tcp_operations ftp_tcp_operations = { +static struct stream_application_operations ftp_stream_operations = { .closed = ftp_closed, .acked = ftp_acked, .newdata = ftp_newdata, @@ -270,20 +280,20 @@ static struct tcp_operations ftp_tcp_operations = { */ /** - * Get FTP request from data TCP application + * Get FTP request from data stream application * - * @v app TCP application + * @v app Stream application * @ret ftp FTP request */ static inline struct ftp_request * -tcp_to_ftp_data ( struct tcp_application *app ) { - return container_of ( app, struct ftp_request, tcp_data ); +stream_to_ftp_data ( struct stream_application *app ) { + return container_of ( app, struct ftp_request, stream_data ); } /** * Handle data channel being closed * - * @v app TCP application + * @v app Stream application * * When the data channel is closed, the control channel should be left * alone; the server will send a completion message via the control @@ -291,8 +301,8 @@ tcp_to_ftp_data ( struct tcp_application *app ) { * * If the data channel is closed due to an error, we abort the request. */ -static void ftp_data_closed ( struct tcp_application *app, int rc ) { - struct ftp_request *ftp = tcp_to_ftp_data ( app ); +static void ftp_data_closed ( struct stream_application *app, int rc ) { + struct ftp_request *ftp = stream_to_ftp_data ( app ); DBGC ( ftp, "FTP %p data connection closed: %s\n", ftp, strerror ( rc ) ); @@ -305,13 +315,13 @@ static void ftp_data_closed ( struct tcp_application *app, int rc ) { /** * Handle new data arriving on the FTP data channel * - * @v app TCP application - * @v data New data - * @v len Length of new data + * @v app Stream application + * @v data New data + * @v len Length of new data */ -static void ftp_data_newdata ( struct tcp_application *app, +static void ftp_data_newdata ( struct stream_application *app, void *data, size_t len ) { - struct ftp_request *ftp = tcp_to_ftp_data ( app ); + struct ftp_request *ftp = stream_to_ftp_data ( app ); int rc; /* Fill data buffer */ @@ -325,7 +335,7 @@ static void ftp_data_newdata ( struct tcp_application *app, } /** FTP data channel operations */ -static struct tcp_operations ftp_data_tcp_operations = { +static struct stream_application_operations ftp_data_stream_operations = { .closed = ftp_data_closed, .newdata = ftp_data_newdata, }; @@ -353,9 +363,6 @@ static struct async_operations ftp_async_operations = { .reap = ftp_reap, }; -#warning "Quick name resolution hack" -#include - /** * Initiate an FTP connection * @@ -387,12 +394,12 @@ int ftp_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) { ftp->already_sent = 0; ftp->recvbuf = ftp->status_text; ftp->recvsize = sizeof ( ftp->status_text ) - 1; - ftp->tcp.tcp_op = &ftp_tcp_operations; - ftp->tcp_data.tcp_op = &ftp_data_tcp_operations; + ftp->stream.op = &ftp_stream_operations; + ftp->stream_data.op = &ftp_data_stream_operations; #warning "Quick name resolution hack" union { - struct sockaddr_tcpip st; + struct sockaddr sa; struct sockaddr_in sin; } server; server.sin.sin_port = htons ( FTP_PORT ); @@ -404,7 +411,9 @@ int ftp_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) { DBGC ( ftp, "FTP %p fetching %s\n", ftp, ftp->uri->path ); - if ( ( rc = tcp_connect ( &ftp->tcp, &server.st, 0 ) ) != 0 ) + if ( ( rc = tcp_open ( &ftp->stream ) ) != 0 ) + goto err; + if ( ( rc = stream_connect ( &ftp->stream, &server.sa ) ) != 0 ) goto err; async_init ( &ftp->async, &ftp_async_operations, parent ); diff --git a/src/net/tcp/http.c b/src/net/tcp/http.c index 18030fe6..381ab1f4 100644 --- a/src/net/tcp/http.c +++ b/src/net/tcp/http.c @@ -36,13 +36,14 @@ #include #include #include +#include #include static struct async_operations http_async_operations; static inline struct http_request * -tcp_to_http ( struct tcp_application *app ) { - return container_of ( app, struct http_request, tcp ); +stream_to_http ( struct stream_application *app ) { + return container_of ( app, struct http_request, stream ); } /** @@ -54,8 +55,8 @@ tcp_to_http ( struct tcp_application *app ) { */ static void http_done ( struct http_request *http, int rc ) { - /* Close TCP connection */ - tcp_close ( &http->tcp ); + /* Close stream connection */ + stream_close ( &http->stream ); /* Prevent further processing of any current packet */ http->rx_state = HTTP_RX_DEAD; @@ -271,9 +272,9 @@ static void http_rx_data ( struct http_request *http, * @v data New data * @v len Length of new data */ -static void http_newdata ( struct tcp_application *app, +static void http_newdata ( struct stream_application *app, void *data, size_t len ) { - struct http_request *http = tcp_to_http ( app ); + struct http_request *http = stream_to_http ( app ); const char *buf = data; char *line; int rc; @@ -319,13 +320,13 @@ static void http_newdata ( struct tcp_application *app, /** * Send HTTP data * - * @v app TCP application + * @v app Stream application * @v buf Temporary data buffer * @v len Length of temporary data buffer */ -static void http_senddata ( struct tcp_application *app, +static void http_senddata ( struct stream_application *app, void *buf, size_t len ) { - struct http_request *http = tcp_to_http ( app ); + struct http_request *http = stream_to_http ( app ); const char *path = http->uri->path; const char *host = http->uri->host; @@ -338,17 +339,18 @@ static void http_senddata ( struct tcp_application *app, "Host: %s\r\n" "\r\n", path, host ); - tcp_send ( app, ( buf + http->tx_offset ), ( len - http->tx_offset ) ); + stream_send ( app, ( buf + http->tx_offset ), + ( len - http->tx_offset ) ); } /** * HTTP data acknowledged * - * @v app TCP application + * @v app Stream application * @v len Length of acknowledged data */ -static void http_acked ( struct tcp_application *app, size_t len ) { - struct http_request *http = tcp_to_http ( app ); +static void http_acked ( struct stream_application *app, size_t len ) { + struct http_request *http = stream_to_http ( app ); http->tx_offset += len; } @@ -356,10 +358,10 @@ static void http_acked ( struct tcp_application *app, size_t len ) { /** * HTTP connection closed by network stack * - * @v app TCP application + * @v app Stream application */ -static void http_closed ( struct tcp_application *app, int rc ) { - struct http_request *http = tcp_to_http ( app ); +static void http_closed ( struct stream_application *app, int rc ) { + struct http_request *http = stream_to_http ( app ); DBGC ( http, "HTTP %p connection closed: %s\n", http, strerror ( rc ) ); @@ -367,8 +369,8 @@ static void http_closed ( struct tcp_application *app, int rc ) { http_done ( http, rc ); } -/** HTTP TCP operations */ -static struct tcp_operations http_tcp_operations = { +/** HTTP stream operations */ +static struct stream_application_operations http_stream_operations = { .closed = http_closed, .acked = http_acked, .newdata = http_newdata, @@ -395,6 +397,7 @@ int http_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) { http->uri = uri; http->buffer = buffer; async_init ( &http->async, &http_async_operations, parent ); + http->stream.op = &http_stream_operations; /* Start name resolution. The download proper will start when * name resolution completes. @@ -432,10 +435,15 @@ static void http_sigchld ( struct async *async, enum signal signal __unused ) { } /* Otherwise, start the HTTP connection */ - http->tcp.tcp_op = &http_tcp_operations; + if ( ( rc = tcp_open ( &http->stream ) ) != 0 ) { + DBGC ( http, "HTTP %p could not open stream connection: %s\n", + http, strerror ( rc ) ); + http_done ( http, rc ); + return; + } st->st_port = htons ( uri_port ( http->uri, HTTP_PORT ) ); - if ( ( rc = tcp_connect ( &http->tcp, st, 0 ) ) != 0 ) { - DBGC ( http, "HTTP %p could not open TCP connection: %s\n", + if ( ( rc = stream_connect ( &http->stream, &http->server ) ) != 0 ) { + DBGC ( http, "HTTP %p could not connect stream: %s\n", http, strerror ( rc ) ); http_done ( http, rc ); return; diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c index 4d95c0b9..56567976 100644 --- a/src/net/tcp/iscsi.c +++ b/src/net/tcp/iscsi.c @@ -26,6 +26,7 @@ #include #include #include +#include #include /** @file @@ -85,8 +86,8 @@ static void iscsi_rx_buffered_data_done ( struct iscsi_session *iscsi ) { */ static void iscsi_close ( struct iscsi_session *iscsi ) { - /* Close TCP connection */ - tcp_close ( &iscsi->tcp ); + /* Close stream connection */ + stream_close ( &iscsi->stream ); /* Clear connection status */ iscsi->status = 0; @@ -338,7 +339,7 @@ static void iscsi_tx_data_out ( struct iscsi_session *iscsi, len = remaining; copy_from_user ( buf, iscsi->command->data_out, offset, len ); - tcp_send ( &iscsi->tcp, buf, len ); + stream_send ( &iscsi->stream, buf, len ); } /**************************************************************************** @@ -507,7 +508,7 @@ static void iscsi_login_request_done ( struct iscsi_session *iscsi ) { static void iscsi_tx_login_request ( struct iscsi_session *iscsi, void *buf, size_t len ) { len = iscsi_build_login_request_strings ( iscsi, buf, len ); - tcp_send ( &iscsi->tcp, buf + iscsi->tx_offset, + stream_send ( &iscsi->stream, buf + iscsi->tx_offset, len - iscsi->tx_offset ); } @@ -750,11 +751,18 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data, if ( response->status_class == ISCSI_STATUS_REDIRECT ) { DBGC ( iscsi, "iSCSI %p redirecting to new server\n", iscsi ); iscsi_close ( iscsi ); - if ( ( rc = tcp_connect ( &iscsi->tcp, &iscsi->target, - 0 ) ) != 0 ) { - DBGC ( iscsi, "iSCSI %p could not open TCP " - "connection: %s\n", iscsi, strerror ( rc ) ); + if ( ( rc = tcp_open ( &iscsi->stream ) ) != 0 ) { + DBGC ( iscsi, "iSCSI %p could not open stream: %s\n ", + iscsi, strerror ( rc ) ); iscsi_done ( iscsi, rc ); + return; + } + if ( ( rc = stream_connect ( &iscsi->stream, + &iscsi->target ) != 0 ) != 0 ) { + DBGC ( iscsi, "iSCSI %p could not connect: %s\n ", + iscsi, strerror ( rc ) ); + iscsi_done ( iscsi, rc ); + return; } return; } @@ -810,13 +818,13 @@ static void iscsi_rx_login_response ( struct iscsi_session *iscsi, void *data, /**************************************************************************** * - * iSCSI to TCP interface + * iSCSI to stream interface * */ static inline struct iscsi_session * -tcp_to_iscsi ( struct tcp_application *app ) { - return container_of ( app, struct iscsi_session, tcp ); +stream_to_iscsi ( struct stream_application *app ) { + return container_of ( app, struct iscsi_session, stream ); } /** @@ -889,15 +897,15 @@ static void iscsi_tx_done ( struct iscsi_session *iscsi ) { } /** - * Handle TCP ACKs + * Handle stream ACKs * * @v iscsi iSCSI session * * Updates iscsi->tx_offset and, if applicable, transitions to the * next TX state. */ -static void iscsi_acked ( struct tcp_application *app, size_t len ) { - struct iscsi_session *iscsi = tcp_to_iscsi ( app ); +static void iscsi_acked ( struct stream_application *app, size_t len ) { + struct iscsi_session *iscsi = stream_to_iscsi ( app ); struct iscsi_bhs_common *common = &iscsi->tx_bhs.common; enum iscsi_tx_state next_state; @@ -953,9 +961,9 @@ static void iscsi_acked ( struct tcp_application *app, size_t len ) { * * Constructs data to be sent for the current TX state */ -static void iscsi_senddata ( struct tcp_application *app, +static void iscsi_senddata ( struct stream_application *app, void *buf, size_t len ) { - struct iscsi_session *iscsi = tcp_to_iscsi ( app ); + struct iscsi_session *iscsi = stream_to_iscsi ( app ); struct iscsi_bhs_common *common = &iscsi->tx_bhs.common; static const char pad[] = { '\0', '\0', '\0' }; @@ -964,7 +972,7 @@ static void iscsi_senddata ( struct tcp_application *app, /* Nothing to send */ break; case ISCSI_TX_BHS: - tcp_send ( app, &iscsi->tx_bhs.bytes[iscsi->tx_offset], + stream_send ( app, &iscsi->tx_bhs.bytes[iscsi->tx_offset], ( sizeof ( iscsi->tx_bhs ) - iscsi->tx_offset ) ); break; case ISCSI_TX_AHS: @@ -975,8 +983,8 @@ static void iscsi_senddata ( struct tcp_application *app, iscsi_tx_data ( iscsi, buf, len ); break; case ISCSI_TX_DATA_PADDING: - tcp_send ( app, pad, ( ISCSI_DATA_PAD_LEN ( common->lengths ) - - iscsi->tx_offset ) ); + stream_send ( app, pad, ( ISCSI_DATA_PAD_LEN( common->lengths ) + - iscsi->tx_offset ) ); break; default: assert ( 0 ); @@ -1068,7 +1076,7 @@ static void iscsi_rx_bhs ( struct iscsi_session *iscsi, void *data, /** * Receive new data * - * @v tcp TCP application + * @v stream Stream application * @v data Received data * @v len Length of received data * @@ -1079,9 +1087,9 @@ static void iscsi_rx_bhs ( struct iscsi_session *iscsi, void *data, * always has a full copy of the BHS available, even for portions of * the data in different packets to the BHS. */ -static void iscsi_newdata ( struct tcp_application *app, void *data, +static void iscsi_newdata ( struct stream_application *app, void *data, size_t len ) { - struct iscsi_session *iscsi = tcp_to_iscsi ( app ); + struct iscsi_session *iscsi = stream_to_iscsi ( app ); struct iscsi_bhs_common *common = &iscsi->rx_bhs.common; void ( *process ) ( struct iscsi_session *iscsi, void *data, size_t len, size_t remaining ); @@ -1138,14 +1146,14 @@ static void iscsi_newdata ( struct tcp_application *app, void *data, } /** - * Handle TCP connection closure + * Handle stream connection closure * - * @v app TCP application + * @v app Stream application * @v status Error code, if any * */ -static void iscsi_closed ( struct tcp_application *app, int status ) { - struct iscsi_session *iscsi = tcp_to_iscsi ( app ); +static void iscsi_closed ( struct stream_application *app, int status ) { + struct iscsi_session *iscsi = stream_to_iscsi ( app ); int rc; /* Even a graceful close counts as an error for iSCSI */ @@ -1159,26 +1167,34 @@ static void iscsi_closed ( struct tcp_application *app, int status ) { if ( ++iscsi->retry_count <= ISCSI_MAX_RETRIES ) { DBGC ( iscsi, "iSCSI %p retrying connection (retry #%d)\n", iscsi, iscsi->retry_count ); - if ( ( rc = tcp_connect ( app, &iscsi->target, 0 ) ) != 0 ) { - DBGC ( iscsi, "iSCSI %p could not open TCP " - "connection: %s\n", iscsi, strerror ( rc ) ); + if ( ( rc = tcp_open ( app ) ) != 0 ) { + DBGC ( iscsi, "iSCSI %p could not open stream: %s\n ", + iscsi, strerror ( rc ) ); iscsi_done ( iscsi, rc ); + return; + } + if ( ( rc = stream_connect ( app, &iscsi->target ) ) != 0 ){ + DBGC ( iscsi, "iSCSI %p could not connect: %s\n", + iscsi, strerror ( rc ) ); + iscsi_done ( iscsi, rc ); + return; } } else { DBGC ( iscsi, "iSCSI %p retry count exceeded\n", iscsi ); iscsi->instant_rc = status; iscsi_done ( iscsi, status ); + return; } } /** - * Handle TCP connection opening + * Handle stream connection opening * - * @v app TCP application + * @v app Stream application * */ -static void iscsi_connected ( struct tcp_application *app ) { - struct iscsi_session *iscsi = tcp_to_iscsi ( app ); +static void iscsi_connected ( struct stream_application *app ) { + struct iscsi_session *iscsi = stream_to_iscsi ( app ); assert ( iscsi->rx_state == ISCSI_RX_BHS ); assert ( iscsi->rx_offset == 0 ); @@ -1194,8 +1210,8 @@ static void iscsi_connected ( struct tcp_application *app ) { iscsi_start_login ( iscsi ); } -/** iSCSI TCP operations */ -static struct tcp_operations iscsi_tcp_operations = { +/** iSCSI stream operations */ +static struct stream_application_operations iscsi_stream_operations = { .closed = iscsi_closed, .connected = iscsi_connected, .acked = iscsi_acked, @@ -1224,14 +1240,19 @@ int iscsi_issue ( struct iscsi_session *iscsi, struct scsi_command *command, } else if ( iscsi->status ) { /* Session already open: issue command */ iscsi_start_command ( iscsi ); - tcp_senddata ( &iscsi->tcp ); + stream_kick ( &iscsi->stream ); } else { /* Session not open: initiate login */ - iscsi->tcp.tcp_op = &iscsi_tcp_operations; - if ( ( rc = tcp_connect ( &iscsi->tcp, &iscsi->target, - 0 ) ) != 0 ) { - DBGC ( iscsi, "iSCSI %p could not open TCP " - "connection: %s\n", iscsi, strerror ( rc ) ); + iscsi->stream.op = &iscsi_stream_operations; + if ( ( rc = tcp_open ( &iscsi->stream ) ) != 0 ) { + DBGC ( iscsi, "iSCSI %p could not open stream: %s\n ", + iscsi, strerror ( rc ) ); + return rc; + } + if ( ( rc = stream_connect ( &iscsi->stream, + &iscsi->target ) ) != 0 ) { + DBGC ( iscsi, "iSCSI %p could not connect: %s\n", + iscsi, strerror ( rc ) ); return rc; } }