TCP_XFER_CLOSED = 0x0001,
/** TCP timestamps are enabled */
TCP_TS_ENABLED = 0x0002,
+ /** TCP acknowledgement is pending */
+ TCP_ACK_PENDING = 0x0004,
};
/**
* Transmit any outstanding data
*
* @v tcp TCP connection
- * @v force_send Force sending of packet
*
* Transmits any outstanding data on the connection.
*
* will have been started if necessary, and so the stack will
* eventually attempt to retransmit the failed packet.
*/
-static int tcp_xmit ( struct tcp_connection *tcp, int force_send ) {
+static int tcp_xmit ( struct tcp_connection *tcp ) {
struct io_buffer *iobuf;
struct tcp_header *tcphdr;
struct tcp_mss_option *mssopt;
tcp->snd_sent = seq_len;
/* If we have nothing to transmit, stop now */
- if ( ( seq_len == 0 ) && ! force_send )
+ if ( ( seq_len == 0 ) && ! ( tcp->flags & TCP_ACK_PENDING ) )
return 0;
/* If we are transmitting anything that requires
return rc;
}
+ /* Clear ACK-pending flag */
+ tcp->flags &= ~TCP_ACK_PENDING;
+
return 0;
}
tcp_close ( tcp, -ETIMEDOUT );
} else {
/* Otherwise, retransmit the packet */
- tcp_xmit ( tcp, 0 );
+ tcp_xmit ( tcp );
}
}
} else {
tcp->rcv_win = 0;
}
+ tcp->flags |= TCP_ACK_PENDING;
}
/**
struct tcp_options options;
size_t hlen;
uint16_t csum;
- uint32_t start_seq;
uint32_t seq;
uint32_t ack;
uint32_t win;
/* Parse parameters from header and strip header */
tcp = tcp_demux ( ntohs ( tcphdr->dest ) );
- start_seq = seq = ntohl ( tcphdr->seq );
+ seq = ntohl ( tcphdr->seq );
ack = ntohl ( tcphdr->ack );
win = ntohs ( tcphdr->win );
flags = tcphdr->flags;
}
}
+ /* Force an ACK if this packet is out of order */
+ if ( ( tcp->tcp_state & TCP_STATE_RCVD ( TCP_SYN ) ) &&
+ ( seq != tcp->rcv_ack ) ) {
+ tcp->flags |= TCP_ACK_PENDING;
+ }
+
/* Handle SYN, if present */
if ( flags & TCP_SYN ) {
tcp_rx_syn ( tcp, seq, &options );
/* Dump out any state change as a result of the received packet */
tcp_dump_state ( tcp );
- /* Send out any pending data. We force sending a reply if either
- *
- * a) the peer is expecting an ACK (i.e. consumed sequence space), or
- * b) either end of the packet was outside the receive window
- *
- * Case (b) enables us to support TCP keepalives using
- * zero-length packets, which we would otherwise ignore. Note
- * that for case (b), we need *only* consider zero-length
- * packets, since non-zero-length packets will already be
- * caught by case (a).
- */
- tcp_xmit ( tcp, ( ( start_seq != seq ) ||
- ( ( seq - tcp->rcv_ack ) > tcp->rcv_win ) ) );
+ /* Send out any pending data */
+ tcp_xmit ( tcp );
/* If this packet was the last we expect to receive, set up
* timer to expire and cause the connection to be freed.
tcp_close ( tcp, rc );
/* Transmit FIN, if possible */
- tcp_xmit ( tcp, 0 );
+ tcp_xmit ( tcp );
}
/**
list_add_tail ( &iobuf->list, &tcp->queue );
/* Transmit data, if possible */
- tcp_xmit ( tcp, 0 );
+ tcp_xmit ( tcp );
return 0;
}