From a4881b949cbf8995e6a6524e780ce58c39efa33c Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Fri, 10 Jul 2026 06:51:15 -0700 Subject: [PATCH] [posix] drain TREL UDP packets per mainloop iteration (#13324) This commit updates `ReceivePacket()` in the POSIX TREL platform implementation (`trel.cpp`) to drain all available UDP datagrams in a loop whenever the TREL socket (`sSocket`) is readable. Previously, `ReceivePacket()` called `recvfrom()` exactly once per `platformTrelProcess()` iteration. When multiple TREL packets (such as an `AddressNotify` immediately followed by MLE or UDP traffic) arrived in rapid succession, only the first datagram was read, leaving the remaining packets buffered in the kernel until subsequent mainloop cycles. If an interleaved packet on another interface (such as `NcpSpinel` on 15.4) was processed before the next mainloop iteration, the neighbor's `mLastRxFragmentTag` advanced, causing the delayed TREL datagram (`AddressNotify`) to be dropped as `kErrorDuplicated` due to `!neighbor->IsLastRxFragmentTagAfter(tag)`. By looping over `recvfrom()` until `EAGAIN` or `EWOULDBLOCK` is returned (`sSocket` is non-blocking), all queued TREL packets are read and processed immediately in receipt order. A loop budget (`kMaxRxPacketsPerIteration = 64`) is included to prevent mainloop starvation during high-rate UDP floods. Additionally, a typo in the buffer overflow check (`sizeof(sRxPacketLength)` vs `sizeof(sRxPacketBuffer)`) is corrected. --- src/posix/platform/trel.cpp | 61 ++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/src/posix/platform/trel.cpp b/src/posix/platform/trel.cpp index f2d2d8e0d..eb5eecacc 100644 --- a/src/posix/platform/trel.cpp +++ b/src/posix/platform/trel.cpp @@ -276,37 +276,50 @@ exit: static void ReceivePacket(int aSocket, otInstance *aInstance) { - struct sockaddr_in6 sockAddr; - socklen_t sockAddrLen = sizeof(sockAddr); - ssize_t ret; + const uint16_t kMaxRxPacketsPerIteration = 64; - memset(&sockAddr, 0, sizeof(sockAddr)); - - ret = recvfrom(aSocket, (char *)sRxPacketBuffer, sizeof(sRxPacketBuffer), 0, (struct sockaddr *)&sockAddr, - &sockAddrLen); - VerifyOrDie(ret >= 0, OT_EXIT_ERROR_ERRNO); - - sRxPacketLength = (uint16_t)(ret); - - if (sRxPacketLength > sizeof(sRxPacketBuffer)) + for (uint16_t i = 0; i < kMaxRxPacketsPerIteration;) { - sRxPacketLength = sizeof(sRxPacketLength); - } + struct sockaddr_in6 sockAddr; + socklen_t sockAddrLen = sizeof(sockAddr); + ssize_t ret; - LogDebg("ReceivePacket() - received from [%s]:%d, id:%d, pkt:%s", Ip6AddrToString(&sockAddr.sin6_addr), - ntohs(sockAddr.sin6_port), sockAddr.sin6_scope_id, BufferToString(sRxPacketBuffer, sRxPacketLength)); + memset(&sockAddr, 0, sizeof(sockAddr)); - if (sEnabled) - { - otSockAddr senderAddr; + ret = recvfrom(aSocket, (char *)sRxPacketBuffer, sizeof(sRxPacketBuffer), 0, (struct sockaddr *)&sockAddr, + &sockAddrLen); + if (ret < 0) + { + if (errno == EAGAIN || errno == EWOULDBLOCK) + { + break; + } + if (errno == EINTR) + { + continue; + } + VerifyOrDie(false, OT_EXIT_ERROR_ERRNO); + } - ++sCounters.mRxPackets; - sCounters.mRxBytes += sRxPacketLength; + sRxPacketLength = (uint16_t)(ret); - memcpy(&senderAddr.mAddress, &sockAddr.sin6_addr, sizeof(otIp6Address)); - senderAddr.mPort = ntohs(sockAddr.sin6_port); + LogDebg("ReceivePacket() - received from [%s]:%d, id:%d, pkt:%s", Ip6AddrToString(&sockAddr.sin6_addr), + ntohs(sockAddr.sin6_port), sockAddr.sin6_scope_id, BufferToString(sRxPacketBuffer, sRxPacketLength)); - otPlatTrelHandleReceived(aInstance, sRxPacketBuffer, sRxPacketLength, &senderAddr); + if (sEnabled) + { + otSockAddr senderAddr; + + ++sCounters.mRxPackets; + sCounters.mRxBytes += sRxPacketLength; + + memcpy(&senderAddr.mAddress, &sockAddr.sin6_addr, sizeof(otIp6Address)); + senderAddr.mPort = ntohs(sockAddr.sin6_port); + + otPlatTrelHandleReceived(aInstance, sRxPacketBuffer, sRxPacketLength, &senderAddr); + } + + i++; } }