Skip to content

Commit 9d229e0

Browse files
Tomasz Bursztykacfriedt
authored andcommitted
net/tcp: Stop TCP state machine breaking when sending locally
On any target, running a TCP server and a net shell can show the issue: net tcp connect local_ip port will fail. Usally it ends up by consumming all tcp connection memory. This is because in tcp_in(), state changes will most of the time lead to sending SYN/ACK/etc... packets under the same thread, which will run all through net_send_data(), back to tcp_in(). Thus a forever loop on SYN -> SYN|ACK -> SYN -> SYN|ACK until tcp connection cannot be allocated anymore. Fixing it by scheduling any local packet to be sent on the queue. Fixes #38576 Signed-off-by: Tomasz Bursztyka <[email protected]>
1 parent 74c00d0 commit 9d229e0

File tree

1 file changed

+27
-1
lines changed

1 file changed

+27
-1
lines changed

subsys/net/ip/tcp2.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,25 @@ static int net_tcp_set_mss_opt(struct tcp *conn, struct net_pkt *pkt)
826826
return net_pkt_set_data(pkt, &mss_option);
827827
}
828828

829+
static bool is_destination_local(struct net_pkt *pkt)
830+
{
831+
if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) {
832+
if (net_ipv4_is_addr_loopback(&NET_IPV4_HDR(pkt)->dst) ||
833+
net_ipv4_is_my_addr(&NET_IPV4_HDR(pkt)->dst)) {
834+
return true;
835+
}
836+
}
837+
838+
if (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6) {
839+
if (net_ipv6_is_addr_loopback(&NET_IPV6_HDR(pkt)->dst) ||
840+
net_ipv6_is_my_addr(&NET_IPV6_HDR(pkt)->dst)) {
841+
return true;
842+
}
843+
}
844+
845+
return false;
846+
}
847+
829848
static int tcp_out_ext(struct tcp *conn, uint8_t flags, struct net_pkt *data,
830849
uint32_t seq)
831850
{
@@ -884,7 +903,14 @@ static int tcp_out_ext(struct tcp *conn, uint8_t flags, struct net_pkt *data,
884903

885904
sys_slist_append(&conn->send_queue, &pkt->next);
886905

887-
if (tcp_send_process_no_lock(conn)) {
906+
if (is_destination_local(pkt)) {
907+
/* If the destination is local, we have to let the current
908+
* thread to finish with any state-machine changes before
909+
* sending the packet, or it might lead to state unconsistencies
910+
*/
911+
k_work_schedule_for_queue(&tcp_work_q,
912+
&conn->send_timer, K_NO_WAIT);
913+
} else if (tcp_send_process_no_lock(conn)) {
888914
tcp_conn_unref(conn);
889915
}
890916
out:

0 commit comments

Comments
 (0)