[socket] Apply SO_REUSEADDR to the pcb and unmap IPv4-mapped IPv6 destinations

This commit is contained in:
J. Nick Koston
2026-08-28 11:23:43 -05:00
parent a4d2a4ad4b
commit fd9760d8e3
4 changed files with 18 additions and 6 deletions
@@ -68,6 +68,11 @@ bool sockaddr_to_lwip(const struct sockaddr *addr, socklen_t addrlen, ip_addr_t
*port = ntohs(addr6->sin6_port);
IP_SET_TYPE_VAL(*ip, IPADDR_TYPE_V6);
memcpy(&ip_2_ip6(ip)->addr, &addr6->sin6_addr.un.u8_addr, 16);
// Unmap ::ffff:a.b.c.d so replies to recvfrom addresses route as IPv4
if (ip6_addr_isipv4mappedipv6(ip_2_ip6(ip))) {
unmap_ipv4_mapped_ipv6(ip_2_ip4(ip), ip_2_ip6(ip));
IP_SET_TYPE_VAL(*ip, IPADDR_TYPE_V4);
}
return true;
}
#endif
@@ -291,7 +291,7 @@ int LWIPRawCommon::setsockopt(int level, int optname, const void *optval, sockle
}
int LWIPRawCommon::ip2sockaddr_(ip_addr_t *ip, uint16_t port, struct sockaddr *name, socklen_t *addrlen) {
// TCP pcb stores port in network byte order; convert to host order for the shared helper
// lwip pcb ports are host order; ntohs preserves historical byte-swapped sin_port output
return lwip_ip_to_sockaddr(this->family_, ip, ntohs(port), name, addrlen);
}
@@ -122,8 +122,16 @@ int LWIPRawUDPSendImpl::setsockopt(int level, int optname, const void *optval, s
return -1;
}
if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
// lwip raw UDP doesn't enforce port exclusivity the same way,
// but we accept this silently for compatibility
if (optval == nullptr || optlen < sizeof(int)) {
errno = EINVAL;
return -1;
}
// Effective only where lwip is built with SO_REUSE=1 (ESP8266 yes, RP2040 currently no)
if (*reinterpret_cast<const int *>(optval)) {
ip_set_option(this->pcb_, SOF_REUSEADDR);
} else {
ip_reset_option(this->pcb_, SOF_REUSEADDR);
}
return 0;
}
if (level == SOL_SOCKET && optname == SO_BROADCAST) {
@@ -170,7 +178,7 @@ int LWIPRawUDPSendImpl::getsockopt(int level, int optname, void *optval, socklen
errno = EINVAL;
return -1;
}
*reinterpret_cast<int *>(optval) = 1;
*reinterpret_cast<int *>(optval) = ip_get_option(this->pcb_, SOF_REUSEADDR) ? 1 : 0;
*optlen = sizeof(int);
return 0;
}
@@ -96,8 +96,7 @@ class LWIPRawUDPImpl : private LWIPRawUDPSendImpl {
static constexpr uint8_t UDP_RX_QUEUE_SIZE = 4;
static constexpr uint8_t UDP_RX_MASK = UDP_RX_QUEUE_SIZE - 1;
static_assert((UDP_RX_QUEUE_SIZE & UDP_RX_MASK) == 0, "UDP_RX_QUEUE_SIZE must be power of 2");
// Fields are written by recv_fn_ before rx_count_ makes a slot visible,
// so per-member initializers would only add dead zeroing of the array.
// Fields are written by recv_fn_ before rx_count_ makes a slot visible
struct UDPRxPacket {
ip_addr_t src_addr;
struct pbuf *pb;