net: tcp: Fix sequence number validator

The sequence number validator was checking the seq numbers
incorrectly. This caused some valid RST packets to be dropped
and the TCP stream to hang.

Added also a TCP test case that tests the seq validator.

Jira: ZEP-2289

Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
This commit is contained in:
Jukka Rissanen 2017-07-07 14:51:22 +03:00
parent ccb9c844b5
commit ee989be286
2 changed files with 67 additions and 2 deletions

View File

@ -1051,8 +1051,10 @@ bool net_tcp_validate_seq(struct net_tcp *tcp, struct net_pkt *pkt)
return false;
}
return !net_tcp_seq_greater(tcp->send_ack + get_recv_wnd(tcp),
sys_get_be32(tcp_hdr->seq));
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);
}
struct net_tcp_hdr *net_tcp_get_hdr(struct net_pkt *pkt,

View File

@ -1433,6 +1433,68 @@ static bool test_init_tcp_context(void)
return true;
}
/* Receive window helper function copied from tcp.c */
static inline u32_t get_recv_wnd(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);
}
static bool test_tcp_seq_validity(void)
{
struct net_tcp *tcp = v6_ctx->tcp;
u8_t flags = NET_TCP_RST;
struct net_pkt *pkt = NULL;
int ret;
ret = net_tcp_prepare_segment(tcp, flags, NULL, 0, NULL,
(struct sockaddr *)&peer_v6_addr, &pkt);
if (ret) {
DBG("Prepare segment failed (%d)\n", ret);
return false;
}
tcp->send_ack = sys_get_be32(NET_TCP_HDR(pkt)->seq) -
get_recv_wnd(tcp) / 2;
if (!net_tcp_validate_seq(tcp, pkt)) {
DBG("1) Sequence validation failed (send_ack %u vs seq %u)\n",
tcp->send_ack, sys_get_be32(NET_TCP_HDR(pkt)->seq));
return false;
}
tcp->send_ack = sys_get_be32(NET_TCP_HDR(pkt)->seq);
if (!net_tcp_validate_seq(tcp, pkt)) {
DBG("2) Sequence validation failed (send_ack %u vs seq %u)\n",
tcp->send_ack, sys_get_be32(NET_TCP_HDR(pkt)->seq));
return false;
}
tcp->send_ack = sys_get_be32(NET_TCP_HDR(pkt)->seq) +
2 * get_recv_wnd(tcp);
if (net_tcp_validate_seq(tcp, pkt)) {
DBG("3) Sequence validation failed (send_ack %u vs seq %u)\n",
tcp->send_ack, sys_get_be32(NET_TCP_HDR(pkt)->seq));
return false;
}
tcp->send_ack = sys_get_be32(NET_TCP_HDR(pkt)->seq) -
2 * get_recv_wnd(tcp);
if (net_tcp_validate_seq(tcp, pkt)) {
DBG("4) Sequence validation failed (send_ack %u vs seq %u)\n",
tcp->send_ack, sys_get_be32(NET_TCP_HDR(pkt)->seq));
return false;
}
return true;
}
static bool test_init_tcp_reply_context(void)
{
struct net_if *iface = net_if_get_default() + 1;
@ -1695,6 +1757,7 @@ static const struct {
{ "test IPv4 TCP fin packet creation", test_create_v4_fin_packet },
{ "test IPv6 TCP seq check", test_v6_seq_check },
{ "test IPv4 TCP seq check", test_v4_seq_check },
{ "test TCP seq validity", test_tcp_seq_validity },
{ "test TCP reply context init", test_init_tcp_reply_context },
{ "test TCP accept init", test_init_tcp_accept },
#if 0