Repository navigation
Held back IPv6 TCP segments while the source address is not valid - #490
Merged
Merged
Conversation
Deleting an IPv6 address, or disabling IPv6, while a TCP connection uses it clears the address entry and detaches it from its interface, but the socket keeps pointing at the entry. The data path refuses to send in that state with NX_NO_INTERFACE_ADDRESS, and once an address is set in the same entry again the connection carries on, which netx_tcp_ipv6_basic_processing_test relies on. The control path (ACK, FIN, RST, keepalive, window probe) and the retransmission path did not check: the next such segment reached _nx_ipv6_packet_send, whose NX_ASSERT on the attached interface puts the sending thread to sleep forever with the IP protection mutex held, deadlocking the IP instance. With NX_DISABLE_ASSERT it is a NULL dereference. _nx_tcp_packet_send_control and _nx_tcp_socket_retransmit now make the data path's check. While the connection's IPv6 source address is not valid, a control segment is dropped, as one lost on the link would be, and a retransmission sends nothing and leaves the packets queued; the retry count still limits how long. Added netx_ipv6_address_delete_tcp_test and netx_ipv6_disable_tcp_test. With the fix reverted both hang to their bound in v6_full_build and v6_only_build; with it they pass in v6_full_build, v6_build, v6_small_build, v6_no_reset_disconn_build and v6_only_build, as do netx_tcp_ipv6_basic_processing_test, netx_ipv6_address_delete_test and netx_ipv6_disable_test. Assisted-by: Claude Code (Opus 5.5) <noreply@anthropic.com>
tinic
added a commit
to tinic/netxduo
that referenced
this pull request
Oct 22, 2026
Upstream eclipse-threadx#490 protects control and retransmission sends while an IPv6 source is invalid. It supersedes the fork reset-on-delete workaround. Preserve SYN-cache flush and deletion notifications; retain the new native tests for queued data, source restoration and continued connection use. Integration assisted by OpenAI Codex (GPT-6).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Deleting an IPv6 address with
nxd_ipv6_address_delete, or disabling IPv6 withnxd_ipv6_disable,while a TCP connection uses that address, deadlocks the IP instance.
Both services clear the address entry, which detaches it from its interface
(
nxd_ipv6_address_attachedbecomesNX_NULL). The TCP socket keepsnx_tcp_socket_ipv6_addrpointing at the entry. That much is by design. The data path checks the address and refuses with
NX_NO_INTERFACE_ADDRESS. Once an address is set in the same entry again, the connection carrieson.
netx_tcp_ipv6_basic_processing_testasserts exactly that.The control path and the retransmission path do not check. The next ACK, FIN, RST, keepalive or
window probe (
_nx_tcp_packet_send_control), or the next retransmission(
_nx_tcp_socket_retransmit), reaches_nx_ipv6_packet_send. There,NX_ASSERT(if_ptr != NX_NULL)(nx_ipv6_packet_send.c:113) runstx_thread_sleep(NX_WAIT_FOREVER)withnx_ip_protectionheld. Every later caller of the IPinstance, the IP thread included, blocks on the mutex. With
NX_DISABLE_ASSERTit is a NULLdereference instead.
The usual trigger is a delayed ACK falling due on the IP thread's fast periodic timer after the
delete. The stack below was captured with gdb on 6.4.1. On
devthe path is the same, and thetests below hang there identically.
Prefix expiry and DAD failure invalidate an address without detaching it, so the header build
refuses the segment gracefully. Only the two API paths that clear the entry have this outcome.
Change
_nx_tcp_packet_send_controland_nx_tcp_socket_retransmitnow make the check the data pathalready makes. While the connection's IPv6 source address is not
NX_IPV6_ADDR_STATE_VALID:how long.
The change is 13 lines in each file and nothing else changes. Once an address is set again,
retransmission resumes and the peer receives the data.
Tests
netx_ipv6_address_delete_tcp_test: an acknowledgment falls due while the address is gone,and so does the retransmission of a data segment lost on the link. A send is refused with
NX_NO_INTERFACE_ADDRESS. After the address is set again, the retransmitted data arrives and theconnection is used and closed normally.
netx_ipv6_disable_tcp_test: an acknowledgment falls due while IPv6 is disabled. An IPv4connection on the same instance keeps carrying data. After enable and address set, the IPv6
connection carries data both ways.
Controlled experiment on
dev(2cd5aa4e), the fix reverted and the tests kept:With the fix: both new tests pass, as do
netx_tcp_ipv6_basic_processing_test,netx_ipv6_address_delete_testandnetx_ipv6_disable_test. Configurations:v6_full_build,v6_build,v6_small_build,v6_no_reset_disconn_build,v6_only_build,v6_no_chain_build.Sweep: the two new tests ran five times each in all 43 NetX Duo configurations. Result: 29
pass, 14 report N/A, 0 failures. The split is exactly the configurations with and without IPv6.
The two no-chain configurations were run after #489 restored their build; this branch is rebased
on it.
netx_tcp_ipv6_basic_processing_testpassing in both directions is the control. It shows thetests are not simply broken, and that the existing contract — the connection survives the delete
and carries on after the address is set again — is kept.