Skip to content

Commit

Permalink
net: tcp: Allow to explicitly manage TCP receive window
Browse files Browse the repository at this point in the history
This fixes the existing situation that "if application buffers data,
it's the problem of application". It's actually the problem of the
stack, as it doesn't allow application to control receive window,
and without this control, any buffer will overflow, peer packets
will be dropped, peer won't receive acks for them, and will employ
exponential backoff, the connection will crawl to a halt.

This patch adds net_context_tcp_recved() function which an
application must explicitly call when it *processes* data, to
advance receive window.

Jira: ZEP-1999

Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
  • Loading branch information
pfalcon committed Aug 4, 2017
1 parent e57b7ec commit a937d04
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 13 deletions.
23 changes: 23 additions & 0 deletions include/net/net_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,29 @@ int net_context_recv(struct net_context *context,
s32_t timeout,
void *user_data);

/**
* @brief Update TCP receive window for context.
*
* @details This function should be used by an application which
* doesn't fully process incoming data in its receive callback,
* but for example, queues it. In this case, receive callback
* should decrease the window (call this function with a negative
* value) by the size of queued data, and function(s) which dequeue
* data - with positive value corresponding to the dequeued size.
* For example, if receive callback gets a packet with the data
* size of 256 and queues it, it should call this function with
* delta of -256. If a function extracts 10 bytes of the queued
* data, it should call it with delta of 10.
*
* @param context The TCP network context to use.
* @param delta Size, in bytes, by which to increase TCP receive
* window (negative value to decrease).
*
* @return 0 if ok, < 0 if error
*/
int net_context_update_recv_wnd(struct net_context *context,
s32_t delta);

/**
* @typedef net_context_cb_t
* @brief Callback used while iterating over network contexts
Expand Down
34 changes: 33 additions & 1 deletion subsys/net/ip/net_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,7 @@ NET_CONN_CB(tcp_established)
struct net_tcp_hdr hdr, *tcp_hdr;
enum net_verdict ret;
u8_t tcp_flags;
u16_t data_len;

NET_ASSERT(context && context->tcp);

Expand Down Expand Up @@ -1187,10 +1188,18 @@ NET_CONN_CB(tcp_established)
}

set_appdata_values(pkt, IPPROTO_TCP);
context->tcp->send_ack += net_pkt_appdatalen(pkt);

data_len = net_pkt_appdatalen(pkt);
if (data_len > net_tcp_get_recv_wnd(context->tcp)) {
NET_ERR("Context %p: overflow of recv window (%d vs %d), pkt dropped",
context, net_tcp_get_recv_wnd(context->tcp), data_len);
return NET_DROP;
}

ret = packet_received(conn, pkt, context->tcp->recv_user_data);

context->tcp->send_ack += data_len;

if (tcp_flags & NET_TCP_FIN) {
/* Sending an ACK in the CLOSE_WAIT state will transition to
* LAST_ACK state
Expand Down Expand Up @@ -2426,6 +2435,29 @@ int net_context_recv(struct net_context *context,
return 0;
}

int net_context_update_recv_wnd(struct net_context *context,
s32_t delta)
{
#if defined(CONFIG_NET_TCP)
s32_t new_win;

if (!context->tcp) {
NET_ERR("context->tcp == NULL");
return -EPROTOTYPE;
}

new_win = context->tcp->recv_wnd + delta;
if (new_win < 0 || new_win > UINT16_MAX) {
return -EINVAL;
}

context->tcp->recv_wnd = new_win;

return 0;
#else
return -EPROTOTYPE;
#endif
}
void net_context_foreach(net_context_cb_t cb, void *user_data)
{
int i;
Expand Down
18 changes: 6 additions & 12 deletions subsys/net/ip/tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ struct net_tcp *net_tcp_alloc(struct net_context *context)

tcp_context[i].send_seq = tcp_init_isn();
tcp_context[i].recv_max_ack = tcp_context[i].send_seq + 1u;
tcp_context[i].recv_wnd = min(NET_TCP_MAX_WIN, NET_TCP_BUF_MAX_LEN);

tcp_context[i].accept_cb = NULL;

Expand Down Expand Up @@ -406,17 +407,9 @@ static struct net_pkt *prepare_segment(struct net_tcp *tcp,
return pkt;
}

static inline u32_t get_recv_wnd(struct net_tcp *tcp)
u32_t net_tcp_get_recv_wnd(const struct net_tcp *tcp)
{
ARG_UNUSED(tcp);

/* We don't queue received data inside the stack, we hand off
* packets to synchronous callbacks (who can queue if they
* want, but it's not our business). So the available window
* size is always the same. There are two configurables to
* check though.
*/
return min(NET_TCP_MAX_WIN, NET_TCP_BUF_MAX_LEN);
return tcp->recv_wnd;
}

int net_tcp_prepare_segment(struct net_tcp *tcp, u8_t flags,
Expand Down Expand Up @@ -482,7 +475,7 @@ int net_tcp_prepare_segment(struct net_tcp *tcp, u8_t flags,
seq++;
}

wnd = get_recv_wnd(tcp);
wnd = net_tcp_get_recv_wnd(tcp);

segment.src_addr = (struct sockaddr_ptr *)local;
segment.dst_addr = remote;
Expand Down Expand Up @@ -1054,7 +1047,8 @@ bool net_tcp_validate_seq(struct net_tcp *tcp, struct net_pkt *pkt)
return (net_tcp_seq_cmp(sys_get_be32(tcp_hdr->seq),
tcp->send_ack) >= 0) &&
(net_tcp_seq_cmp(sys_get_be32(tcp_hdr->seq),
tcp->send_ack + get_recv_wnd(tcp)) < 0);
tcp->send_ack
+ net_tcp_get_recv_wnd(tcp)) < 0);
}

struct net_tcp_hdr *net_tcp_get_hdr(struct net_pkt *pkt,
Expand Down
11 changes: 11 additions & 0 deletions subsys/net/ip/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ struct net_tcp {
* Semaphore to signal TCP connection completion
*/
struct k_sem connect_wait;

u16_t recv_wnd;
};

static inline bool net_tcp_is_used(struct net_tcp *tcp)
Expand Down Expand Up @@ -342,6 +344,15 @@ void net_tcp_ack_received(struct net_context *ctx, u32_t ack);
*/
u16_t net_tcp_get_recv_mss(const struct net_tcp *tcp);

/**
* @brief Returns the receive window for a given TCP context
*
* @param tcp TCP context
*
* @return Current TCP receive window
*/
u32_t net_tcp_get_recv_wnd(const struct net_tcp *tcp);

/**
* @brief Obtains the state for a TCP context
*
Expand Down

0 comments on commit a937d04

Please sign in to comment.