implemented; should be done at some point.)
*/
#define TCP_MAX_WINDOW_SIZE ( 65536 - 4 )
*/
#define TCP_MAX_WINDOW_SIZE ( 65536 - 4 )
+/**
+ * Path MTU
+ *
+ * We really ought to implement Path MTU discovery. Until we do,
+ * anything with a path MTU greater than this may fail.
+ */
+#define TCP_PATH_MTU 1460
+
/**
* Advertised TCP MSS
*
/**
* Advertised TCP MSS
*
***************************************************************************
*/
***************************************************************************
*/
+/**
+ * Calculate transmission window
+ *
+ * @v tcp TCP connection
+ * @ret len Maximum length that can be sent in a single packet
+ */
+static size_t tcp_xmit_win ( struct tcp_connection *tcp ) {
+ size_t len;
+
+ /* Not ready if we're not in a suitable connection state */
+ if ( ! TCP_CAN_SEND_DATA ( tcp->tcp_state ) )
+ return 0;
+
+ /* Length is the minimum of the receiver's window and the path MTU */
+ len = tcp->snd_win;
+ if ( len > TCP_PATH_MTU )
+ len = TCP_PATH_MTU;
+
+ return len;
+}
+
/**
* Process TCP transmit queue
*
/**
* Process TCP transmit queue
*
unsigned int flags;
size_t len = 0;
size_t seq_len;
unsigned int flags;
size_t len = 0;
size_t seq_len;
- size_t app_window;
- size_t window;
+ size_t app_win;
+ size_t rcv_win;
int rc;
/* If retransmission timer is already running, do nothing */
int rc;
/* If retransmission timer is already running, do nothing */
* lengths that we wish to transmit.
*/
if ( TCP_CAN_SEND_DATA ( tcp->tcp_state ) ) {
* lengths that we wish to transmit.
*/
if ( TCP_CAN_SEND_DATA ( tcp->tcp_state ) ) {
- len = tcp_process_queue ( tcp, tcp->snd_win, NULL, 0 );
+ len = tcp_process_queue ( tcp, tcp_xmit_win ( tcp ),
+ NULL, 0 );
}
seq_len = len;
flags = TCP_FLAGS_SENDING ( tcp->tcp_state );
}
seq_len = len;
flags = TCP_FLAGS_SENDING ( tcp->tcp_state );
tcp_process_queue ( tcp, len, iobuf, 0 );
/* Estimate window size */
tcp_process_queue ( tcp, len, iobuf, 0 );
/* Estimate window size */
- window = ( ( freemem * 3 ) / 4 );
- if ( window > TCP_MAX_WINDOW_SIZE )
- window = TCP_MAX_WINDOW_SIZE;
- app_window = xfer_window ( &tcp->xfer );
- if ( window > app_window )
- window = app_window;
- window &= ~0x03; /* Keep everything dword-aligned */
+ rcv_win = ( ( freemem * 3 ) / 4 );
+ if ( rcv_win > TCP_MAX_WINDOW_SIZE )
+ rcv_win = TCP_MAX_WINDOW_SIZE;
+ app_win = xfer_window ( &tcp->xfer );
+ if ( rcv_win > app_win )
+ rcv_win = app_win;
+ rcv_win &= ~0x03; /* Keep everything dword-aligned */
/* Fill up the TCP header */
payload = iobuf->data;
/* Fill up the TCP header */
payload = iobuf->data;
tcphdr->ack = htonl ( tcp->rcv_ack );
tcphdr->hlen = ( ( payload - iobuf->data ) << 2 );
tcphdr->flags = flags;
tcphdr->ack = htonl ( tcp->rcv_ack );
tcphdr->hlen = ( ( payload - iobuf->data ) << 2 );
tcphdr->flags = flags;
- tcphdr->win = htons ( window );
+ tcphdr->win = htons ( rcv_win );
tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) );
/* Dump header */
tcphdr->csum = tcpip_chksum ( iobuf->data, iob_len ( iobuf ) );
/* Dump header */
struct tcp_connection *tcp =
container_of ( xfer, struct tcp_connection, xfer );
struct tcp_connection *tcp =
container_of ( xfer, struct tcp_connection, xfer );
- /* Not ready if we're not in a suitable connection state */
- if ( ! TCP_CAN_SEND_DATA ( tcp->tcp_state ) )
- return 0;
-
/* Not ready if data queue is non-empty. This imposes a limit
* of only one unACKed packet in the TX queue at any time; we
* do this to conserve memory usage.
/* Not ready if data queue is non-empty. This imposes a limit
* of only one unACKed packet in the TX queue at any time; we
* do this to conserve memory usage.
return 0;
/* Return TCP window length */
return 0;
/* Return TCP window length */
+ return tcp_xmit_win ( tcp );