|  | @@ -65,6 +65,13 @@ struct tcp_connection {
 | 
		
	
		
			
			| 65 | 65 |  	 * Equivalent to RCV.NXT in RFC 793 terminology.
 | 
		
	
		
			
			| 66 | 66 |  	 */
 | 
		
	
		
			
			| 67 | 67 |  	uint32_t rcv_ack;
 | 
		
	
		
			
			|  | 68 | +	/** Most recent received timestamp
 | 
		
	
		
			
			|  | 69 | +	 *
 | 
		
	
		
			
			|  | 70 | +	 * Equivalent to TS.Recent in RFC 1323 terminology.
 | 
		
	
		
			
			|  | 71 | +	 */
 | 
		
	
		
			
			|  | 72 | +	uint32_t ts_recent;
 | 
		
	
		
			
			|  | 73 | +	/** Timestamps enabled */
 | 
		
	
		
			
			|  | 74 | +	int timestamps;
 | 
		
	
		
			
			| 68 | 75 |  
 | 
		
	
		
			
			| 69 | 76 |  	/** Transmit queue */
 | 
		
	
		
			
			| 70 | 77 |  	struct list_head queue;
 | 
		
	
	
		
			
			|  | @@ -381,6 +388,7 @@ static int tcp_xmit ( struct tcp_connection *tcp, int force_send ) {
 | 
		
	
		
			
			| 381 | 388 |  	struct io_buffer *iobuf;
 | 
		
	
		
			
			| 382 | 389 |  	struct tcp_header *tcphdr;
 | 
		
	
		
			
			| 383 | 390 |  	struct tcp_mss_option *mssopt;
 | 
		
	
		
			
			|  | 391 | +	struct tcp_timestamp_padded_option *tsopt;
 | 
		
	
		
			
			| 384 | 392 |  	void *payload;
 | 
		
	
		
			
			| 385 | 393 |  	unsigned int flags;
 | 
		
	
		
			
			| 386 | 394 |  	size_t len = 0;
 | 
		
	
	
		
			
			|  | @@ -449,6 +457,14 @@ static int tcp_xmit ( struct tcp_connection *tcp, int force_send ) {
 | 
		
	
		
			
			| 449 | 457 |  		mssopt->length = sizeof ( *mssopt );
 | 
		
	
		
			
			| 450 | 458 |  		mssopt->mss = htons ( TCP_MSS );
 | 
		
	
		
			
			| 451 | 459 |  	}
 | 
		
	
		
			
			|  | 460 | +	if ( ( flags & TCP_SYN ) || tcp->timestamps ) {
 | 
		
	
		
			
			|  | 461 | +		tsopt = iob_push ( iobuf, sizeof ( *tsopt ) );
 | 
		
	
		
			
			|  | 462 | +		memset ( tsopt->nop, TCP_OPTION_NOP, sizeof ( tsopt->nop ) );
 | 
		
	
		
			
			|  | 463 | +		tsopt->tsopt.kind = TCP_OPTION_TS;
 | 
		
	
		
			
			|  | 464 | +		tsopt->tsopt.length = sizeof ( tsopt->tsopt );
 | 
		
	
		
			
			|  | 465 | +		tsopt->tsopt.tsval = ntohl ( currticks() );
 | 
		
	
		
			
			|  | 466 | +		tsopt->tsopt.tsecr = ntohl ( tcp->ts_recent );
 | 
		
	
		
			
			|  | 467 | +	}
 | 
		
	
		
			
			| 452 | 468 |  	tcphdr = iob_push ( iobuf, sizeof ( *tcphdr ) );
 | 
		
	
		
			
			| 453 | 469 |  	memset ( tcphdr, 0, sizeof ( *tcphdr ) );
 | 
		
	
		
			
			| 454 | 470 |  	tcphdr->src = tcp->local_port;
 | 
		
	
	
		
			
			|  | @@ -594,18 +610,63 @@ static struct tcp_connection * tcp_demux ( unsigned int local_port ) {
 | 
		
	
		
			
			| 594 | 610 |  	return NULL;
 | 
		
	
		
			
			| 595 | 611 |  }
 | 
		
	
		
			
			| 596 | 612 |  
 | 
		
	
		
			
			|  | 613 | +/**
 | 
		
	
		
			
			|  | 614 | + * Parse TCP received options
 | 
		
	
		
			
			|  | 615 | + *
 | 
		
	
		
			
			|  | 616 | + * @v tcp		TCP connection
 | 
		
	
		
			
			|  | 617 | + * @v data		Raw options data
 | 
		
	
		
			
			|  | 618 | + * @v len		Raw options length
 | 
		
	
		
			
			|  | 619 | + * @v options		Options structure to fill in
 | 
		
	
		
			
			|  | 620 | + */
 | 
		
	
		
			
			|  | 621 | +static void tcp_rx_opts ( struct tcp_connection *tcp, const void *data,
 | 
		
	
		
			
			|  | 622 | +			  size_t len, struct tcp_options *options ) {
 | 
		
	
		
			
			|  | 623 | +	const void *end = ( data + len );
 | 
		
	
		
			
			|  | 624 | +	const struct tcp_option *option;
 | 
		
	
		
			
			|  | 625 | +	unsigned int kind;
 | 
		
	
		
			
			|  | 626 | +
 | 
		
	
		
			
			|  | 627 | +	memset ( options, 0, sizeof ( *options ) );
 | 
		
	
		
			
			|  | 628 | +	while ( data < end ) {
 | 
		
	
		
			
			|  | 629 | +		option = data;
 | 
		
	
		
			
			|  | 630 | +		kind = option->kind;
 | 
		
	
		
			
			|  | 631 | +		if ( kind == TCP_OPTION_END )
 | 
		
	
		
			
			|  | 632 | +			return;
 | 
		
	
		
			
			|  | 633 | +		if ( kind == TCP_OPTION_NOP ) {
 | 
		
	
		
			
			|  | 634 | +			data++;
 | 
		
	
		
			
			|  | 635 | +			continue;
 | 
		
	
		
			
			|  | 636 | +		}
 | 
		
	
		
			
			|  | 637 | +		switch ( kind ) {
 | 
		
	
		
			
			|  | 638 | +		case TCP_OPTION_MSS:
 | 
		
	
		
			
			|  | 639 | +			options->mssopt = data;
 | 
		
	
		
			
			|  | 640 | +			break;
 | 
		
	
		
			
			|  | 641 | +		case TCP_OPTION_TS:
 | 
		
	
		
			
			|  | 642 | +			options->tsopt = data;
 | 
		
	
		
			
			|  | 643 | +			break;
 | 
		
	
		
			
			|  | 644 | +		default:
 | 
		
	
		
			
			|  | 645 | +			DBGC ( tcp, "TCP %p received unknown option %d\n",
 | 
		
	
		
			
			|  | 646 | +			       tcp, kind );
 | 
		
	
		
			
			|  | 647 | +			break;
 | 
		
	
		
			
			|  | 648 | +		}
 | 
		
	
		
			
			|  | 649 | +		data += option->length;
 | 
		
	
		
			
			|  | 650 | +	}
 | 
		
	
		
			
			|  | 651 | +}
 | 
		
	
		
			
			|  | 652 | +
 | 
		
	
		
			
			| 597 | 653 |  /**
 | 
		
	
		
			
			| 598 | 654 |   * Handle TCP received SYN
 | 
		
	
		
			
			| 599 | 655 |   *
 | 
		
	
		
			
			| 600 | 656 |   * @v tcp		TCP connection
 | 
		
	
		
			
			| 601 | 657 |   * @v seq		SEQ value (in host-endian order)
 | 
		
	
		
			
			|  | 658 | + * @v options		TCP options
 | 
		
	
		
			
			| 602 | 659 |   * @ret rc		Return status code
 | 
		
	
		
			
			| 603 | 660 |   */
 | 
		
	
		
			
			| 604 |  | -static int tcp_rx_syn ( struct tcp_connection *tcp, uint32_t seq ) {
 | 
		
	
		
			
			|  | 661 | +static int tcp_rx_syn ( struct tcp_connection *tcp, uint32_t seq,
 | 
		
	
		
			
			|  | 662 | +			struct tcp_options *options ) {
 | 
		
	
		
			
			| 605 | 663 |  
 | 
		
	
		
			
			| 606 | 664 |  	/* Synchronise sequence numbers on first SYN */
 | 
		
	
		
			
			| 607 |  | -	if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) )
 | 
		
	
		
			
			|  | 665 | +	if ( ! ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) ) {
 | 
		
	
		
			
			| 608 | 666 |  		tcp->rcv_ack = seq;
 | 
		
	
		
			
			|  | 667 | +		if ( options->tsopt )
 | 
		
	
		
			
			|  | 668 | +			tcp->timestamps = 1;
 | 
		
	
		
			
			|  | 669 | +	}
 | 
		
	
		
			
			| 609 | 670 |  
 | 
		
	
		
			
			| 610 | 671 |  	/* Ignore duplicate SYN */
 | 
		
	
		
			
			| 611 | 672 |  	if ( ( tcp->rcv_ack - seq ) > 0 )
 | 
		
	
	
		
			
			|  | @@ -776,6 +837,7 @@ static int tcp_rx ( struct io_buffer *iobuf,
 | 
		
	
		
			
			| 776 | 837 |  		    uint16_t pshdr_csum ) {
 | 
		
	
		
			
			| 777 | 838 |  	struct tcp_header *tcphdr = iobuf->data;
 | 
		
	
		
			
			| 778 | 839 |  	struct tcp_connection *tcp;
 | 
		
	
		
			
			|  | 840 | +	struct tcp_options options;
 | 
		
	
		
			
			| 779 | 841 |  	unsigned int hlen;
 | 
		
	
		
			
			| 780 | 842 |  	uint16_t csum;
 | 
		
	
		
			
			| 781 | 843 |  	uint32_t start_seq;
 | 
		
	
	
		
			
			|  | @@ -820,6 +882,8 @@ static int tcp_rx ( struct io_buffer *iobuf,
 | 
		
	
		
			
			| 820 | 882 |  	ack = ntohl ( tcphdr->ack );
 | 
		
	
		
			
			| 821 | 883 |  	win = ntohs ( tcphdr->win );
 | 
		
	
		
			
			| 822 | 884 |  	flags = tcphdr->flags;
 | 
		
	
		
			
			|  | 885 | +	tcp_rx_opts ( tcp, ( ( ( void * ) tcphdr ) + sizeof ( *tcphdr ) ),
 | 
		
	
		
			
			|  | 886 | +		      ( hlen - sizeof ( *tcphdr ) ), &options );
 | 
		
	
		
			
			| 823 | 887 |  	iob_pull ( iobuf, hlen );
 | 
		
	
		
			
			| 824 | 888 |  	len = iob_len ( iobuf );
 | 
		
	
		
			
			| 825 | 889 |  
 | 
		
	
	
		
			
			|  | @@ -849,7 +913,7 @@ static int tcp_rx ( struct io_buffer *iobuf,
 | 
		
	
		
			
			| 849 | 913 |  
 | 
		
	
		
			
			| 850 | 914 |  	/* Handle SYN, if present */
 | 
		
	
		
			
			| 851 | 915 |  	if ( flags & TCP_SYN ) {
 | 
		
	
		
			
			| 852 |  | -		tcp_rx_syn ( tcp, seq );
 | 
		
	
		
			
			|  | 916 | +		tcp_rx_syn ( tcp, seq, &options );
 | 
		
	
		
			
			| 853 | 917 |  		seq++;
 | 
		
	
		
			
			| 854 | 918 |  	}
 | 
		
	
		
			
			| 855 | 919 |  
 | 
		
	
	
		
			
			|  | @@ -869,6 +933,10 @@ static int tcp_rx ( struct io_buffer *iobuf,
 | 
		
	
		
			
			| 869 | 933 |  		seq++;
 | 
		
	
		
			
			| 870 | 934 |  	}
 | 
		
	
		
			
			| 871 | 935 |  
 | 
		
	
		
			
			|  | 936 | +	/* Update timestamp, if present and applicable */
 | 
		
	
		
			
			|  | 937 | +	if ( ( seq == tcp->rcv_ack ) && options.tsopt )
 | 
		
	
		
			
			|  | 938 | +		tcp->ts_recent = ntohl ( options.tsopt->tsval );
 | 
		
	
		
			
			|  | 939 | +
 | 
		
	
		
			
			| 872 | 940 |  	/* Dump out any state change as a result of the received packet */
 | 
		
	
		
			
			| 873 | 941 |  	tcp_dump_state ( tcp );
 | 
		
	
		
			
			| 874 | 942 |  
 |