summaryrefslogtreecommitdiffstats
path: root/src/net/tcp.c
diff options
context:
space:
mode:
authorMichael Brown2006-12-29 01:44:31 +0100
committerMichael Brown2006-12-29 01:44:31 +0100
commitce9819af2762c5008df216b27612f7c589f21fac (patch)
treec750c06d9fbdc04e7adb32135c43417ca31e4865 /src/net/tcp.c
parentDon't send a second FIN if we receive a FIN while in FIN_WAIT_2 (diff)
downloadipxe-ce9819af2762c5008df216b27612f7c589f21fac.tar.gz
ipxe-ce9819af2762c5008df216b27612f7c589f21fac.tar.xz
ipxe-ce9819af2762c5008df216b27612f7c589f21fac.zip
Redefine TCP state to include "flags that have been sent" rather than
"flags that are currently being sent". This allows at least one special case (checking that we haven't already sent a FIN in tcp_rx_fin()) to be collapsed.
Diffstat (limited to 'src/net/tcp.c')
-rw-r--r--src/net/tcp.c34
1 files changed, 15 insertions, 19 deletions
diff --git a/src/net/tcp.c b/src/net/tcp.c
index 1b5f76c0..a5a1be09 100644
--- a/src/net/tcp.c
+++ b/src/net/tcp.c
@@ -229,6 +229,7 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) {
struct tcp_application *app = conn->app;
struct pk_buff *pkb;
struct tcp_header *tcphdr;
+ unsigned int flags;
size_t len;
size_t seq_len;
@@ -264,9 +265,9 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) {
*/
len = pkb_len ( pkb );
seq_len = len;
- assert ( ! ( ( conn->tcp_state & TCP_STATE_SENDING ( TCP_SYN ) ) &&
- ( conn->tcp_state & TCP_STATE_SENDING ( TCP_FIN ) ) ) );
- if ( conn->tcp_state & TCP_STATE_SENDING ( TCP_SYN | TCP_FIN ) )
+ flags = TCP_FLAGS_SENDING ( conn->tcp_state );
+ assert ( ! ( ( flags & TCP_SYN ) && ( flags & TCP_FIN ) ) );
+ if ( flags & ( TCP_SYN | TCP_FIN ) )
seq_len++;
conn->snd_sent = seq_len;
@@ -291,7 +292,7 @@ static int tcp_senddata_conn ( struct tcp_connection *conn, int force_send ) {
tcphdr->seq = htonl ( conn->snd_seq );
tcphdr->ack = htonl ( conn->rcv_ack );
tcphdr->hlen = ( ( sizeof ( *tcphdr ) / 4 ) << 4 );
- tcphdr->flags = TCP_FLAGS_SENDING ( conn->tcp_state );
+ tcphdr->flags = flags;
tcphdr->win = htons ( TCP_WINDOW_SIZE );
tcphdr->csum = tcpip_chksum ( pkb->data, pkb_len ( pkb ) );
@@ -458,7 +459,7 @@ static int tcp_rx_syn ( struct tcp_connection *conn, uint32_t seq ) {
return 0;
/* Mark SYN as received and start sending ACKs with each packet */
- conn->tcp_state |= ( TCP_STATE_SENDING ( TCP_ACK ) |
+ conn->tcp_state |= ( TCP_STATE_SENT ( TCP_ACK ) |
TCP_STATE_RCVD ( TCP_SYN ) );
/* Acknowledge SYN */
@@ -517,10 +518,8 @@ static int tcp_rx_ack ( struct tcp_connection *conn, uint32_t ack,
app->tcp_op->acked ( app, len );
/* Mark SYN/FIN as acknowledged if applicable. */
- if ( acked_flags ) {
- conn->tcp_state &= ~TCP_STATE_SENDING ( TCP_SYN | TCP_FIN );
+ if ( acked_flags )
conn->tcp_state |= TCP_STATE_ACKED ( acked_flags );
- }
/* Notify application of established connection, if applicable */
if ( ( acked_flags & TCP_SYN ) && app && app->tcp_op->connected )
@@ -573,14 +572,11 @@ static int tcp_rx_fin ( struct tcp_connection *conn, uint32_t seq ) {
if ( ( conn->rcv_ack - seq ) > 0 )
return 0;
- /* Mark FIN as received and acknowledge it */
- conn->tcp_state |= TCP_STATE_RCVD ( TCP_FIN );
+ /* Mark FIN as received, acknowledge it, and send our own FIN */
+ conn->tcp_state |= ( TCP_STATE_RCVD ( TCP_FIN ) |
+ TCP_STATE_SENT ( TCP_FIN ) );
conn->rcv_ack++;
- /* If we haven't already sent our FIN, send a FIN */
- if ( ! ( conn->tcp_state & TCP_STATE_ACKED ( TCP_FIN ) ) )
- conn->tcp_state |= TCP_STATE_SENDING ( TCP_FIN );
-
/* Break association with application */
tcp_disassociate ( conn );
@@ -832,15 +828,15 @@ void tcp_close ( struct tcp_application *app ) {
return;
}
- /* If we have sent a SYN but not had it 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 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_SENDING ( TCP_SYN ) )
+ 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_SENDING ( TCP_FIN );
+ conn->tcp_state |= TCP_STATE_SENT ( TCP_FIN );
tcp_dump_state ( conn );
tcp_senddata_conn ( conn, 0 );
}