Skip to content

Held back IPv6 TCP segments while the source address is not valid - #490

Merged
fdesbiens merged 1 commit into
devfrom
fix/ipv6-tcp-address-delete
Oct 17, 2026
Merged

fdesbiens merged 1 commit into
devfrom
fix/ipv6-tcp-address-delete

Conversation

@fdesbiens

Copy link
Copy Markdown
Contributor

Problem

Deleting an IPv6 address with nxd_ipv6_address_delete, or disabling IPv6 with nxd_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_attached becomes NX_NULL). The TCP socket keeps nx_tcp_socket_ipv6_addr
pointing 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 carries
on. netx_tcp_ipv6_basic_processing_test asserts 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) runs
tx_thread_sleep(NX_WAIT_FOREVER) with nx_ip_protection held. Every later caller of the IP
instance, the IP thread included, blocks on the mutex. With NX_DISABLE_ASSERT it is a NULL
dereference 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 dev the path is the same, and the
tests below hang there identically.

_tx_thread_sleep(0xFFFFFFFF)
_nx_ipv6_packet_send
_nx_tcp_packet_send_control
_nx_tcp_packet_send_ack
_nx_tcp_fast_periodic_processing
_nx_ip_thread_entry

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_control and _nx_tcp_socket_retransmit now make the check the data path
already makes. While the connection's IPv6 source address is not NX_IPV6_ADDR_STATE_VALID:

  • Control segment: dropped, as one lost on the link would be.
  • Retransmission: nothing is sent and the packets stay queued. The retry count still limits
    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 the
    connection is used and closed normally.
  • netx_ipv6_disable_tcp_test: an acknowledgment falls due while IPv6 is disabled. An IPv4
    connection 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:

v6_full_build   netx_ipv6_address_delete_tcp_test     hangs (timeout, exit 124)
v6_full_build   netx_ipv6_disable_tcp_test            hangs (timeout, exit 124)
v6_full_build   netx_tcp_ipv6_basic_processing_test   SUCCESS
v6_only_build   (same three results)

With the fix: both new tests pass, as do netx_tcp_ipv6_basic_processing_test,
netx_ipv6_address_delete_test and netx_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_test passing in both directions is the control. It shows the
tests 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.

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>
@fdesbiens
fdesbiens merged commit 86aa854 into dev Oct 17, 2026
22 checks passed
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).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant