diff --git a/src/include/gpxe/tcp.h b/src/include/gpxe/tcp.h index f5df8cba..f0ac8ace 100644 --- a/src/include/gpxe/tcp.h +++ b/src/include/gpxe/tcp.h @@ -42,17 +42,16 @@ struct tcp_header { /** * @defgroup tcpstates TCP states * -* The TCP state is defined by a combination of the flags that are -* currently being sent in outgoing packets, the flags that have been -* sent and acknowledged by the peer, and the flags that have been -* received from the peer. +* The TCP state is defined by a combination of the flags that have +* been sent to the peer, the flags that have been acknowledged by the +* peer, and the flags that have been received from the peer. * * @{ */ -/** TCP flags that are currently being sent in outgoing packets */ -#define TCP_STATE_SENDING(flags) ( (flags) << 0 ) -#define TCP_FLAGS_SENDING(state) ( ( (state) >> 0 ) & 0xff ) +/** TCP flags that have been sent in outgoing packets */ +#define TCP_STATE_SENT(flags) ( (flags) << 0 ) +#define TCP_FLAGS_SENT(state) ( ( (state) >> 0 ) & 0xff ) /** TCP flags that have been acknowledged by the peer * @@ -69,6 +68,10 @@ struct tcp_header { #define TCP_STATE_RCVD(flags) ( (flags) << 12 ) #define TCP_FLAGS_RCVD(state) ( ( (state) >> 12 ) & 0x03 ) +/** TCP flags that are currently being sent in outgoing packets */ +#define TCP_FLAGS_SENDING(state) \ + ( TCP_FLAGS_SENT ( state ) & ~TCP_FLAGS_ACKED ( state ) ) + /** CLOSED * * The connection has not yet been used for anything. @@ -86,21 +89,21 @@ struct tcp_header { * * SYN has been sent, nothing has yet been received or acknowledged. */ -#define TCP_SYN_SENT ( TCP_STATE_SENDING ( TCP_SYN ) ) +#define TCP_SYN_SENT ( TCP_STATE_SENT ( TCP_SYN ) ) /** SYN_RCVD * * SYN has been sent but not acknowledged, SYN has been received. */ -#define TCP_SYN_RCVD ( TCP_STATE_SENDING ( TCP_SYN | TCP_ACK ) | \ +#define TCP_SYN_RCVD ( TCP_STATE_SENT ( TCP_SYN | TCP_ACK ) | \ TCP_STATE_RCVD ( TCP_SYN ) ) /** ESTABLISHED * * SYN has been sent and acknowledged, SYN has been received. */ -#define TCP_ESTABLISHED ( TCP_STATE_SENDING ( TCP_ACK ) | \ - TCP_STATE_ACKED ( TCP_SYN ) | \ +#define TCP_ESTABLISHED ( TCP_STATE_SENT ( TCP_SYN | TCP_ACK ) | \ + TCP_STATE_ACKED ( TCP_SYN ) | \ TCP_STATE_RCVD ( TCP_SYN ) ) /** FIN_WAIT_1 @@ -117,8 +120,8 @@ struct tcp_header { * to FIN_WAIT_1, we have to remember to set TCP_STATE_ACKED(TCP_SYN) * and increment our sequence number. */ -#define TCP_FIN_WAIT_1 ( TCP_STATE_SENDING ( TCP_ACK | TCP_FIN ) | \ - TCP_STATE_ACKED ( TCP_SYN ) | \ +#define TCP_FIN_WAIT_1 ( TCP_STATE_SENT ( TCP_SYN | TCP_ACK | TCP_FIN ) | \ + TCP_STATE_ACKED ( TCP_SYN ) | \ TCP_STATE_RCVD ( TCP_SYN ) ) /** FIN_WAIT_2 @@ -126,8 +129,8 @@ struct tcp_header { * SYN has been sent and acknowledged, SYN has been received, FIN has * been sent and acknowledged, FIN ha not been received. */ -#define TCP_FIN_WAIT_2 ( TCP_STATE_SENDING ( TCP_ACK ) | \ - TCP_STATE_ACKED ( TCP_SYN | TCP_FIN ) | \ +#define TCP_FIN_WAIT_2 ( TCP_STATE_SENT ( TCP_SYN | TCP_ACK | TCP_FIN ) | \ + TCP_STATE_ACKED ( TCP_SYN | TCP_FIN ) | \ TCP_STATE_RCVD ( TCP_SYN ) ) /** CLOSING / LAST_ACK @@ -139,9 +142,9 @@ struct tcp_header { * identical with the definition of state that we use. I don't * *believe* that they need to be distinguished. */ -#define TCP_CLOSING_OR_LAST_ACK \ - ( TCP_STATE_SENDING ( TCP_ACK | TCP_FIN ) | \ - TCP_STATE_ACKED ( TCP_SYN ) | \ +#define TCP_CLOSING_OR_LAST_ACK \ + ( TCP_STATE_SENT ( TCP_SYN | TCP_ACK | TCP_FIN ) | \ + TCP_STATE_ACKED ( TCP_SYN ) | \ TCP_STATE_RCVD ( TCP_SYN | TCP_FIN ) ) /** TIME_WAIT @@ -149,8 +152,8 @@ struct tcp_header { * SYN has been sent and acknowledged, SYN has been received, FIN has * been sent and acknowledged, FIN has been received. */ -#define TCP_TIME_WAIT ( TCP_STATE_SENDING ( TCP_ACK ) | \ - TCP_STATE_ACKED ( TCP_SYN | TCP_FIN ) | \ +#define TCP_TIME_WAIT ( TCP_STATE_SENT ( TCP_SYN | TCP_ACK | TCP_FIN ) | \ + TCP_STATE_ACKED ( TCP_SYN | TCP_FIN ) | \ TCP_STATE_RCVD ( TCP_SYN | TCP_FIN ) ) /** CLOSE_WAIT @@ -158,8 +161,8 @@ struct tcp_header { * SYN has been sent and acknowledged, SYN has been received, FIN has * been received. */ -#define TCP_CLOSE_WAIT ( TCP_STATE_SENDING ( TCP_ACK ) | \ - TCP_STATE_ACKED ( TCP_SYN ) | \ +#define TCP_CLOSE_WAIT ( TCP_STATE_SENT ( TCP_SYN | TCP_ACK ) | \ + TCP_STATE_ACKED ( TCP_SYN ) | \ TCP_STATE_RCVD ( TCP_SYN | TCP_FIN ) ) /** Can send data in current state @@ -167,9 +170,9 @@ struct tcp_header { * We can send data if and only if we have had our SYN acked and we * have not yet sent our FIN. */ -#define TCP_CAN_SEND_DATA(state) \ - ( ( (state) & ( TCP_STATE_ACKED ( TCP_SYN | TCP_FIN ) | \ - TCP_STATE_SENDING ( TCP_FIN ) ) ) \ +#define TCP_CAN_SEND_DATA(state) \ + ( ( (state) & ( TCP_STATE_ACKED ( TCP_SYN ) | \ + TCP_STATE_SENT ( TCP_FIN ) ) ) \ == TCP_STATE_ACKED ( TCP_SYN ) ) /** Have closed gracefully @@ -177,9 +180,9 @@ struct tcp_header { * We have closed gracefully if we have both received a FIN and had * our own FIN acked. */ -#define TCP_CLOSED_GRACEFULLY(state) \ - ( ( (state) & ( TCP_STATE_ACKED ( TCP_FIN ) | \ - TCP_STATE_RCVD ( TCP_FIN ) ) ) \ +#define TCP_CLOSED_GRACEFULLY(state) \ + ( ( (state) & ( TCP_STATE_ACKED ( TCP_FIN ) | \ + TCP_STATE_RCVD ( TCP_FIN ) ) ) \ == ( TCP_STATE_ACKED ( TCP_FIN ) | TCP_STATE_RCVD ( TCP_FIN ) ) ) /** @} */ 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 ); }