Commit 1ddb9f94 authored by Andy Ross's avatar Andy Ross Committed by Jukka Rissanen
Browse files

net: tcp: Rework ACK behavior



TCP ACK values aren't known until packet transmission time.  Set the
ACK value then, logging the last one sent for later comparison.

Note that this allows us to effect a neat trick: if your
net_context_send() callback produces a synchronous reply on the
stream, Zephyr can include the ACK in the sent data and not have to
transmit a separate packet.  Traditional OSes with internal queing and
a syscall interface can't do this.

Change-Id: If8b8546dac6163d763b8f8dd75865192f2eb302a
Signed-off-by: default avatarAndy Ross <andrew.j.ross@intel.com>
Signed-off-by: default avatarLeandro Pereira <leandro.pereira@intel.com>
parent a93779b0
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -643,6 +643,13 @@ static inline int send_ack(struct net_context *context,
	struct net_buf *buf = NULL;
	int ret;

	/* Something (e.g. a data transmission under the user
	 * callback) already sent the ACK, no need
	 */
	if (context->tcp->send_ack == context->tcp->sent_ack) {
		return 0;
	}

	ret = net_tcp_prepare_ack(context->tcp, remote, &buf);
	if (ret) {
		return ret;
@@ -650,7 +657,7 @@ static inline int send_ack(struct net_context *context,

	net_tcp_print_send_info("ACK", buf, NET_TCP_BUF(buf)->dst_port);

	ret = net_send_data(buf);
	ret = net_tcp_send_buf(buf);
	if (ret < 0) {
		net_nbuf_unref(buf);
	}
@@ -759,9 +766,9 @@ static enum net_verdict tcp_established(struct net_conn *conn,
			return NET_DROP;
		}

		ret = packet_received(conn, buf, user_data);

		context->tcp->send_ack += net_nbuf_appdatalen(buf);

		ret = packet_received(conn, buf, user_data);
	}

	send_ack(context, &conn->remote_addr);
+22 −4
Original line number Diff line number Diff line
@@ -323,14 +323,11 @@ int net_tcp_prepare_segment(struct net_tcp *tcp, uint8_t flags,
{
	uint32_t seq;
	uint16_t wnd;
	uint32_t ack = 0;
	struct tcp_segment segment = { 0 };

	seq = tcp->send_seq;

	if (flags & NET_TCP_ACK) {
		ack = tcp->send_ack;

		if (tcp->state == NET_TCP_FIN_WAIT_1) {
			if (flags & NET_TCP_FIN) {
				/* FIN is used here only to determine which
@@ -370,7 +367,7 @@ int net_tcp_prepare_segment(struct net_tcp *tcp, uint8_t flags,
	segment.src_addr = &tcp->context->local;
	segment.dst_addr = remote;
	segment.seq = tcp->send_seq;
	segment.ack = ack;
	segment.ack = tcp->send_ack;
	segment.flags = flags;
	segment.wnd = wnd;
	segment.options = options;
@@ -586,6 +583,27 @@ int tcp_queue_data(struct net_context *context, struct net_buf *buf)
	return 0;
}

int net_tcp_send_buf(struct net_buf *buf)
{
	struct net_context *ctx = net_nbuf_context(buf);
	struct net_tcp_hdr *tcphdr = NET_TCP_BUF(buf);

	sys_put_be32(ctx->tcp->send_ack, tcphdr->ack);

	/* The data stream code always sets this flag, because
	 * existing stacks (Linux, anyway) seem to ignore data packets
	 * without a valid-but-already-transmitted ACK.  But set it
	 * anyway if we know we need it just to sanify edge cases.
	 */
	if (ctx->tcp->sent_ack != ctx->tcp->send_ack) {
		tcphdr->flags |= NET_TCP_ACK;
	}

	ctx->tcp->sent_ack = ctx->tcp->send_ack;

	return net_send_data(buf);
}

int tcp_send_data(struct net_context *context)
{
	struct net_buf *buf;
+12 −1
Original line number Diff line number Diff line
@@ -126,9 +126,12 @@ struct net_tcp {
	/** Current sequence number. */
	uint32_t send_seq;

	/** Acknowledgment number. */
	/** Acknowledgment number to send in next packet. */
	uint32_t send_ack;

	/** Last ACK value sent */
	uint32_t sent_ack;

	/** Max RX segment size (MSS). */
	uint16_t recv_mss;

@@ -283,6 +286,14 @@ int tcp_send_data(struct net_context *context);
 */
int tcp_queue_data(struct net_context *context, struct net_buf *buf);

/**
 * @brief Sends one TCP packet initialized with the _prepare_*()
 *        family of functions.
 *
 * @param buf Packet
 */
int net_tcp_send_buf(struct net_buf *buf);

#if defined(CONFIG_NET_TCP)
void net_tcp_init(void);
#else