mirror of https://github.com/ipxe/ipxe.git
Add support for TCP timestamps
parent
eb530845d4
commit
096fa94f0c
|
@ -27,18 +27,59 @@ struct tcp_header {
|
||||||
uint16_t urg; /* Urgent pointer */
|
uint16_t urg; /* Urgent pointer */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/** @defgroup tcpopts TCP options
|
||||||
* TCP MSS option
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** 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 {
|
struct tcp_mss_option {
|
||||||
uint8_t kind;
|
uint8_t kind;
|
||||||
uint8_t length;
|
uint8_t length;
|
||||||
uint16_t mss;
|
uint16_t mss;
|
||||||
};
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
/** Code for the TCP MSS option */
|
/** Code for the TCP MSS option */
|
||||||
#define TCP_OPTION_MSS 2
|
#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
|
* TCP flags
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -65,6 +65,13 @@ struct tcp_connection {
|
||||||
* Equivalent to RCV.NXT in RFC 793 terminology.
|
* Equivalent to RCV.NXT in RFC 793 terminology.
|
||||||
*/
|
*/
|
||||||
uint32_t rcv_ack;
|
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 */
|
/** Transmit queue */
|
||||||
struct list_head 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 io_buffer *iobuf;
|
||||||
struct tcp_header *tcphdr;
|
struct tcp_header *tcphdr;
|
||||||
struct tcp_mss_option *mssopt;
|
struct tcp_mss_option *mssopt;
|
||||||
|
struct tcp_timestamp_padded_option *tsopt;
|
||||||
void *payload;
|
void *payload;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
@ -449,6 +457,14 @@ static int tcp_xmit ( struct tcp_connection *tcp, int force_send ) {
|
||||||
mssopt->length = sizeof ( *mssopt );
|
mssopt->length = sizeof ( *mssopt );
|
||||||
mssopt->mss = htons ( TCP_MSS );
|
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 ) );
|
tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) );
|
||||||
memset ( tcphdr, 0, sizeof ( *tcphdr ) );
|
memset ( tcphdr, 0, sizeof ( *tcphdr ) );
|
||||||
tcphdr->src = tcp->local_port;
|
tcphdr->src = tcp->local_port;
|
||||||
|
@ -594,18 +610,63 @@ static struct tcp_connection * tcp_demux ( unsigned int local_port ) {
|
||||||
return NULL;
|
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
|
* Handle TCP received SYN
|
||||||
*
|
*
|
||||||
* @v tcp TCP connection
|
* @v tcp TCP connection
|
||||||
* @v seq SEQ value (in host-endian order)
|
* @v seq SEQ value (in host-endian order)
|
||||||
|
* @v options TCP options
|
||||||
* @ret rc Return status code
|
* @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 */
|
/* 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;
|
tcp->rcv_ack = seq;
|
||||||
|
if ( options->tsopt )
|
||||||
|
tcp->timestamps = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Ignore duplicate SYN */
|
/* Ignore duplicate SYN */
|
||||||
if ( ( tcp->rcv_ack - seq ) > 0 )
|
if ( ( tcp->rcv_ack - seq ) > 0 )
|
||||||
|
@ -776,6 +837,7 @@ static int tcp_rx ( struct io_buffer *iobuf,
|
||||||
uint16_t pshdr_csum ) {
|
uint16_t pshdr_csum ) {
|
||||||
struct tcp_header *tcphdr = iobuf->data;
|
struct tcp_header *tcphdr = iobuf->data;
|
||||||
struct tcp_connection *tcp;
|
struct tcp_connection *tcp;
|
||||||
|
struct tcp_options options;
|
||||||
unsigned int hlen;
|
unsigned int hlen;
|
||||||
uint16_t csum;
|
uint16_t csum;
|
||||||
uint32_t start_seq;
|
uint32_t start_seq;
|
||||||
|
@ -820,6 +882,8 @@ static int tcp_rx ( struct io_buffer *iobuf,
|
||||||
ack = ntohl ( tcphdr->ack );
|
ack = ntohl ( tcphdr->ack );
|
||||||
win = ntohs ( tcphdr->win );
|
win = ntohs ( tcphdr->win );
|
||||||
flags = tcphdr->flags;
|
flags = tcphdr->flags;
|
||||||
|
tcp_rx_opts ( tcp, ( ( ( void * ) tcphdr ) + sizeof ( *tcphdr ) ),
|
||||||
|
( hlen - sizeof ( *tcphdr ) ), &options );
|
||||||
iob_pull ( iobuf, hlen );
|
iob_pull ( iobuf, hlen );
|
||||||
len = iob_len ( iobuf );
|
len = iob_len ( iobuf );
|
||||||
|
|
||||||
|
@ -849,7 +913,7 @@ static int tcp_rx ( struct io_buffer *iobuf,
|
||||||
|
|
||||||
/* Handle SYN, if present */
|
/* Handle SYN, if present */
|
||||||
if ( flags & TCP_SYN ) {
|
if ( flags & TCP_SYN ) {
|
||||||
tcp_rx_syn ( tcp, seq );
|
tcp_rx_syn ( tcp, seq, &options );
|
||||||
seq++;
|
seq++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -869,6 +933,10 @@ static int tcp_rx ( struct io_buffer *iobuf,
|
||||||
seq++;
|
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 */
|
/* Dump out any state change as a result of the received packet */
|
||||||
tcp_dump_state ( tcp );
|
tcp_dump_state ( tcp );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue