From 096fa94f0c62f5cd813f35bd229f2c6f003e92c3 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 13 Jul 2007 11:32:53 +0100 Subject: [PATCH] Add support for TCP timestamps --- src/include/gpxe/tcp.h | 47 +++++++++++++++++++++++++-- src/net/tcp.c | 74 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 115 insertions(+), 6 deletions(-) diff --git a/src/include/gpxe/tcp.h b/src/include/gpxe/tcp.h index d927d241..d967791f 100644 --- a/src/include/gpxe/tcp.h +++ b/src/include/gpxe/tcp.h @@ -27,18 +27,59 @@ struct tcp_header { uint16_t urg; /* Urgent pointer */ }; -/** - * TCP MSS option +/** @defgroup tcpopts TCP options + * @{ */ + +/** End of TCP options list */ +#define TCP_OPTION_END 0 + +/** TCP option pad */ +#define TCP_OPTION_NOP 1 + +/** Generic TCP option */ +struct tcp_option { + uint8_t kind; + uint8_t length; +} __attribute__ (( packed )); + +/** TCP MSS option */ struct tcp_mss_option { uint8_t kind; uint8_t length; uint16_t mss; -}; +} __attribute__ (( packed )); /** Code for the TCP MSS option */ #define TCP_OPTION_MSS 2 +/** TCP timestamp option */ +struct tcp_timestamp_option { + uint8_t kind; + uint8_t length; + uint32_t tsval; + uint32_t tsecr; +} __attribute__ (( packed )); + +/** Padded TCP timestamp option (used for sending) */ +struct tcp_timestamp_padded_option { + uint8_t nop[2]; + struct tcp_timestamp_option tsopt; +} __attribute__ (( packed )); + +/** Code for the TCP timestamp option */ +#define TCP_OPTION_TS 8 + +/** Parsed TCP options */ +struct tcp_options { + /** MSS option, if present */ + const struct tcp_mss_option *mssopt; + /** Timestampe option, if present */ + const struct tcp_timestamp_option *tsopt; +}; + +/** @} */ + /* * TCP flags */ diff --git a/src/net/tcp.c b/src/net/tcp.c index 98db274d..b2d9b2de 100644 --- a/src/net/tcp.c +++ b/src/net/tcp.c @@ -65,6 +65,13 @@ struct tcp_connection { * Equivalent to RCV.NXT in RFC 793 terminology. */ uint32_t rcv_ack; + /** Most recent received timestamp + * + * Equivalent to TS.Recent in RFC 1323 terminology. + */ + uint32_t ts_recent; + /** Timestamps enabled */ + int timestamps; /** Transmit queue */ struct list_head queue; @@ -381,6 +388,7 @@ static int tcp_xmit ( struct tcp_connection *tcp, int force_send ) { struct io_buffer *iobuf; struct tcp_header *tcphdr; struct tcp_mss_option *mssopt; + struct tcp_timestamp_padded_option *tsopt; void *payload; unsigned int flags; size_t len = 0; @@ -449,6 +457,14 @@ static int tcp_xmit ( struct tcp_connection *tcp, int force_send ) { mssopt->length = sizeof ( *mssopt ); mssopt->mss = htons ( TCP_MSS ); } + if ( ( flags & TCP_SYN ) || tcp->timestamps ) { + tsopt = iob_push ( iobuf, sizeof ( *tsopt ) ); + memset ( tsopt->nop, TCP_OPTION_NOP, sizeof ( tsopt->nop ) ); + tsopt->tsopt.kind = TCP_OPTION_TS; + tsopt->tsopt.length = sizeof ( tsopt->tsopt ); + tsopt->tsopt.tsval = ntohl ( currticks() ); + tsopt->tsopt.tsecr = ntohl ( tcp->ts_recent ); + } tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) ); memset ( tcphdr, 0, sizeof ( *tcphdr ) ); tcphdr->src = tcp->local_port; @@ -594,18 +610,63 @@ static struct tcp_connection * tcp_demux ( unsigned int local_port ) { return NULL; } +/** + * Parse TCP received options + * + * @v tcp TCP connection + * @v data Raw options data + * @v len Raw options length + * @v options Options structure to fill in + */ +static void tcp_rx_opts ( struct tcp_connection *tcp, const void *data, + size_t len, struct tcp_options *options ) { + const void *end = ( data + len ); + const struct tcp_option *option; + unsigned int kind; + + memset ( options, 0, sizeof ( *options ) ); + while ( data < end ) { + option = data; + kind = option->kind; + if ( kind == TCP_OPTION_END ) + return; + if ( kind == TCP_OPTION_NOP ) { + data++; + continue; + } + switch ( kind ) { + case TCP_OPTION_MSS: + options->mssopt = data; + break; + case TCP_OPTION_TS: + options->tsopt = data; + break; + default: + DBGC ( tcp, "TCP %p received unknown option %d\n", + tcp, kind ); + break; + } + data += option->length; + } +} + /** * Handle TCP received SYN * * @v tcp TCP connection * @v seq SEQ value (in host-endian order) + * @v options TCP options * @ret rc Return status code */ -static int tcp_rx_syn ( struct tcp_connection *tcp, uint32_t seq ) { +static int tcp_rx_syn ( struct tcp_connection *tcp, uint32_t seq, + struct tcp_options *options ) { /* Synchronise sequence numbers on first SYN */ - if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) + if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) { tcp->rcv_ack = seq; + if ( options->tsopt ) + tcp->timestamps = 1; + } /* Ignore duplicate SYN */ if ( ( tcp->rcv_ack - seq ) > 0 ) @@ -776,6 +837,7 @@ static int tcp_rx ( struct io_buffer *iobuf, uint16_t pshdr_csum ) { struct tcp_header *tcphdr = iobuf->data; struct tcp_connection *tcp; + struct tcp_options options; unsigned int hlen; uint16_t csum; uint32_t start_seq; @@ -820,6 +882,8 @@ static int tcp_rx ( struct io_buffer *iobuf, ack = ntohl ( tcphdr->ack ); win = ntohs ( tcphdr->win ); flags = tcphdr->flags; + tcp_rx_opts ( tcp, ( ( ( void * ) tcphdr ) + sizeof ( *tcphdr ) ), + ( hlen - sizeof ( *tcphdr ) ), &options ); iob_pull ( iobuf, hlen ); len = iob_len ( iobuf ); @@ -849,7 +913,7 @@ static int tcp_rx ( struct io_buffer *iobuf, /* Handle SYN, if present */ if ( flags & TCP_SYN ) { - tcp_rx_syn ( tcp, seq ); + tcp_rx_syn ( tcp, seq, &options ); seq++; } @@ -869,6 +933,10 @@ static int tcp_rx ( struct io_buffer *iobuf, seq++; } + /* Update timestamp, if present and applicable */ + if ( ( seq == tcp->rcv_ack ) && options.tsopt ) + tcp->ts_recent = ntohl ( options.tsopt->tsval ); + /* Dump out any state change as a result of the received packet */ tcp_dump_state ( tcp );