|
@@ -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
|
|