|
@@ -97,6 +97,8 @@ struct tcp_connection {
|
97
|
97
|
* Equivalent to Rcv.Wind.Scale in RFC 1323 terminology
|
98
|
98
|
*/
|
99
|
99
|
uint8_t rcv_win_scale;
|
|
100
|
+ /** Maximum receive window */
|
|
101
|
+ uint32_t max_rcv_win;
|
100
|
102
|
|
101
|
103
|
/** Transmit queue */
|
102
|
104
|
struct list_head tx_queue;
|
|
@@ -295,6 +297,7 @@ static int tcp_open ( struct interface *xfer, struct sockaddr *peer,
|
295
|
297
|
tcp->tcp_state = TCP_STATE_SENT ( TCP_SYN );
|
296
|
298
|
tcp_dump_state ( tcp );
|
297
|
299
|
tcp->snd_seq = random();
|
|
300
|
+ tcp->max_rcv_win = TCP_MAX_WINDOW_SIZE;
|
298
|
301
|
INIT_LIST_HEAD ( &tcp->tx_queue );
|
299
|
302
|
INIT_LIST_HEAD ( &tcp->rx_queue );
|
300
|
303
|
memcpy ( &tcp->peer, st_peer, sizeof ( tcp->peer ) );
|
|
@@ -557,9 +560,7 @@ static int tcp_xmit ( struct tcp_connection *tcp ) {
|
557
|
560
|
tcp_process_tx_queue ( tcp, len, iobuf, 0 );
|
558
|
561
|
|
559
|
562
|
/* Expand receive window if possible */
|
560
|
|
- max_rcv_win = ( ( freemem * 3 ) / 4 );
|
561
|
|
- if ( max_rcv_win > TCP_MAX_WINDOW_SIZE )
|
562
|
|
- max_rcv_win = TCP_MAX_WINDOW_SIZE;
|
|
563
|
+ max_rcv_win = tcp->max_rcv_win;
|
563
|
564
|
app_win = xfer_window ( &tcp->xfer );
|
564
|
565
|
if ( max_rcv_win > app_win )
|
565
|
566
|
max_rcv_win = app_win;
|
|
@@ -1299,13 +1300,29 @@ struct tcpip_protocol tcp_protocol __tcpip_protocol = {
|
1299
|
1300
|
static unsigned int tcp_discard ( void ) {
|
1300
|
1301
|
struct tcp_connection *tcp;
|
1301
|
1302
|
struct io_buffer *iobuf;
|
|
1303
|
+ struct tcp_rx_queued_header *tcpqhdr;
|
|
1304
|
+ uint32_t max_win;
|
1302
|
1305
|
unsigned int discarded = 0;
|
1303
|
1306
|
|
1304
|
1307
|
/* Try to drop one queued RX packet from each connection */
|
1305
|
1308
|
list_for_each_entry ( tcp, &tcp_conns, list ) {
|
1306
|
1309
|
list_for_each_entry_reverse ( iobuf, &tcp->rx_queue, list ) {
|
|
1310
|
+
|
|
1311
|
+ /* Limit window to prevent future discards */
|
|
1312
|
+ tcpqhdr = iobuf->data;
|
|
1313
|
+ max_win = ( tcpqhdr->seq - tcp->rcv_ack );
|
|
1314
|
+ if ( max_win < tcp->max_rcv_win ) {
|
|
1315
|
+ DBGC ( tcp, "TCP %p reducing maximum window "
|
|
1316
|
+ "from %d to %d\n",
|
|
1317
|
+ tcp, tcp->max_rcv_win, max_win );
|
|
1318
|
+ tcp->max_rcv_win = max_win;
|
|
1319
|
+ }
|
|
1320
|
+
|
|
1321
|
+ /* Remove packet from queue */
|
1307
|
1322
|
list_del ( &iobuf->list );
|
1308
|
1323
|
free_iob ( iobuf );
|
|
1324
|
+
|
|
1325
|
+ /* Report discard */
|
1309
|
1326
|
discarded++;
|
1310
|
1327
|
break;
|
1311
|
1328
|
}
|