Bug Summary
_nx_tcp_socket_send_internal does not restore nx_packet_prepend_ptr and nx_packet_length after a retransmit-retry path that retains the packet for re-attempt. The next attempt reuses the packet with its prepend pointer offset by sizeof(NX_TCP_HEADER) = 20. The wire-level segment is malformed: TCP header bytes are consumed twice. The host-side TCP stack flags repeated malformed segments and resets the connection.
Detailed Description
Environment
- MCU: STM32H563ZIT6
- Board: NUCLEO-H563ZI (MB1404 Rev C-01)
- Firmware pack: STM32CubeH5 FW.H5.1.6.0 (latest public release at filing)
- NetX Duo: 6.4.0 (Dec 28 2023, bundled with FW.H5.1.6.0)
- Affected file:
Middlewares/ST/netxduo/common/src/nx_tcp_socket_send_internal.c
- Affected function:
_nx_tcp_socket_send_internal
- Latest tagged NetX Duo upstream: 6.4.3 (Mar 18 2025) — also missing the fix
- Upstream fix: eclipse-threadx/netxduo@778b383 (Jan 9 2026, on master)
Summary
_nx_tcp_socket_send_internal does not restore nx_packet_prepend_ptr and nx_packet_length after a retransmit-retry path that retains the packet for re-attempt. The next attempt reuses the packet with its prepend pointer offset by sizeof(NX_TCP_HEADER) = 20. The wire-level segment is malformed: TCP header bytes are consumed twice. The host-side TCP stack flags repeated malformed segments and resets the connection.
Symptoms only show under sustained TCP load with retransmits (packet loss, ACK delay, or a busy host). At low connection rate the bug is invisible because retransmits do not fire.
Reproduction steps
- Build and flash any TCP echo server on a NUCLEO-H563ZI bound to a static IP on the host's subnet (e.g. 192.168.100.1/24, host at 192.168.100.230).
- From the host:
import socket
for i in range(1000):
s = socket.socket()
s.settimeout(5)
s.connect(("192.168.100.1", 7))
s.sendall(b"X" * 1400)
rx = s.recv(2048)
s.close()
- Observe successful round-trips for the first ~10 iterations, then
socket.timeout on iteration ~12-20 and beyond. Subsequent connections also time out; the device is unresponsive on the listen port (ICMP still works).
Expected behavior
All 1000 iterations round-trip cleanly.
Actual behavior
Iterations 0-N succeed (N typically 10-20). Iteration N+1 times out. All subsequent iterations time out. Halt under SWD shows the TCP server thread blocked inside the receive call; no HardFault. tcpdump on the host shows malformed TCP segments and host-stack RST emitted at the failure boundary.
Root cause
_nx_tcp_socket_send_internal line ~828 (NetX Duo 6.4.0):
/* Release the packet when the sequence is changed. */
if (send_packet != packet_ptr)
{
_nx_packet_release(send_packet);
}
/* (no else branch — packet retained for retry, but its prepend pointer
is left offset by the TCP header size from the previous attempt) */
/* Regain exclusive access to IP instance. */
tx_mutex_get(&(ip_ptr -> nx_ip_protection), TX_WAIT_FOREVER);
continue;
When the function takes the else (implicit) path — packet retained for retransmit — the prepend pointer and length are not restored to pre-attempt state. The retried packet's nx_packet_prepend_ptr is offset by sizeof(NX_TCP_HEADER) because the previous attempt consumed those header bytes. The retransmit therefore sends an additional 20 bytes of header-stripped payload on the wire.
Verification of root cause
Applying the upstream fix from commit 778b383 to Middlewares/ST/netxduo/common/src/nx_tcp_socket_send_internal.c resolves the failure entirely:
if (send_packet != packet_ptr)
{
_nx_packet_release(send_packet);
}
else
{
send_packet -> nx_packet_prepend_ptr += sizeof(NX_TCP_HEADER);
send_packet -> nx_packet_length -= sizeof(NX_TCP_HEADER);
}
Pre/post stress test on the same hardware:
| Test |
Pre-fix |
Post-fix |
| 1000 × 7-byte sequential |
Fails ~iter 12 |
1000/1000 PASS, 153 conn/s |
| 1000 × 1400-byte sustained |
Fails ~iter 12 |
1000/1000 PASS, 117 conn/s, 160 KB/s |
Bench-verified May 1 2026 on NUCLEO-H563ZI with the cumulative project's TCP echo server.
Suggested upstream fix
Cherry-pick eclipse-threadx/netxduo@778b383 into the next FW.H5 release, or bump the bundled NetX Duo to a tagged release that includes the commit. The fix has been on upstream master for roughly four months at filing; no released NetX Duo tag (latest 6.4.3, March 2025) yet contains it.
The same NetX Duo source is used across the STM32 firmware packs (FW.H7, FW.U5, FW.WB1M, etc.); customers on those packs may be hitting the same bug whenever sustained TCP traffic triggers a retransmit retry path.
Expected Behavior
No response
Actual Behavior
No response
Environment
No response
Severity
None
Bug Summary
_nx_tcp_socket_send_internaldoes not restorenx_packet_prepend_ptrandnx_packet_lengthafter a retransmit-retry path that retains the packet for re-attempt. The next attempt reuses the packet with its prepend pointer offset bysizeof(NX_TCP_HEADER) = 20. The wire-level segment is malformed: TCP header bytes are consumed twice. The host-side TCP stack flags repeated malformed segments and resets the connection.Detailed Description
Environment
Middlewares/ST/netxduo/common/src/nx_tcp_socket_send_internal.c_nx_tcp_socket_send_internalSummary
_nx_tcp_socket_send_internaldoes not restorenx_packet_prepend_ptrandnx_packet_lengthafter a retransmit-retry path that retains the packet for re-attempt. The next attempt reuses the packet with its prepend pointer offset bysizeof(NX_TCP_HEADER) = 20. The wire-level segment is malformed: TCP header bytes are consumed twice. The host-side TCP stack flags repeated malformed segments and resets the connection.Symptoms only show under sustained TCP load with retransmits (packet loss, ACK delay, or a busy host). At low connection rate the bug is invisible because retransmits do not fire.
Reproduction steps
socket.timeouton iteration ~12-20 and beyond. Subsequent connections also time out; the device is unresponsive on the listen port (ICMP still works).Expected behavior
All 1000 iterations round-trip cleanly.
Actual behavior
Iterations 0-N succeed (N typically 10-20). Iteration N+1 times out. All subsequent iterations time out. Halt under SWD shows the TCP server thread blocked inside the receive call; no HardFault.
tcpdumpon the host shows malformed TCP segments and host-stack RST emitted at the failure boundary.Root cause
_nx_tcp_socket_send_internalline ~828 (NetX Duo 6.4.0):When the function takes the
else(implicit) path — packet retained for retransmit — the prepend pointer and length are not restored to pre-attempt state. The retried packet'snx_packet_prepend_ptris offset bysizeof(NX_TCP_HEADER)because the previous attempt consumed those header bytes. The retransmit therefore sends an additional 20 bytes of header-stripped payload on the wire.Verification of root cause
Applying the upstream fix from commit 778b383 to
Middlewares/ST/netxduo/common/src/nx_tcp_socket_send_internal.cresolves the failure entirely:Pre/post stress test on the same hardware:
Bench-verified May 1 2026 on NUCLEO-H563ZI with the cumulative project's TCP echo server.
Suggested upstream fix
Cherry-pick eclipse-threadx/netxduo@778b383 into the next FW.H5 release, or bump the bundled NetX Duo to a tagged release that includes the commit. The fix has been on upstream master for roughly four months at filing; no released NetX Duo tag (latest 6.4.3, March 2025) yet contains it.
The same NetX Duo source is used across the STM32 firmware packs (FW.H7, FW.U5, FW.WB1M, etc.); customers on those packs may be hitting the same bug whenever sustained TCP traffic triggers a retransmit retry path.
Expected Behavior
No response
Actual Behavior
No response
Environment
No response
Severity
None