net: tcp: Remove NET_TCP_HDR() macro and direct access to net_buf
Remove NET_TCP_HDR() macro as we cannot safely access TCP header
via it if the network packet header spans over multiple net_buf
fragments.
Fixed also the TCP unit tests so that they pass correctly.
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
diff --git a/include/net/net_pkt.h b/include/net/net_pkt.h
index d548240..40defb0 100644
--- a/include/net/net_pkt.h
+++ b/include/net/net_pkt.h
@@ -321,12 +321,6 @@
return pkt->frags->data;
}
-static inline u8_t *net_pkt_tcp_data(struct net_pkt *pkt)
-{
- return &pkt->frags->data[net_pkt_ip_hdr_len(pkt) +
- net_pkt_ipv6_ext_len(pkt)];
-}
-
static inline u8_t *net_pkt_appdata(struct net_pkt *pkt)
{
return pkt->appdata;
@@ -402,7 +396,6 @@
#define NET_IPV6_HDR(pkt) ((struct net_ipv6_hdr *)net_pkt_ip_data(pkt))
#define NET_IPV4_HDR(pkt) ((struct net_ipv4_hdr *)net_pkt_ip_data(pkt))
-#define NET_TCP_HDR(pkt) ((struct net_tcp_hdr *)(net_pkt_tcp_data(pkt)))
static inline void net_pkt_set_src_ipv6_addr(struct net_pkt *pkt)
{
diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c
index 1d117ba..d1767e2 100644
--- a/subsys/net/ip/connection.c
+++ b/subsys/net/ip/connection.c
@@ -24,6 +24,7 @@
#include "icmpv6.h"
#include "icmpv4.h"
#include "udp_internal.h"
+#include "tcp.h"
#include "connection.h"
#include "net_stats.h"
@@ -801,7 +802,7 @@
}
if (proto == IPPROTO_TCP) {
- chksum = NET_TCP_HDR(pkt)->chksum;
+ chksum = net_tcp_get_chksum(pkt, pkt->frags);
} else {
chksum = udp_hdr->chksum;
}
@@ -886,8 +887,8 @@
proto == IPPROTO_TCP) {
u16_t chksum_calc;
- NET_TCP_HDR(pkt)->chksum = 0;
- chksum_calc = ~net_calc_chksum_tcp(pkt);
+ net_tcp_set_chksum(pkt, pkt->frags);
+ chksum_calc = net_tcp_get_chksum(pkt, pkt->frags);
if (chksum != chksum_calc) {
net_stats_update_tcp_seg_chkerr();
diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c
index 5cbe81f..f556259 100644
--- a/subsys/net/ip/ipv4.c
+++ b/subsys/net/ip/ipv4.c
@@ -23,6 +23,7 @@
#include "net_stats.h"
#include "icmpv4.h"
#include "udp_internal.h"
+#include "tcp.h"
#include "ipv4.h"
struct net_pkt *net_ipv4_create_raw(struct net_pkt *pkt,
@@ -103,8 +104,7 @@
#endif
#if defined(CONFIG_NET_TCP)
if (next_header == IPPROTO_TCP) {
- NET_TCP_HDR(pkt)->chksum = 0;
- NET_TCP_HDR(pkt)->chksum = ~net_calc_chksum_tcp(pkt);
+ net_tcp_set_chksum(pkt, pkt->frags);
}
#endif
diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c
index b212d5a..af9d6f9 100644
--- a/subsys/net/ip/ipv6.c
+++ b/subsys/net/ip/ipv6.c
@@ -28,6 +28,7 @@
#include "connection.h"
#include "icmpv6.h"
#include "udp_internal.h"
+#include "tcp.h"
#include "ipv6.h"
#include "nbr.h"
#include "6lo.h"
@@ -706,8 +707,7 @@
#if defined(CONFIG_NET_TCP)
if (next_header == IPPROTO_TCP) {
- NET_TCP_HDR(pkt)->chksum = 0;
- NET_TCP_HDR(pkt)->chksum = ~net_calc_chksum_tcp(pkt);
+ net_tcp_set_chksum(pkt, pkt->frags);
} else
#endif
diff --git a/subsys/net/ip/net_context.c b/subsys/net/ip/net_context.c
index cd375c2..957110b 100644
--- a/subsys/net/ip/net_context.c
+++ b/subsys/net/ip/net_context.c
@@ -111,11 +111,18 @@
static struct sockaddr *create_sockaddr(struct net_pkt *pkt,
struct sockaddr *addr)
{
+ struct net_tcp_hdr hdr, *tcp_hdr;
+
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return NULL;
+ }
+
#if defined(CONFIG_NET_IPV6)
if (net_pkt_family(pkt) == AF_INET6) {
net_ipaddr_copy(&net_sin6(addr)->sin6_addr,
&NET_IPV6_HDR(pkt)->src);
- net_sin6(addr)->sin6_port = NET_TCP_HDR(pkt)->src_port;
+ net_sin6(addr)->sin6_port = tcp_hdr->src_port;
net_sin6(addr)->sin6_family = AF_INET6;
} else
#endif
@@ -124,7 +131,7 @@
if (net_pkt_family(pkt) == AF_INET) {
net_ipaddr_copy(&net_sin(addr)->sin_addr,
&NET_IPV4_HDR(pkt)->src);
- net_sin(addr)->sin_port = NET_TCP_HDR(pkt)->src_port;
+ net_sin(addr)->sin_port = tcp_hdr->src_port;
net_sin(addr)->sin_family = AF_INET;
} else
#endif
@@ -137,6 +144,7 @@
static int tcp_backlog_find(struct net_pkt *pkt, int *empty_slot)
{
+ struct net_tcp_hdr hdr, *tcp_hdr;
int i, empty = -1;
for (i = 0; i < CONFIG_NET_TCP_BACKLOG_SIZE; i++) {
@@ -149,11 +157,13 @@
continue;
}
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+
switch (net_pkt_family(pkt)) {
#if defined(CONFIG_NET_IPV6)
case AF_INET6:
if (net_sin6(&tcp_backlog[i].remote)->sin6_port !=
- NET_TCP_HDR(pkt)->src_port) {
+ tcp_hdr->src_port) {
continue;
}
@@ -168,7 +178,7 @@
#if defined(CONFIG_NET_IPV4)
case AF_INET:
if (net_sin(&tcp_backlog[i].remote)->sin_port !=
- NET_TCP_HDR(pkt)->src_port) {
+ tcp_hdr->src_port) {
continue;
}
@@ -221,6 +231,7 @@
static int tcp_backlog_ack(struct net_pkt *pkt, struct net_context *context)
{
+ struct net_tcp_hdr hdr, *tcp_hdr;
int r;
r = tcp_backlog_find(pkt, NULL);
@@ -229,9 +240,13 @@
return r;
}
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return -EINVAL;
+ }
+
/* Sent SEQ + 1 needs to be the same as the received ACK */
- if (tcp_backlog[r].send_seq + 1
- != sys_get_be32(NET_TCP_HDR(pkt)->ack)) {
+ if (tcp_backlog[r].send_seq + 1 != sys_get_be32(tcp_hdr->ack)) {
return -EINVAL;
}
@@ -258,6 +273,7 @@
static int tcp_backlog_rst(struct net_pkt *pkt)
{
+ struct net_tcp_hdr hdr, *tcp_hdr;
int r;
r = tcp_backlog_find(pkt, NULL);
@@ -265,8 +281,13 @@
return r;
}
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return -EINVAL;
+ }
+
/* The ACK sent needs to be the same as the received SEQ */
- if (tcp_backlog[r].send_ack != sys_get_be32(NET_TCP_HDR(pkt)->seq)) {
+ if (tcp_backlog[r].send_ack != sys_get_be32(tcp_hdr->seq)) {
return -EINVAL;
}
@@ -852,7 +873,7 @@
#if defined(CONFIG_NET_TCP)
#if defined(CONFIG_NET_DEBUG_CONTEXT)
-#define net_tcp_print_recv_info(str, pkt, port) \
+#define net_tcp_print_recv_info(str, pkt, port) \
do { \
if (net_context_get_family(context) == AF_INET6) { \
NET_DBG("%s received from %s port %d", str, \
@@ -865,23 +886,37 @@
} \
} while (0)
-#define net_tcp_print_send_info(str, pkt, port) \
+#define net_tcp_print_send_info(str, pkt, port) \
do { \
- if (net_context_get_family(context) == AF_INET6) { \
+ struct net_context *ctx = net_pkt_context(pkt); \
+ if (net_context_get_family(ctx) == AF_INET6) { \
NET_DBG("%s sent to %s port %d", str, \
net_sprint_ipv6_addr(&NET_IPV6_HDR(pkt)->dst),\
ntohs(port)); \
- } else if (net_context_get_family(context) == AF_INET) {\
+ } else if (net_context_get_family(ctx) == AF_INET) { \
NET_DBG("%s sent to %s port %d", str, \
net_sprint_ipv4_addr(&NET_IPV4_HDR(pkt)->dst),\
ntohs(port)); \
} \
} while (0)
+
#else
#define net_tcp_print_recv_info(...)
#define net_tcp_print_send_info(...)
#endif /* CONFIG_NET_DEBUG_CONTEXT */
+static void print_send_info(struct net_pkt *pkt, const char *msg)
+{
+ if (IS_ENABLED(CONFIG_NET_DEBUG_CONTEXT)) {
+ struct net_tcp_hdr hdr, *tcp_hdr;
+
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (tcp_hdr) {
+ net_tcp_print_send_info(msg, pkt, tcp_hdr->dst_port);
+ }
+ }
+}
+
static inline int send_control_segment(struct net_context *context,
const struct sockaddr_ptr *local,
const struct sockaddr *remote,
@@ -901,7 +936,7 @@
net_pkt_unref(pkt);
}
- net_tcp_print_send_info(msg, pkt, NET_TCP_HDR(pkt)->dst_port);
+ print_send_info(pkt, msg);
return ret;
}
@@ -941,7 +976,7 @@
return ret;
}
- net_tcp_print_send_info("ACK", pkt, NET_TCP_HDR(pkt)->dst_port);
+ print_send_info(pkt, "ACK");
ret = net_tcp_send_pkt(pkt);
if (ret < 0) {
@@ -962,7 +997,7 @@
return ret;
}
- net_tcp_print_send_info("RST", pkt, NET_TCP_HDR(pkt)->dst_port);
+ print_send_info(pkt, "RST");
ret = net_send_data(pkt);
if (ret < 0) {
@@ -974,10 +1009,15 @@
static int tcp_hdr_len(struct net_pkt *pkt)
{
- /* "Offset": 4-bit field in high nibble, units of dwords */
- struct net_tcp_hdr *hdr = (void *)net_pkt_tcp_data(pkt);
+ struct net_tcp_hdr hdr, *tcp_hdr;
- return 4 * (hdr->offset >> 4);
+ /* "Offset": 4-bit field in high nibble, units of dwords */
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (tcp_hdr) {
+ return 4 * (tcp_hdr->offset >> 4);
+ }
+
+ return 0;
}
/* This is called when we receive data after the connection has been
@@ -986,23 +1026,29 @@
NET_CONN_CB(tcp_established)
{
struct net_context *context = (struct net_context *)user_data;
+ struct net_tcp_hdr hdr, *tcp_hdr;
enum net_verdict ret;
u8_t tcp_flags;
NET_ASSERT(context && context->tcp);
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return NET_DROP;
+ }
+
if (net_tcp_get_state(context->tcp) < NET_TCP_ESTABLISHED) {
NET_ERR("Context %p in wrong state %d",
context, net_tcp_get_state(context->tcp));
return NET_DROP;
}
- net_tcp_print_recv_info("DATA", pkt, NET_TCP_HDR(pkt)->src_port);
+ net_tcp_print_recv_info("DATA", pkt, tcp_hdr->src_port);
- tcp_flags = NET_TCP_FLAGS(pkt);
+ tcp_flags = NET_TCP_FLAGS(tcp_hdr);
if (tcp_flags & NET_TCP_ACK) {
net_tcp_ack_received(context,
- sys_get_be32(NET_TCP_HDR(pkt)->ack));
+ sys_get_be32(tcp_hdr->ack));
}
/*
@@ -1018,7 +1064,7 @@
net_stats_update_tcp_seg_rst();
- net_tcp_print_recv_info("RST", pkt, NET_TCP_HDR(pkt)->src_port);
+ net_tcp_print_recv_info("RST", pkt, tcp_hdr->src_port);
if (context->recv_cb) {
context->recv_cb(context, NULL, -ECONNRESET,
@@ -1030,7 +1076,7 @@
return NET_DROP;
}
- if (net_tcp_seq_cmp(sys_get_be32(NET_TCP_HDR(pkt)->seq),
+ if (net_tcp_seq_cmp(sys_get_be32(tcp_hdr->seq),
context->tcp->send_ack) < 0) {
/* Peer sent us packet we've already seen. Apparently,
* our ack was lost.
@@ -1043,7 +1089,7 @@
return NET_DROP;
}
- if (sys_get_be32(NET_TCP_HDR(pkt)->seq) - context->tcp->send_ack) {
+ if (sys_get_be32(tcp_hdr->seq) - context->tcp->send_ack) {
/* Don't try to reorder packets. If it doesn't
* match the next segment exactly, drop and wait for
* retransmit
@@ -1097,6 +1143,7 @@
NET_CONN_CB(tcp_synack_received)
{
struct net_context *context = (struct net_context *)user_data;
+ struct net_tcp_hdr hdr, *tcp_hdr;
int ret;
NET_ASSERT(context && context->tcp);
@@ -1115,7 +1162,12 @@
NET_ASSERT(net_pkt_iface(pkt));
- if (NET_TCP_FLAGS(pkt) & NET_TCP_RST) {
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return NET_DROP;
+ }
+
+ if (NET_TCP_FLAGS(tcp_hdr) & NET_TCP_RST) {
/* We only accept RST packet that has valid seq field. */
if (!net_tcp_validate_seq(context->tcp, pkt)) {
net_stats_update_tcp_seg_rsterr();
@@ -1132,15 +1184,15 @@
return NET_DROP;
}
- if (NET_TCP_FLAGS(pkt) & NET_TCP_SYN) {
+ if (NET_TCP_FLAGS(tcp_hdr) & NET_TCP_SYN) {
context->tcp->send_ack =
- sys_get_be32(NET_TCP_HDR(pkt)->seq) + 1;
+ sys_get_be32(tcp_hdr->seq) + 1;
context->tcp->recv_max_ack = context->tcp->send_seq + 1;
}
/*
* If we receive SYN, we send SYN-ACK and go to SYN_RCVD state.
*/
- if (NET_TCP_FLAGS(pkt) == (NET_TCP_SYN | NET_TCP_ACK)) {
+ if (NET_TCP_FLAGS(tcp_hdr) == (NET_TCP_SYN | NET_TCP_ACK)) {
struct sockaddr *laddr;
struct sockaddr *raddr;
@@ -1159,12 +1211,12 @@
raddr = (struct sockaddr *)&r6addr;
r6addr.sin6_family = AF_INET6;
- r6addr.sin6_port = NET_TCP_HDR(pkt)->src_port;
+ r6addr.sin6_port = tcp_hdr->src_port;
net_ipaddr_copy(&r6addr.sin6_addr,
&NET_IPV6_HDR(pkt)->src);
l6addr.sin6_family = AF_INET6;
- l6addr.sin6_port = NET_TCP_HDR(pkt)->dst_port;
+ l6addr.sin6_port = htons(tcp_hdr->dst_port);
net_ipaddr_copy(&l6addr.sin6_addr,
&NET_IPV6_HDR(pkt)->dst);
} else
@@ -1175,12 +1227,12 @@
raddr = (struct sockaddr *)&r4addr;
r4addr.sin_family = AF_INET;
- r4addr.sin_port = NET_TCP_HDR(pkt)->src_port;
+ r4addr.sin_port = tcp_hdr->src_port;
net_ipaddr_copy(&r4addr.sin_addr,
&NET_IPV4_HDR(pkt)->src);
l4addr.sin_family = AF_INET;
- l4addr.sin_port = NET_TCP_HDR(pkt)->dst_port;
+ l4addr.sin_port = htons(tcp_hdr->dst_port);
net_ipaddr_copy(&l4addr.sin_addr,
&NET_IPV4_HDR(pkt)->dst);
} else
@@ -1197,8 +1249,8 @@
ret = net_tcp_register(raddr,
laddr,
- ntohs(NET_TCP_HDR(pkt)->src_port),
- ntohs(NET_TCP_HDR(pkt)->dst_port),
+ ntohs(tcp_hdr->src_port),
+ ntohs(tcp_hdr->dst_port),
tcp_established,
context,
&context->conn_handler);
@@ -1424,6 +1476,13 @@
static void pkt_get_sockaddr(sa_family_t family, struct net_pkt *pkt,
struct sockaddr_ptr *addr)
{
+ struct net_tcp_hdr hdr, *tcp_hdr;
+
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return;
+ }
+
memset(addr, 0, sizeof(*addr));
#if defined(CONFIG_NET_IPV4)
@@ -1431,7 +1490,7 @@
struct sockaddr_in_ptr *addr4 = net_sin_ptr(addr);
addr4->sin_family = AF_INET;
- addr4->sin_port = NET_TCP_HDR(pkt)->dst_port;
+ addr4->sin_port = tcp_hdr->dst_port;
addr4->sin_addr = &NET_IPV4_HDR(pkt)->dst;
}
#endif
@@ -1441,7 +1500,7 @@
struct sockaddr_in6_ptr *addr6 = net_sin6_ptr(addr);
addr6->sin6_family = AF_INET6;
- addr6->sin6_port = NET_TCP_HDR(pkt)->dst_port;
+ addr6->sin6_port = tcp_hdr->dst_port;
addr6->sin6_addr = &NET_IPV6_HDR(pkt)->dst;
}
#endif
@@ -1466,6 +1525,7 @@
NET_CONN_CB(tcp_syn_rcvd)
{
struct net_context *context = (struct net_context *)user_data;
+ struct net_tcp_hdr hdr, *tcp_hdr;
struct net_tcp *tcp;
struct sockaddr_ptr pkt_src_addr;
@@ -1492,14 +1552,19 @@
NET_ASSERT(net_pkt_iface(pkt));
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return NET_DROP;
+ }
+
/*
* If we receive SYN, we send SYN-ACK and go to SYN_RCVD state.
*/
- if (NET_TCP_FLAGS(pkt) == NET_TCP_SYN) {
+ if (NET_TCP_FLAGS(tcp_hdr) == NET_TCP_SYN) {
struct sockaddr peer, *remote;
int r;
- net_tcp_print_recv_info("SYN", pkt, NET_TCP_HDR(pkt)->src_port);
+ net_tcp_print_recv_info("SYN", pkt, tcp_hdr->src_port);
net_tcp_change_state(tcp, NET_TCP_SYN_RCVD);
@@ -1508,7 +1573,7 @@
/* Set TCP seq and ack which are then stored in the backlog */
context->tcp->send_seq = tcp_init_isn();
context->tcp->send_ack =
- sys_get_be32(NET_TCP_HDR(pkt)->seq) + 1;
+ sys_get_be32(tcp_hdr->seq) + 1;
context->tcp->recv_max_ack = context->tcp->send_seq + 1;
r = tcp_backlog_syn(pkt, context);
@@ -1533,7 +1598,7 @@
* See RFC 793 chapter 3.4 "Reset Processing" and RFC 793, page 65
* for more details.
*/
- if (NET_TCP_FLAGS(pkt) == NET_TCP_RST) {
+ if (NET_TCP_FLAGS(tcp_hdr) == NET_TCP_RST) {
if (tcp_backlog_rst(pkt) < 0) {
net_stats_update_tcp_seg_rsterr();
@@ -1542,7 +1607,7 @@
net_stats_update_tcp_seg_rst();
- net_tcp_print_recv_info("RST", pkt, NET_TCP_HDR(pkt)->src_port);
+ net_tcp_print_recv_info("RST", pkt, tcp_hdr->src_port);
return NET_DROP;
}
@@ -1550,7 +1615,7 @@
/*
* If we receive ACK, we go to ESTABLISHED state.
*/
- if (NET_TCP_FLAGS(pkt) == NET_TCP_ACK) {
+ if (NET_TCP_FLAGS(tcp_hdr) == NET_TCP_ACK) {
struct net_context *new_context;
struct sockaddr local_addr;
struct sockaddr remote_addr;
@@ -1558,7 +1623,7 @@
socklen_t addrlen;
int ret;
- net_tcp_print_recv_info("ACK", pkt, NET_TCP_HDR(pkt)->src_port);
+ net_tcp_print_recv_info("ACK", pkt, tcp_hdr->src_port);
if (!context->tcp->accept_cb) {
NET_DBG("No accept callback, connection reset.");
@@ -1595,8 +1660,8 @@
remote_addr6->sin6_family = AF_INET6;
local_addr6->sin6_family = AF_INET6;
- local_addr6->sin6_port = NET_TCP_HDR(pkt)->dst_port;
- remote_addr6->sin6_port = NET_TCP_HDR(pkt)->src_port;
+ local_addr6->sin6_port = tcp_hdr->dst_port;
+ remote_addr6->sin6_port = tcp_hdr->src_port;
net_ipaddr_copy(&local_addr6->sin6_addr,
&NET_IPV6_HDR(pkt)->dst);
@@ -1616,8 +1681,8 @@
remote_addr4->sin_family = AF_INET;
local_addr4->sin_family = AF_INET;
- local_addr4->sin_port = NET_TCP_HDR(pkt)->dst_port;
- remote_addr4->sin_port = NET_TCP_HDR(pkt)->src_port;
+ local_addr4->sin_port = tcp_hdr->dst_port;
+ remote_addr4->sin_port = tcp_hdr->src_port;
net_ipaddr_copy(&local_addr4->sin_addr,
&NET_IPV4_HDR(pkt)->dst);
@@ -2077,8 +2142,7 @@
#if defined(CONFIG_NET_TCP)
if (proto == IPPROTO_TCP) {
- net_pkt_set_appdata(pkt, net_pkt_tcp_data(pkt) +
- tcp_hdr_len(pkt));
+ proto_len = tcp_hdr_len(pkt);
}
#endif /* CONFIG_NET_TCP */
diff --git a/subsys/net/ip/net_pkt.c b/subsys/net/ip/net_pkt.c
index 8545753..5149a69 100644
--- a/subsys/net/ip/net_pkt.c
+++ b/subsys/net/ip/net_pkt.c
@@ -1746,6 +1746,32 @@
return (struct net_udp_hdr *)(frag->data + offset);
}
+struct net_tcp_hdr *net_pkt_tcp_data(struct net_pkt *pkt)
+{
+ struct net_buf *frag;
+ u16_t offset;
+
+ frag = net_frag_get_pos(pkt,
+ net_pkt_ip_hdr_len(pkt) +
+ net_pkt_ipv6_ext_len(pkt),
+ &offset);
+ if (!frag) {
+ /* We tried to read past the end of the data */
+ NET_ASSERT_INFO(frag,
+ "IP hdr %d ext len %d offset %d pos %d "
+ "total %zd",
+ net_pkt_ip_hdr_len(pkt),
+ net_pkt_ipv6_ext_len(pkt),
+ offset,
+ net_pkt_ip_hdr_len(pkt) +
+ net_pkt_ipv6_ext_len(pkt),
+ net_buf_frags_len(pkt->frags));
+ return NULL;
+ }
+
+ return (struct net_tcp_hdr *)(frag->data + offset);
+}
+
void net_pkt_init(void)
{
NET_DBG("Allocating %u RX (%zu bytes), %u TX (%zu bytes), "
diff --git a/subsys/net/ip/net_private.h b/subsys/net/ip/net_private.h
index ea28b39..750d017 100644
--- a/subsys/net/ip/net_private.h
+++ b/subsys/net/ip/net_private.h
@@ -70,6 +70,19 @@
return NULL;
}
+struct net_tcp_hdr *net_pkt_tcp_data(struct net_pkt *pkt);
+
+static inline
+struct net_tcp_hdr *net_tcp_header_fits(struct net_pkt *pkt,
+ struct net_tcp_hdr *hdr)
+{
+ if (net_header_fits(pkt, (u8_t *)hdr, sizeof(*hdr))) {
+ return hdr;
+ }
+
+ return NULL;
+}
+
#if defined(CONFIG_NET_IPV4)
extern u16_t net_calc_chksum_ipv4(struct net_pkt *pkt);
#endif /* CONFIG_NET_IPV4 */
diff --git a/subsys/net/ip/tcp.c b/subsys/net/ip/tcp.c
index d35c611..a3c5c18 100644
--- a/subsys/net/ip/tcp.c
+++ b/subsys/net/ip/tcp.c
@@ -77,10 +77,17 @@
static void net_tcp_trace(struct net_pkt *pkt, struct net_tcp *tcp)
{
- u8_t flags = NET_TCP_FLAGS(pkt);
+ struct net_tcp_hdr hdr, *tcp_hdr;
u32_t rel_ack, ack;
+ u8_t flags;
- ack = sys_get_be32(NET_TCP_HDR(pkt)->ack);
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return;
+ }
+
+ flags = NET_TCP_FLAGS(tcp_hdr);
+ ack = sys_get_be32(tcp_hdr->ack);
if (!tcp->sent_ack) {
rel_ack = 0;
@@ -91,10 +98,10 @@
NET_DBG("pkt %p src %u dst %u seq 0x%04x (%u) ack 0x%04x (%u/%u) "
"flags %c%c%c%c%c%c win %u chk 0x%04x",
pkt,
- ntohs(NET_TCP_HDR(pkt)->src_port),
- ntohs(NET_TCP_HDR(pkt)->dst_port),
- sys_get_be32(NET_TCP_HDR(pkt)->seq),
- sys_get_be32(NET_TCP_HDR(pkt)->seq),
+ ntohs(tcp_hdr->src_port),
+ ntohs(tcp_hdr->dst_port),
+ sys_get_be32(tcp_hdr->seq),
+ sys_get_be32(tcp_hdr->seq),
ack,
ack,
/* This tells how many bytes we are acking now */
@@ -105,8 +112,8 @@
upper_if_set('r', flags & NET_TCP_RST),
upper_if_set('s', flags & NET_TCP_SYN),
upper_if_set('f', flags & NET_TCP_FIN),
- sys_get_be16(NET_TCP_HDR(pkt)->wnd),
- ntohs(NET_TCP_HDR(pkt)->chksum));
+ sys_get_be16(tcp_hdr->wnd),
+ ntohs(tcp_hdr->chksum));
}
#else
#define net_tcp_trace(...)
@@ -295,8 +302,8 @@
struct net_pkt *pkt)
{
struct net_buf *header, *tail = NULL;
- struct net_tcp_hdr *tcphdr;
struct net_context *context = tcp->context;
+ struct net_tcp_hdr *tcp_hdr;
u16_t dst_port, src_port;
u8_t optlen = 0;
@@ -354,23 +361,23 @@
net_pkt_frag_add(pkt, header);
- tcphdr = (struct net_tcp_hdr *)net_buf_add(header, NET_TCPH_LEN);
+ tcp_hdr = (struct net_tcp_hdr *)net_buf_add(header, NET_TCPH_LEN);
if (segment->options && segment->optlen) {
optlen = net_tcp_add_options(header, segment->optlen,
segment->options);
}
- tcphdr->offset = (NET_TCPH_LEN + optlen) << 2;
+ tcp_hdr->offset = (NET_TCPH_LEN + optlen) << 2;
- tcphdr->src_port = src_port;
- tcphdr->dst_port = dst_port;
- sys_put_be32(segment->seq, tcphdr->seq);
- sys_put_be32(segment->ack, tcphdr->ack);
- tcphdr->flags = segment->flags;
- sys_put_be16(segment->wnd, tcphdr->wnd);
- tcphdr->urg[0] = 0;
- tcphdr->urg[1] = 0;
+ tcp_hdr->src_port = src_port;
+ tcp_hdr->dst_port = dst_port;
+ sys_put_be32(segment->seq, tcp_hdr->seq);
+ sys_put_be32(segment->ack, tcp_hdr->ack);
+ tcp_hdr->flags = segment->flags;
+ sys_put_be16(segment->wnd, tcp_hdr->wnd);
+ tcp_hdr->urg[0] = 0;
+ tcp_hdr->urg[1] = 0;
if (tail) {
net_pkt_frag_add(pkt, tail);
@@ -695,9 +702,14 @@
int net_tcp_send_pkt(struct net_pkt *pkt)
{
struct net_context *ctx = net_pkt_context(pkt);
- struct net_tcp_hdr *tcphdr = NET_TCP_HDR(pkt);
+ struct net_tcp_hdr hdr, *tcp_hdr;
- sys_put_be32(ctx->tcp->send_ack, tcphdr->ack);
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return -EINVAL;
+ }
+
+ sys_put_be32(ctx->tcp->send_ack, tcp_hdr->ack);
/* The data stream code always sets this flag, because
* existing stacks (Linux, anyway) seem to ignore data packets
@@ -705,10 +717,10 @@
* 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;
+ tcp_hdr->flags |= NET_TCP_ACK;
}
- if (tcphdr->flags & NET_TCP_FIN) {
+ if (tcp_hdr->flags & NET_TCP_FIN) {
ctx->tcp->fin_sent = 1;
}
@@ -716,6 +728,10 @@
net_pkt_set_sent(pkt, true);
+ /* As we modified the header, we need to write it back.
+ */
+ net_tcp_set_hdr(pkt, tcp_hdr);
+
/* We must have special handling for some network technologies that
* tweak the IP protocol headers during packet sending. This happens
* with Bluetooth and IEEE 802.15.4 which use IPv6 header compression
@@ -823,7 +839,6 @@
sys_slist_t *list = &ctx->tcp->sent_list;
sys_snode_t *head;
struct net_pkt *pkt;
- struct net_tcp_hdr *tcphdr;
u32_t seq;
bool valid_ack = false;
@@ -833,18 +848,21 @@
}
while (!sys_slist_is_empty(list)) {
+ struct net_tcp_hdr hdr, *tcp_hdr;
+
head = sys_slist_peek_head(list);
pkt = CONTAINER_OF(head, struct net_pkt, sent_list);
- tcphdr = NET_TCP_HDR(pkt);
- seq = sys_get_be32(tcphdr->seq) + net_pkt_appdatalen(pkt) - 1;
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+
+ seq = sys_get_be32(tcp_hdr->seq) + net_pkt_appdatalen(pkt) - 1;
if (!net_tcp_seq_greater(ack, seq)) {
net_stats_update_tcp_seg_ackerr();
break;
}
- if (tcphdr->flags & NET_TCP_FIN) {
+ if (tcp_hdr->flags & NET_TCP_FIN) {
enum net_tcp_state s = net_tcp_get_state(tcp);
if (s == NET_TCP_FIN_WAIT_1) {
@@ -1003,6 +1021,142 @@
bool net_tcp_validate_seq(struct net_tcp *tcp, struct net_pkt *pkt)
{
+ struct net_tcp_hdr hdr, *tcp_hdr;
+
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return false;
+ }
+
return !net_tcp_seq_greater(tcp->send_ack + get_recv_wnd(tcp),
- sys_get_be32(NET_TCP_HDR(pkt)->seq));
+ sys_get_be32(tcp_hdr->seq));
+}
+
+struct net_tcp_hdr *net_tcp_get_hdr(struct net_pkt *pkt,
+ struct net_tcp_hdr *hdr)
+{
+ struct net_tcp_hdr *tcp_hdr;
+ struct net_buf *frag;
+ u16_t pos;
+
+ tcp_hdr = net_pkt_tcp_data(pkt);
+ if (net_tcp_header_fits(pkt, tcp_hdr)) {
+ return tcp_hdr;
+ }
+
+ frag = net_frag_read(pkt->frags, net_pkt_ip_hdr_len(pkt) +
+ net_pkt_ipv6_ext_len(pkt),
+ &pos, sizeof(hdr->src_port),
+ (u8_t *)&hdr->src_port);
+ frag = net_frag_read(frag, pos, &pos, sizeof(hdr->dst_port),
+ (u8_t *)&hdr->dst_port);
+ frag = net_frag_read(frag, pos, &pos, sizeof(hdr->seq), hdr->seq);
+ frag = net_frag_read(frag, pos, &pos, sizeof(hdr->ack), hdr->ack);
+ frag = net_frag_read_u8(frag, pos, &pos, &hdr->offset);
+ frag = net_frag_read_u8(frag, pos, &pos, &hdr->flags);
+ frag = net_frag_read(frag, pos, &pos, sizeof(hdr->wnd), hdr->wnd);
+ frag = net_frag_read(frag, pos, &pos, sizeof(hdr->chksum),
+ (u8_t *)&hdr->chksum);
+ frag = net_frag_read(frag, pos, &pos, sizeof(hdr->urg), hdr->urg);
+
+ if (!frag && pos == 0xffff) {
+ NET_ASSERT(frag);
+ return NULL;
+ }
+
+ return hdr;
+}
+
+struct net_tcp_hdr *net_tcp_set_hdr(struct net_pkt *pkt,
+ struct net_tcp_hdr *hdr)
+{
+ struct net_buf *frag;
+ u16_t pos;
+
+ if (net_tcp_header_fits(pkt, hdr)) {
+ return hdr;
+ }
+
+ frag = net_pkt_write(pkt, pkt->frags, net_pkt_ip_hdr_len(pkt) +
+ net_pkt_ipv6_ext_len(pkt),
+ &pos, sizeof(hdr->src_port),
+ (u8_t *)&hdr->src_port, ALLOC_TIMEOUT);
+ frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->dst_port),
+ (u8_t *)&hdr->dst_port, ALLOC_TIMEOUT);
+ frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->seq), hdr->seq,
+ ALLOC_TIMEOUT);
+ frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->ack), hdr->ack,
+ ALLOC_TIMEOUT);
+ frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->offset),
+ &hdr->offset, ALLOC_TIMEOUT);
+ frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->flags),
+ &hdr->flags, ALLOC_TIMEOUT);
+ frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->wnd), hdr->wnd,
+ ALLOC_TIMEOUT);
+ frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->chksum),
+ (u8_t *)&hdr->chksum, ALLOC_TIMEOUT);
+ frag = net_pkt_write(pkt, frag, pos, &pos, sizeof(hdr->urg), hdr->urg,
+ ALLOC_TIMEOUT);
+
+ if (!frag) {
+ NET_ASSERT(frag);
+ return NULL;
+ }
+
+ return hdr;
+}
+
+u16_t net_tcp_get_chksum(struct net_pkt *pkt, struct net_buf *frag)
+{
+ struct net_tcp_hdr *hdr;
+ u16_t chksum;
+ u16_t pos;
+
+ hdr = net_pkt_tcp_data(pkt);
+ if (net_tcp_header_fits(pkt, hdr)) {
+ return hdr->chksum;
+ }
+
+ frag = net_frag_read(frag,
+ net_pkt_ip_hdr_len(pkt) +
+ net_pkt_ipv6_ext_len(pkt) +
+ 2 + 2 + 4 + 4 + /* src + dst + seq + ack */
+ 1 + 1 + 2 /* offset + flags + wnd */,
+ &pos, sizeof(chksum), (u8_t *)&chksum);
+ NET_ASSERT(frag);
+
+ return chksum;
+}
+
+struct net_buf *net_tcp_set_chksum(struct net_pkt *pkt, struct net_buf *frag)
+{
+ struct net_tcp_hdr *hdr;
+ u16_t chksum = 0;
+ u16_t pos;
+
+ hdr = net_pkt_tcp_data(pkt);
+ if (net_tcp_header_fits(pkt, hdr)) {
+ hdr->chksum = 0;
+ hdr->chksum = ~net_calc_chksum_tcp(pkt);
+
+ return frag;
+ }
+
+ /* We need to set the checksum to 0 first before the calc */
+ frag = net_pkt_write(pkt, frag,
+ net_pkt_ip_hdr_len(pkt) +
+ net_pkt_ipv6_ext_len(pkt) +
+ 2 + 2 + 4 + 4 + /* src + dst + seq + ack */
+ 1 + 1 + 2 /* offset + flags + wnd */,
+ &pos, sizeof(chksum), (u8_t *)&chksum,
+ ALLOC_TIMEOUT);
+
+ chksum = ~net_calc_chksum_tcp(pkt);
+
+ frag = net_pkt_write(pkt, frag, pos - 2, &pos, sizeof(chksum),
+ (u8_t *)&chksum, ALLOC_TIMEOUT);
+
+ NET_ASSERT(frag);
+
+ return frag;
}
diff --git a/subsys/net/ip/tcp.h b/subsys/net/ip/tcp.h
index cca3bd6..f843d81 100644
--- a/subsys/net/ip/tcp.h
+++ b/subsys/net/ip/tcp.h
@@ -70,7 +70,7 @@
#define NET_TCP_URG 0x20
#define NET_TCP_CTL 0x3f
-#define NET_TCP_FLAGS(net_pkt) (NET_TCP_HDR(net_pkt)->flags & NET_TCP_CTL)
+#define NET_TCP_FLAGS(hdr) (hdr->flags & NET_TCP_CTL)
/* TCP max window size */
#define NET_TCP_MAX_WIN (4 * 1024)
@@ -358,6 +358,58 @@
bool net_tcp_validate_seq(struct net_tcp *tcp, struct net_pkt *pkt);
#if defined(CONFIG_NET_TCP)
+/**
+ * @brief Get TCP packet header data from net_pkt. The array values are in
+ * network byte order and other values are in host byte order.
+ *
+ * @param pkt Network packet
+ * @param hdr Where to place the header.
+ *
+ * @return Return pointer to header or NULL if something went wrong.
+ */
+struct net_tcp_hdr *net_tcp_get_hdr(struct net_pkt *pkt,
+ struct net_tcp_hdr *hdr);
+
+/**
+ * @brief Set TCP packet header data in net_pkt. The array values are in
+ * network byte order and other values are in host byte order.
+ *
+ * @param pkt Network packet
+ * @param hdr Header to be written
+ *
+ * @return Return hdr or NULL if error
+ */
+struct net_tcp_hdr *net_tcp_set_hdr(struct net_pkt *pkt,
+ struct net_tcp_hdr *hdr);
+
+/**
+ * @brief Set TCP checksum in network packet.
+ *
+ * @param pkt Network packet
+ * @param frag Fragment where to start calculating the offset.
+ * Typically this is set to pkt->frags by the caller.
+ *
+ * @return Return the actual fragment where the checksum was written.
+ */
+struct net_buf *net_tcp_set_chksum(struct net_pkt *pkt, struct net_buf *frag);
+
+/**
+ * @brief Get TCP checksum from network packet.
+ *
+ * @param pkt Network packet
+ * @param frag Fragment where to start calculating the offset.
+ * Typically this is set to pkt->frags by the caller.
+ *
+ * @return Return the checksum in host byte order.
+ */
+u16_t net_tcp_get_chksum(struct net_pkt *pkt, struct net_buf *frag);
+#else
+#define net_tcp_get_chksum(pkt, frag) (0)
+#define net_tcp_set_chksum(pkt, frag) NULL
+#define net_tcp_set_hdr(pkt, frag) NULL
+#endif
+
+#if defined(CONFIG_NET_TCP)
void net_tcp_init(void);
#else
#define net_tcp_init(...)
diff --git a/tests/net/tcp/src/main.c b/tests/net/tcp/src/main.c
index 1b21de2..78aba86 100644
--- a/tests/net/tcp/src/main.c
+++ b/tests/net/tcp/src/main.c
@@ -61,6 +61,8 @@
static struct sockaddr_in my_v4_addr;
static struct sockaddr_in peer_v4_addr;
+#define NET_TCP_HDR(pkt) net_pkt_tcp_data(pkt)
+
#define MY_TCP_PORT 5545
#define PEER_TCP_PORT 9876
@@ -258,27 +260,30 @@
u16_t remote_port,
u16_t local_port)
{
- NET_IPV6_HDR(pkt)->vtc = 0x60;
- NET_IPV6_HDR(pkt)->tcflow = 0;
- NET_IPV6_HDR(pkt)->flow = 0;
- NET_IPV6_HDR(pkt)->len[0] = 0;
- NET_IPV6_HDR(pkt)->len[1] = NET_TCPH_LEN;
+ struct net_ipv6_hdr ipv6;
+ struct net_tcp_hdr tcp_hdr = { 0 };
+ u8_t data[] = { 'f', 'o', 'o', 'b', 'a', 'r' };
- NET_IPV6_HDR(pkt)->nexthdr = IPPROTO_TCP;
- NET_IPV6_HDR(pkt)->hop_limit = 255;
+ ipv6.vtc = 0x60;
+ ipv6.tcflow = 0;
+ ipv6.flow = 0;
+ ipv6.len[0] = 0;
+ ipv6.len[1] = NET_TCPH_LEN + sizeof(data);
+ ipv6.nexthdr = IPPROTO_TCP;
+ ipv6.hop_limit = 255;
- net_ipaddr_copy(&NET_IPV6_HDR(pkt)->src, remote_addr);
- net_ipaddr_copy(&NET_IPV6_HDR(pkt)->dst, local_addr);
+ net_ipaddr_copy(&ipv6.src, remote_addr);
+ net_ipaddr_copy(&ipv6.dst, local_addr);
net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr));
-
- NET_TCP_HDR(pkt)->src_port = htons(remote_port);
- NET_TCP_HDR(pkt)->dst_port = htons(local_port);
-
net_pkt_set_ipv6_ext_len(pkt, 0);
- net_buf_add(pkt->frags, net_pkt_ip_hdr_len(pkt) +
- sizeof(struct net_tcp_hdr));
+ tcp_hdr.src_port = htons(remote_port);
+ tcp_hdr.dst_port = htons(local_port);
+
+ net_pkt_append_all(pkt, sizeof(ipv6), (u8_t *)&ipv6, K_FOREVER);
+ net_pkt_append_all(pkt, sizeof(tcp_hdr), (u8_t *)&tcp_hdr, K_FOREVER);
+ net_pkt_append_all(pkt, sizeof(data), data, K_FOREVER);
}
static void setup_ipv4_tcp(struct net_pkt *pkt,
@@ -287,26 +292,120 @@
u16_t remote_port,
u16_t local_port)
{
- NET_IPV4_HDR(pkt)->vhl = 0x45;
- NET_IPV4_HDR(pkt)->tos = 0;
- NET_IPV4_HDR(pkt)->len[0] = 0;
- NET_IPV4_HDR(pkt)->len[1] = NET_TCPH_LEN +
+ struct net_ipv4_hdr ipv4;
+ struct net_tcp_hdr tcp_hdr = { 0 };
+ u8_t data[] = { 'f', 'o', 'o', 'b', 'a', 'r' };
+
+ ipv4.vhl = 0x45;
+ ipv4.tos = 0;
+ ipv4.len[0] = 0;
+ ipv4.len[1] = NET_TCPH_LEN + sizeof(data) +
sizeof(struct net_ipv4_hdr);
- NET_IPV4_HDR(pkt)->proto = IPPROTO_TCP;
+ ipv4.proto = IPPROTO_TCP;
- net_ipaddr_copy(&NET_IPV4_HDR(pkt)->src, remote_addr);
- net_ipaddr_copy(&NET_IPV4_HDR(pkt)->dst, local_addr);
+ net_ipaddr_copy(&ipv4.src, remote_addr);
+ net_ipaddr_copy(&ipv4.dst, local_addr);
net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr));
- NET_TCP_HDR(pkt)->src_port = htons(remote_port);
- NET_TCP_HDR(pkt)->dst_port = htons(local_port);
+ tcp_hdr.src_port = htons(remote_port);
+ tcp_hdr.dst_port = htons(local_port);
- net_pkt_set_ipv6_ext_len(pkt, 0);
+ net_pkt_append_all(pkt, sizeof(ipv4), (u8_t *)&ipv4, K_FOREVER);
+ net_pkt_append_all(pkt, sizeof(tcp_hdr), (u8_t *)&tcp_hdr, K_FOREVER);
+ net_pkt_append_all(pkt, sizeof(data), data, K_FOREVER);
+}
- net_buf_add(pkt->frags, net_pkt_ip_hdr_len(pkt) +
- sizeof(struct net_tcp_hdr));
+u8_t ipv6_hop_by_hop_ext_hdr[] = {
+/* Next header TCP */
+0x06,
+/* Length (multiple of 8 octets) */
+0x08,
+/* Experimental extension */
+0x3e,
+/* Length in bytes */
+0x20,
+0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+0x49, 0x4A, 0x4B, 0x4C, 0x4E, 0x4F, 0x50, 0x51,
+0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+0x5A, 0x5B, 0x5C, 0x5D, 0x5F, 0x60, 0x61, 0x62,
+/* Another experimental extension */
+0x3e,
+/* Length in bytes */
+0x20,
+0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A,
+0x6B, 0x6C, 0x6D, 0x6F, 0x70, 0x71, 0x72, 0x73,
+0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B,
+0x7C, 0x7D, 0x7E, 0x21, 0x22, 0x23, 0x24, 0x25,
+/* Padding */
+0x00,
+/* Padding */
+0x00,
+};
+
+static void setup_ipv6_tcp_long(struct net_pkt *pkt,
+ struct in6_addr *remote_addr,
+ struct in6_addr *local_addr,
+ u16_t remote_port,
+ u16_t local_port)
+{
+ struct net_tcp_hdr hdr, *tcp_hdr;
+ struct net_ipv6_hdr ipv6;
+ u8_t data[] = { 'f', 'o', 'o', 'b', 'a', 'r' };
+
+ ipv6.vtc = 0x60;
+ ipv6.tcflow = 0;
+ ipv6.flow = 0;
+ ipv6.len[0] = 0;
+ ipv6.len[1] = NET_TCPH_LEN + sizeof(data) +
+ sizeof(ipv6_hop_by_hop_ext_hdr);
+
+ ipv6.nexthdr = 0; /* Hop-by-hop option */
+ ipv6.hop_limit = 255;
+
+ net_ipaddr_copy(&ipv6.src, remote_addr);
+ net_ipaddr_copy(&ipv6.dst, local_addr);
+
+ net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr));
+
+ net_pkt_append_all(pkt, sizeof(ipv6), (u8_t *)&ipv6, K_FOREVER);
+ net_pkt_append_all(pkt, sizeof(ipv6_hop_by_hop_ext_hdr),
+ ipv6_hop_by_hop_ext_hdr, K_FOREVER);
+ net_pkt_append_all(pkt, sizeof(hdr), (u8_t *)&hdr, K_FOREVER);
+ net_pkt_append_all(pkt, sizeof(data), data, K_FOREVER);
+
+ net_pkt_set_ipv6_ext_len(pkt, sizeof(ipv6_hop_by_hop_ext_hdr));
+
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (tcp_hdr != &hdr) {
+ TC_ERROR("Invalid TCP header pointer\n");
+ return;
+ }
+
+ tcp_hdr->src_port = htons(remote_port);
+ tcp_hdr->dst_port = htons(local_port);
+
+ net_tcp_set_hdr(pkt, &hdr);
+
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (tcp_hdr != &hdr) {
+ TC_ERROR("Invalid TCP header pointer %p\n", tcp_hdr);
+ test_failed = true;
+ return;
+ }
+
+ if (tcp_hdr->src_port != htons(remote_port)) {
+ TC_ERROR("Invalid remote port, should have been %d was %d\n",
+ remote_port, ntohs(tcp_hdr->src_port));
+ test_failed = true;
+ }
+
+ if (tcp_hdr->dst_port != htons(local_port)) {
+ TC_ERROR("Invalid local port, should have been %d was %d\n",
+ local_port, ntohs(tcp_hdr->dst_port));
+ test_failed = true;
+ }
}
#define TIMEOUT K_MSEC(200)
@@ -342,11 +441,11 @@
}
if (k_sem_take(&recv_lock, TIMEOUT)) {
- DBG("Timeout, packet not received\n");
if (expect_failure) {
- return false;
- } else {
return true;
+ } else {
+ DBG("Timeout, packet not received\n");
+ return false;
}
}
@@ -393,11 +492,11 @@
}
if (k_sem_take(&recv_lock, TIMEOUT)) {
- DBG("Timeout, packet not received\n");
if (expect_failure) {
- return false;
- } else {
return true;
+ } else {
+ DBG("Timeout, packet not received\n");
+ return false;
}
}
@@ -413,6 +512,57 @@
return !fail;
}
+static bool send_ipv6_tcp_long_msg(struct net_if *iface,
+ struct in6_addr *src,
+ struct in6_addr *dst,
+ u16_t src_port,
+ u16_t dst_port,
+ struct ud *ud,
+ bool expect_failure)
+{
+ struct net_pkt *pkt;
+ struct net_buf *frag;
+ int ret;
+
+ pkt = net_pkt_get_reserve_tx(0, K_FOREVER);
+
+ net_pkt_set_ll_reserve(pkt, 0);
+
+ frag = net_pkt_get_frag(pkt, K_FOREVER);
+
+ net_pkt_frag_add(pkt, frag);
+
+ net_pkt_set_iface(pkt, iface);
+
+ setup_ipv6_tcp_long(pkt, src, dst, src_port, dst_port);
+
+ ret = net_recv_data(iface, pkt);
+ if (ret < 0) {
+ DBG("Cannot recv pkt %p, ret %d\n", pkt, ret);
+ return false;
+ }
+
+ if (k_sem_take(&recv_lock, TIMEOUT)) {
+ if (expect_failure) {
+ return true;
+ } else {
+ DBG("Timeout, packet not received\n");
+ return false;
+ }
+ }
+
+ /* Check that the returned user data is the same as what was given
+ * as a parameter.
+ */
+ if (ud != returned_ud && !expect_failure) {
+ DBG("IPv6 wrong user data %p returned, expected %p\n",
+ returned_ud, ud);
+ return false;
+ }
+
+ return !fail;
+}
+
static void set_port(sa_family_t family, struct sockaddr *raddr,
struct sockaddr *laddr, u16_t rport,
u16_t lport)
@@ -559,10 +709,28 @@
return false; \
}
+#define TEST_IPV6_LONG_OK(ud, raddr, laddr, rport, lport) \
+ st = send_ipv6_tcp_long_msg(iface, raddr, laddr, rport, lport, ud, \
+ false); \
+ if (!st) { \
+ DBG("%d: TCP long test \"%s\" fail\n", __LINE__, \
+ ud->test); \
+ return false; \
+ }
+
+#define TEST_IPV4_LONG_OK(ud, raddr, laddr, rport, lport) \
+ st = send_ipv4_tcp_long_msg(iface, raddr, laddr, rport, lport, ud, \
+ false); \
+ if (!st) { \
+ DBG("%d: TCP long_test \"%s\" fail\n", __LINE__, \
+ ud->test); \
+ return false; \
+ }
+
#define TEST_IPV6_FAIL(ud, raddr, laddr, rport, lport) \
st = send_ipv6_tcp_msg(iface, raddr, laddr, rport, lport, ud, \
true); \
- if (st) { \
+ if (!st) { \
DBG("%d: TCP neg test \"%s\" fail\n", __LINE__, \
ud->test); \
return false; \
@@ -571,7 +739,7 @@
#define TEST_IPV4_FAIL(ud, raddr, laddr, rport, lport) \
st = send_ipv4_tcp_msg(iface, raddr, laddr, rport, lport, ud, \
true); \
- if (st) { \
+ if (!st) { \
DBG("%d: TCP neg test \"%s\" fail\n", __LINE__, \
ud->test); \
return false; \
@@ -580,6 +748,8 @@
ud = REGISTER(AF_INET6, &any_addr6, &any_addr6, 1234, 4242);
TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242);
TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242);
+ TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242);
+ TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242);
TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400);
TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400);
UNREGISTER(ud);
@@ -594,6 +764,8 @@
ud = REGISTER(AF_INET6, &any_addr6, NULL, 1234, 4242);
TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242);
TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242);
+ TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242);
+ TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242);
TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400);
TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400);
UNREGISTER(ud);
@@ -601,6 +773,8 @@
ud = REGISTER(AF_INET6, NULL, &any_addr6, 1234, 4242);
TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242);
TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242);
+ TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242);
+ TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 1234, 4242);
TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400);
TEST_IPV6_FAIL(ud, &in6addr_peer, &in6addr_my, 1234, 61400);
UNREGISTER(ud);
@@ -629,6 +803,7 @@
ud = REGISTER(AF_UNSPEC, NULL, NULL, 0, 0);
TEST_IPV4_OK(ud, &in4addr_peer, &in4addr_my, 12345, 42421);
TEST_IPV6_OK(ud, &in6addr_peer, &in6addr_my, 12345, 42421);
+ TEST_IPV6_LONG_OK(ud, &in6addr_peer, &in6addr_my, 12345, 42421);
/* Remote addr same as local addr, these two will never match */
REGISTER(AF_INET6, &my_addr6, NULL, 1234, 4242);
@@ -756,6 +931,7 @@
struct net_tcp *tcp = v6_ctx->tcp;
u8_t flags = NET_TCP_RST;
struct net_pkt *pkt = NULL;
+ struct net_tcp_hdr hdr, *tcp_hdr;
int ret;
ret = net_tcp_prepare_segment(tcp, flags, NULL, 0, NULL,
@@ -767,7 +943,12 @@
net_hexdump_frags("TCPv6", pkt);
- if (!(NET_TCP_FLAGS(pkt) & NET_TCP_RST)) {
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return false;
+ }
+
+ if (!(NET_TCP_FLAGS(tcp_hdr) & NET_TCP_RST)) {
DBG("Reset flag not set\n");
return false;
}
@@ -787,6 +968,7 @@
struct net_tcp *tcp = v4_ctx->tcp;
u8_t flags = NET_TCP_RST;
struct net_pkt *pkt = NULL;
+ struct net_tcp_hdr hdr, *tcp_hdr;
int ret;
ret = net_tcp_prepare_segment(tcp, flags, NULL, 0, NULL,
@@ -798,7 +980,12 @@
net_hexdump_frags("TCPv4", pkt);
- if (!(NET_TCP_FLAGS(pkt) & NET_TCP_RST)) {
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return false;
+ }
+
+ if (!(NET_TCP_FLAGS(tcp_hdr) & NET_TCP_RST)) {
DBG("Reset flag not set\n");
return false;
}
@@ -818,6 +1005,7 @@
struct net_tcp *tcp = v6_ctx->tcp;
u8_t flags = NET_TCP_SYN;
struct net_pkt *pkt = NULL;
+ struct net_tcp_hdr hdr, *tcp_hdr;
int ret;
ret = net_tcp_prepare_segment(tcp, flags, NULL, 0, NULL,
@@ -829,7 +1017,12 @@
net_hexdump_frags("TCPv6", pkt);
- if (!(NET_TCP_FLAGS(pkt) & NET_TCP_SYN)) {
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return false;
+ }
+
+ if (!(NET_TCP_FLAGS(tcp_hdr) & NET_TCP_SYN)) {
DBG("SYN flag not set\n");
return false;
}
@@ -849,6 +1042,7 @@
struct net_tcp *tcp = v4_ctx->tcp;
u8_t flags = NET_TCP_SYN;
struct net_pkt *pkt = NULL;
+ struct net_tcp_hdr hdr, *tcp_hdr;
int ret;
ret = net_tcp_prepare_segment(tcp, flags, NULL, 0, NULL,
@@ -860,7 +1054,12 @@
net_hexdump_frags("TCPv4", pkt);
- if (!(NET_TCP_FLAGS(pkt) & NET_TCP_SYN)) {
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return false;
+ }
+
+ if (!(NET_TCP_FLAGS(tcp_hdr) & NET_TCP_SYN)) {
DBG("Reset flag not set\n");
return false;
}
@@ -880,6 +1079,7 @@
struct net_tcp *tcp = v6_ctx->tcp;
u8_t flags = NET_TCP_SYN | NET_TCP_ACK;
struct net_pkt *pkt = NULL;
+ struct net_tcp_hdr hdr, *tcp_hdr;
int ret;
ret = net_tcp_prepare_segment(tcp, flags, NULL, 0, NULL,
@@ -891,8 +1091,13 @@
net_hexdump_frags("TCPv6", pkt);
- if (!((NET_TCP_FLAGS(pkt) & NET_TCP_SYN) &&
- (NET_TCP_FLAGS(pkt) & NET_TCP_ACK))) {
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return false;
+ }
+
+ if (!((NET_TCP_FLAGS(tcp_hdr) & NET_TCP_SYN) &&
+ (NET_TCP_FLAGS(tcp_hdr) & NET_TCP_ACK))) {
DBG("SYN|ACK flag not set\n");
return false;
}
@@ -912,6 +1117,7 @@
struct net_tcp *tcp = v4_ctx->tcp;
u8_t flags = NET_TCP_SYN | NET_TCP_ACK;
struct net_pkt *pkt = NULL;
+ struct net_tcp_hdr hdr, *tcp_hdr;
int ret;
ret = net_tcp_prepare_segment(tcp, flags, NULL, 0, NULL,
@@ -923,8 +1129,13 @@
net_hexdump_frags("TCPv4", pkt);
- if (!((NET_TCP_FLAGS(pkt) & NET_TCP_SYN) &&
- (NET_TCP_FLAGS(pkt) & NET_TCP_ACK))) {
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return false;
+ }
+
+ if (!((NET_TCP_FLAGS(tcp_hdr) & NET_TCP_SYN) &&
+ (NET_TCP_FLAGS(tcp_hdr) & NET_TCP_ACK))) {
DBG("SYN|ACK flag not set\n");
return false;
}
@@ -944,6 +1155,7 @@
struct net_tcp *tcp = v6_ctx->tcp;
u8_t flags = NET_TCP_FIN;
struct net_pkt *pkt = NULL;
+ struct net_tcp_hdr hdr, *tcp_hdr;
int ret;
ret = net_tcp_prepare_segment(tcp, flags, NULL, 0, NULL,
@@ -955,7 +1167,12 @@
net_hexdump_frags("TCPv6", pkt);
- if (!(NET_TCP_FLAGS(pkt) & NET_TCP_FIN)) {
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return false;
+ }
+
+ if (!(NET_TCP_FLAGS(tcp_hdr) & NET_TCP_FIN)) {
DBG("FIN flag not set\n");
return false;
}
@@ -975,6 +1192,7 @@
struct net_tcp *tcp = v4_ctx->tcp;
u8_t flags = NET_TCP_FIN;
struct net_pkt *pkt = NULL;
+ struct net_tcp_hdr hdr, *tcp_hdr;
int ret;
ret = net_tcp_prepare_segment(tcp, flags, NULL, 0, NULL,
@@ -986,7 +1204,12 @@
net_hexdump_frags("TCPv4", pkt);
- if (!(NET_TCP_FLAGS(pkt) & NET_TCP_FIN)) {
+ tcp_hdr = net_tcp_get_hdr(pkt, &hdr);
+ if (!tcp_hdr) {
+ return false;
+ }
+
+ if (!(NET_TCP_FLAGS(tcp_hdr) & NET_TCP_FIN)) {
DBG("FIN flag not set\n");
return false;
}