summaryrefslogtreecommitdiffstats
path: root/src/net/tcp.c
diff options
context:
space:
mode:
authorMichael Brown2006-12-05 23:53:28 +0100
committerMichael Brown2006-12-05 23:53:28 +0100
commitcc0b92652f876834f332935be4f44414e0445b47 (patch)
tree28627ccc12f80425ed7d6eb410d3c3f64cdea690 /src/net/tcp.c
parentEnsure that tcp_rx() always frees its received packet buffer. (diff)
downloadipxe-cc0b92652f876834f332935be4f44414e0445b47.tar.gz
ipxe-cc0b92652f876834f332935be4f44414e0445b47.tar.xz
ipxe-cc0b92652f876834f332935be4f44414e0445b47.zip
Call closed() method only when the connection is genuinely in the
TCP_CLOSED state (i.e. after the final FIN/ACK exchange), and has been removed from the list of TCP connections.
Diffstat (limited to 'src/net/tcp.c')
-rw-r--r--src/net/tcp.c33
1 files changed, 19 insertions, 14 deletions
diff --git a/src/net/tcp.c b/src/net/tcp.c
index afdf47c2..f8ac7011 100644
--- a/src/net/tcp.c
+++ b/src/net/tcp.c
@@ -378,21 +378,27 @@ void tcp_init_conn ( struct tcp_connection *conn ) {
* @v over Failure indicator
*/
void tcp_expired ( struct retry_timer *timer, int over ) {
- struct tcp_connection *conn;
- conn = ( struct tcp_connection * ) container_of ( timer,
- struct tcp_connection, timer );
+ struct tcp_connection *conn =
+ container_of ( timer, struct tcp_connection, timer );
+
DBG ( "Timer expired in %s\n", tcp_states[conn->tcp_state] );
switch ( conn->tcp_state ) {
case TCP_SYN_SENT:
if ( over ) {
+ list_del ( &conn->list );
tcp_trans ( conn, TCP_CLOSED );
+ if ( conn->tcp_op->closed )
+ conn->tcp_op->closed ( conn, -ETIMEDOUT );
DBG ( "Timeout! Connection closed\n" );
return;
}
goto send_tcp_nomsg;
case TCP_SYN_RCVD:
if ( over ) {
+ list_del ( &conn->list );
tcp_trans ( conn, TCP_CLOSED );
+ if ( conn->tcp_op->closed )
+ conn->tcp_op->closed ( conn, -ETIMEDOUT );
goto send_tcp_nomsg;
}
goto send_tcp_nomsg;
@@ -416,7 +422,10 @@ void tcp_expired ( struct retry_timer *timer, int over ) {
}
return;
case TCP_TIME_WAIT:
+ list_del ( &conn->list );
tcp_trans ( conn, TCP_CLOSED );
+ if ( conn->tcp_op->closed )
+ conn->tcp_op->closed ( conn, 0 );
return;
}
/* Retransmit the data */
@@ -496,8 +505,6 @@ int tcp_close ( struct tcp_connection *conn ) {
case TCP_SYN_RCVD:
case TCP_ESTABLISHED:
tcp_trans ( conn, TCP_FIN_WAIT_1 );
- if ( conn->tcp_op->closed )
- conn->tcp_op->closed ( conn, CONN_SNDCLOSE ); /* TODO: Check! */
/* FIN consumes one byte on the snd stream */
// conn->snd_una++;
goto send_tcp_nomsg;
@@ -511,12 +518,10 @@ int tcp_close ( struct tcp_connection *conn ) {
list_del ( &conn->list );
tcp_trans ( conn, TCP_CLOSED );
if ( conn->tcp_op->closed )
- conn->tcp_op->closed ( conn, CONN_SNDCLOSE );
+ conn->tcp_op->closed ( conn, 0 );
return 0;
case TCP_CLOSE_WAIT:
tcp_trans ( conn, TCP_LAST_ACK );
- if ( conn->tcp_op->closed )
- conn->tcp_op->closed ( conn, CONN_SNDCLOSE ); /* TODO: Check! */
/* FIN consumes one byte on the snd stream */
// conn->snd_una++;
goto send_tcp_nomsg;
@@ -715,8 +720,8 @@ static int tcp_rx ( struct pk_buff *pkb,
struct sockaddr_tcpip *st_dest __unused ) {
struct tcp_connection *conn;
struct tcp_header *tcphdr;
- uint32_t acked, toack;
- int hlen;
+ int32_t acked, toack;
+ unsigned int hlen;
int rc;
/* Sanity check */
@@ -817,7 +822,7 @@ static int tcp_rx ( struct pk_buff *pkb,
if ( tcphdr->flags & TCP_RST ) {
tcp_trans ( conn, TCP_LISTEN );
if ( conn->tcp_op->closed )
- conn->tcp_op->closed ( conn, CONN_RESTART );
+ conn->tcp_op->closed ( conn, -ECONNRESET );
rc = 0;
goto done;
}
@@ -855,9 +860,6 @@ static int tcp_rx ( struct pk_buff *pkb,
if ( tcphdr->flags & TCP_FIN ) {
conn->rcv_nxt++;
conn->tcp_flags |= TCP_ACK;
- if ( conn->tcp_op->closed )
- conn->tcp_op->closed ( conn, CONN_SNDCLOSE );
-
if ( tcphdr->flags & TCP_ACK ) {
tcp_trans ( conn, TCP_TIME_WAIT );
} else {
@@ -898,7 +900,10 @@ static int tcp_rx ( struct pk_buff *pkb,
break;
case TCP_LAST_ACK:
if ( tcphdr->flags & TCP_ACK ) {
+ list_del ( &conn->list );
tcp_trans ( conn, TCP_CLOSED );
+ if ( conn->tcp_op->closed )
+ conn->tcp_op->closed ( conn, 0 );
rc = 0;
goto done;
}