|
@@ -87,6 +87,16 @@ struct tcp_connection {
|
87
|
87
|
* Equivalent to TS.Recent in RFC 1323 terminology.
|
88
|
88
|
*/
|
89
|
89
|
uint32_t ts_recent;
|
|
90
|
+ /** Send window scale
|
|
91
|
+ *
|
|
92
|
+ * Equivalent to Snd.Wind.Scale in RFC 1323 terminology
|
|
93
|
+ */
|
|
94
|
+ uint8_t snd_win_scale;
|
|
95
|
+ /** Receive window scale
|
|
96
|
+ *
|
|
97
|
+ * Equivalent to Rcv.Wind.Scale in RFC 1323 terminology
|
|
98
|
+ */
|
|
99
|
+ uint8_t rcv_win_scale;
|
90
|
100
|
|
91
|
101
|
/** Transmit queue */
|
92
|
102
|
struct list_head tx_queue;
|
|
@@ -490,6 +500,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
|
490
|
500
|
struct io_buffer *iobuf;
|
491
|
501
|
struct tcp_header *tcphdr;
|
492
|
502
|
struct tcp_mss_option *mssopt;
|
|
503
|
+ struct tcp_window_scale_padded_option *wsopt;
|
493
|
504
|
struct tcp_timestamp_padded_option *tsopt;
|
494
|
505
|
void *payload;
|
495
|
506
|
unsigned int flags;
|
|
@@ -497,6 +508,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
|
497
|
508
|
uint32_t seq_len;
|
498
|
509
|
uint32_t app_win;
|
499
|
510
|
uint32_t max_rcv_win;
|
|
511
|
+ uint32_t max_representable_win;
|
500
|
512
|
int rc;
|
501
|
513
|
|
502
|
514
|
/* If retransmission timer is already running, do nothing */
|
|
@@ -551,6 +563,9 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
|
551
|
563
|
app_win = xfer_window ( &tcp->xfer );
|
552
|
564
|
if ( max_rcv_win > app_win )
|
553
|
565
|
max_rcv_win = app_win;
|
|
566
|
+ max_representable_win = ( 0xffff << tcp->rcv_win_scale );
|
|
567
|
+ if ( max_rcv_win > max_representable_win )
|
|
568
|
+ max_rcv_win = max_representable_win;
|
554
|
569
|
max_rcv_win &= ~0x03; /* Keep everything dword-aligned */
|
555
|
570
|
if ( tcp->rcv_win < max_rcv_win )
|
556
|
571
|
tcp->rcv_win = max_rcv_win;
|
|
@@ -562,6 +577,11 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
|
562
|
577
|
mssopt->kind = TCP_OPTION_MSS;
|
563
|
578
|
mssopt->length = sizeof ( *mssopt );
|
564
|
579
|
mssopt->mss = htons ( TCP_MSS );
|
|
580
|
+ wsopt = iob_push ( iobuf, sizeof ( *wsopt ) );
|
|
581
|
+ wsopt->nop = TCP_OPTION_NOP;
|
|
582
|
+ wsopt->wsopt.kind = TCP_OPTION_WS;
|
|
583
|
+ wsopt->wsopt.length = sizeof ( wsopt->wsopt );
|
|
584
|
+ wsopt->wsopt.scale = TCP_RX_WINDOW_SCALE;
|
565
|
585
|
}
|
566
|
586
|
if ( ( flags & TCP_SYN ) || ( tcp->flags & TCP_TS_ENABLED ) ) {
|
567
|
587
|
tsopt = iob_push ( iobuf, sizeof ( *tsopt ) );
|
|
@@ -581,7 +601,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
|
581
|
601
|
tcphdr->ack = htonl ( tcp->rcv_ack );
|
582
|
602
|
tcphdr->hlen = ( ( payload - iobuf->data ) << 2 );
|
583
|
603
|
tcphdr->flags = flags;
|
584
|
|
- tcphdr->win = htons ( tcp->rcv_win );
|
|
604
|
+ tcphdr->win = htons ( tcp->rcv_win >> tcp->rcv_win_scale );
|
585
|
605
|
tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) );
|
586
|
606
|
|
587
|
607
|
/* Dump header */
|
|
@@ -769,6 +789,9 @@ static void tcp_rx_opts ( struct tcp_connection *tcp, const void *data,
|
769
|
789
|
case TCP_OPTION_MSS:
|
770
|
790
|
options->mssopt = data;
|
771
|
791
|
break;
|
|
792
|
+ case TCP_OPTION_WS:
|
|
793
|
+ options->wsopt = data;
|
|
794
|
+ break;
|
772
|
795
|
case TCP_OPTION_TS:
|
773
|
796
|
options->tsopt = data;
|
774
|
797
|
break;
|
|
@@ -825,6 +848,10 @@ static int tcp_rx_syn ( struct tcp_connection *tcp, uint32_t seq,
|
825
|
848
|
tcp->rcv_ack = seq;
|
826
|
849
|
if ( options->tsopt )
|
827
|
850
|
tcp->flags |= TCP_TS_ENABLED;
|
|
851
|
+ if ( options->wsopt ) {
|
|
852
|
+ tcp->snd_win_scale = options->wsopt->scale;
|
|
853
|
+ tcp->rcv_win_scale = TCP_RX_WINDOW_SCALE;
|
|
854
|
+ }
|
828
|
855
|
}
|
829
|
856
|
|
830
|
857
|
/* Ignore duplicate SYN */
|
|
@@ -1168,7 +1195,7 @@ static int tcp_rx ( struct io_buffer *iobuf,
|
1168
|
1195
|
tcp = tcp_demux ( ntohs ( tcphdr->dest ) );
|
1169
|
1196
|
seq = ntohl ( tcphdr->seq );
|
1170
|
1197
|
ack = ntohl ( tcphdr->ack );
|
1171
|
|
- win = ntohs ( tcphdr->win );
|
|
1198
|
+ win = ( ntohs ( tcphdr->win ) << tcp->snd_win_scale );
|
1172
|
1199
|
flags = tcphdr->flags;
|
1173
|
1200
|
tcp_rx_opts ( tcp, ( ( ( void * ) tcphdr ) + sizeof ( *tcphdr ) ),
|
1174
|
1201
|
( hlen - sizeof ( *tcphdr ) ), &options );
|