diff --git a/src/inet/UDPEndPointImplLwIP.cpp b/src/inet/UDPEndPointImplLwIP.cpp index 8690fb3839377c..0226eb719a4c44 100644 --- a/src/inet/UDPEndPointImplLwIP.cpp +++ b/src/inet/UDPEndPointImplLwIP.cpp @@ -23,6 +23,8 @@ #include +#include + #if CHIP_HAVE_CONFIG_H #include // nogncheck #endif // CHIP_HAVE_CONFIG_H @@ -35,16 +37,14 @@ #include #include #include +#include #include #include #include -static_assert(LWIP_VERSION_MAJOR > 1, "CHIP requires LwIP 2.0 or later"); +#include -#if !(CHIP_DEVICE_LAYER_TARGET_BL602 || CHIP_DEVICE_LAYER_TARGET_BL702 || CHIP_DEVICE_LAYER_TARGET_BL702L || \ - CHIP_DEVICE_LAYER_TARGET_ASR) -static_assert(LWIP_TCPIP_CORE_LOCKING, "CHIP requires config LWIP_TCPIP_CORE_LOCKING enabled"); -#endif +static_assert(LWIP_VERSION_MAJOR > 1, "CHIP requires LwIP 2.0 or later"); #if !defined(RAW_FLAGS_MULTICAST_LOOP) || !defined(UDP_FLAGS_MULTICAST_LOOP) || !defined(raw_clear_flags) || \ !defined(raw_set_flags) || !defined(udp_clear_flags) || !defined(udp_set_flags) @@ -67,27 +67,24 @@ static_assert(LWIP_TCPIP_CORE_LOCKING, "CHIP requires config LWIP_TCPIP_CORE_LOC namespace chip { namespace Inet { -namespace { -/** - * @brief - * RAII locking for LwIP core to simplify management of - * LOCK_TCPIP_CORE()/UNLOCK_TCPIP_CORE() calls. - */ -class ScopedLwIPLock +EndpointQueueFilter * UDPEndPointImplLwIP::sQueueFilter = nullptr; + +struct TCPIPCallContext { -public: - ScopedLwIPLock() { LOCK_TCPIP_CORE(); } - ~ScopedLwIPLock() { UNLOCK_TCPIP_CORE(); } + struct tcpip_api_call_data call; + std::function fn; }; -} // anonymous namespace -EndpointQueueFilter * UDPEndPointImplLwIP::sQueueFilter = nullptr; +err_t RunOnTCPIP(std::function fn) +{ + TCPIPCallContext ctx = { .fn = fn }; + return tcpip_api_call([](struct tcpip_api_call_data * call) { return reinterpret_cast(call)->fn(); }, + &ctx.call); +} CHIP_ERROR UDPEndPointImplLwIP::BindImpl(IPAddressType addressType, const IPAddress & address, uint16_t port, InterfaceId interfaceId) { - ScopedLwIPLock lwipLock; - // Make sure we have the appropriate type of PCB. CHIP_ERROR res = GetPCB(addressType); @@ -100,7 +97,7 @@ CHIP_ERROR UDPEndPointImplLwIP::BindImpl(IPAddressType addressType, const IPAddr if (res == CHIP_NO_ERROR) { - res = chip::System::MapErrorLwIP(udp_bind(mUDP, &ipAddr, port)); + res = chip::System::MapErrorLwIP(RunOnTCPIP([this, &ipAddr, port]() { return udp_bind(mUDP, &ipAddr, port); })); } if (res == CHIP_NO_ERROR) @@ -113,10 +110,7 @@ CHIP_ERROR UDPEndPointImplLwIP::BindImpl(IPAddressType addressType, const IPAddr CHIP_ERROR UDPEndPointImplLwIP::BindInterfaceImpl(IPAddressType addrType, InterfaceId intfId) { - // A lock is required because the LwIP thread may be referring to intf_filter, - // while this code running in the Inet application is potentially modifying it. // NOTE: this only supports LwIP interfaces whose number is no bigger than 9. - ScopedLwIPLock lwipLock; // Make sure we have the appropriate type of PCB. CHIP_ERROR err = GetPCB(addrType); @@ -140,14 +134,15 @@ CHIP_ERROR UDPEndPointImplLwIP::LwIPBindInterface(struct udp_pcb * aUDP, Interfa } } - udp_bind_netif(aUDP, netifp); + RunOnTCPIP([aUDP, netifp]() { + udp_bind_netif(aUDP, netifp); + return ERR_OK; + }); return CHIP_NO_ERROR; } InterfaceId UDPEndPointImplLwIP::GetBoundInterface() const { - ScopedLwIPLock lwipLock; - #if HAVE_LWIP_UDP_BIND_NETIF return InterfaceId(netif_get_by_index(mUDP->netif_idx)); #else @@ -162,9 +157,10 @@ uint16_t UDPEndPointImplLwIP::GetBoundPort() const CHIP_ERROR UDPEndPointImplLwIP::ListenImpl() { - ScopedLwIPLock lwipLock; - - udp_recv(mUDP, LwIPReceiveUDPMessage, this); + RunOnTCPIP([this]() { + udp_recv(mUDP, LwIPReceiveUDPMessage, this); + return ERR_OK; + }); return CHIP_NO_ERROR; } @@ -186,50 +182,47 @@ CHIP_ERROR UDPEndPointImplLwIP::SendMsgImpl(const IPPacketInfo * pktInfo, System CHIP_ERROR res = CHIP_NO_ERROR; err_t lwipErr = ERR_VAL; - // Adding a scope here to unlock the LwIP core when the lock is no longer required. + // Make sure we have the appropriate type of PCB based on the destination address. + res = GetPCB(destAddr.Type()); + if (res != CHIP_NO_ERROR) { - ScopedLwIPLock lwipLock; - - // Make sure we have the appropriate type of PCB based on the destination address. - res = GetPCB(destAddr.Type()); - if (res != CHIP_NO_ERROR) - { - return res; - } + return res; + } - // Send the message to the specified address/port. - // If an outbound interface has been specified, call a specific version of the UDP sendto() - // function that accepts the target interface. - // If a source address has been specified, temporarily override the local_ip of the PCB. - // This results in LwIP using the given address being as the source address for the generated - // packet, as if the PCB had been bound to that address. - const IPAddress & srcAddr = pktInfo->SrcAddress; - const uint16_t & destPort = pktInfo->DestPort; - const InterfaceId & intfId = pktInfo->Interface; + // Send the message to the specified address/port. + // If an outbound interface has been specified, call a specific version of the UDP sendto() + // function that accepts the target interface. + // If a source address has been specified, temporarily override the local_ip of the PCB. + // This results in LwIP using the given address being as the source address for the generated + // packet, as if the PCB had been bound to that address. + const IPAddress & srcAddr = pktInfo->SrcAddress; + const uint16_t & destPort = pktInfo->DestPort; + const InterfaceId & intfId = pktInfo->Interface; - ip_addr_t lwipSrcAddr = srcAddr.ToLwIPAddr(); - ip_addr_t lwipDestAddr = destAddr.ToLwIPAddr(); + ip_addr_t lwipSrcAddr = srcAddr.ToLwIPAddr(); + ip_addr_t lwipDestAddr = destAddr.ToLwIPAddr(); - ip_addr_t boundAddr; - ip_addr_copy(boundAddr, mUDP->local_ip); + ip_addr_t boundAddr; + ip_addr_copy(boundAddr, mUDP->local_ip); - if (!ip_addr_isany(&lwipSrcAddr)) - { - ip_addr_copy(mUDP->local_ip, lwipSrcAddr); - } + if (!ip_addr_isany(&lwipSrcAddr)) + { + ip_addr_copy(mUDP->local_ip, lwipSrcAddr); + } + lwipErr = RunOnTCPIP([this, &intfId, &msg, &lwipDestAddr, destPort]() { if (intfId.IsPresent()) { - lwipErr = udp_sendto_if(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort, - intfId.GetPlatformInterface()); + return udp_sendto_if(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort, + intfId.GetPlatformInterface()); } else { - lwipErr = udp_sendto(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort); + return udp_sendto(mUDP, System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(msg), &lwipDestAddr, destPort); } + }); - ip_addr_copy(mUDP->local_ip, boundAddr); - } + ip_addr_copy(mUDP->local_ip, boundAddr); if (lwipErr != ERR_OK) { @@ -241,13 +234,14 @@ CHIP_ERROR UDPEndPointImplLwIP::SendMsgImpl(const IPPacketInfo * pktInfo, System void UDPEndPointImplLwIP::CloseImpl() { - ScopedLwIPLock lwipLock; - // Since UDP PCB is released synchronously here, but UDP endpoint itself might have to wait // for destruction asynchronously, there could be more allocated UDP endpoints than UDP PCBs. if (mUDP != nullptr) { - udp_remove(mUDP); + RunOnTCPIP([this]() { + udp_remove(mUDP); + return ERR_OK; + }); mUDP = nullptr; mLwIPEndPointType = LwIPEndPointType::Unknown; @@ -315,12 +309,18 @@ CHIP_ERROR UDPEndPointImplLwIP::GetPCB(IPAddressType addrType) // Allocate a PCB of the appropriate type. if (addrType == IPAddressType::kIPv6) { - mUDP = udp_new_ip_type(IPADDR_TYPE_V6); + RunOnTCPIP([this]() { + mUDP = udp_new_ip_type(IPADDR_TYPE_V6); + return ERR_OK; + }); } #if INET_CONFIG_ENABLE_IPV4 else if (addrType == IPAddressType::kIPv4) { - mUDP = udp_new_ip_type(IPADDR_TYPE_V4); + RunOnTCPIP([this]() { + mUDP = udp_new_ip_type(IPADDR_TYPE_V4); + return ERR_OK; + }); } #endif // INET_CONFIG_ENABLE_IPV4 else @@ -370,14 +370,20 @@ void UDPEndPointImplLwIP::LwIPReceiveUDPMessage(void * arg, struct udp_pcb * pcb u16_t port) { UDPEndPointImplLwIP * ep = static_cast(arg); + + // This + DeviceLayer::PlatformMgr().LockChipStack(); + if (ep->mState == State::kClosed) { + DeviceLayer::PlatformMgr().UnlockChipStack(); return; } auto pktInfo = Platform::MakeUnique(); if (pktInfo.get() == nullptr) { + DeviceLayer::PlatformMgr().UnlockChipStack(); ChipLogError(Inet, "Cannot allocate packet info"); return; } @@ -415,12 +421,14 @@ void UDPEndPointImplLwIP::LwIPReceiveUDPMessage(void * arg, struct udp_pcb * pcb if (filterOutcome != EndpointQueueFilter::FilterOutcome::kAllowPacket) { // Logging, if any, should be at the choice of the filter impl at time of filtering. + DeviceLayer::PlatformMgr().UnlockChipStack(); return; } // Increase mDelayReleaseCount to delay release of this UDP EndPoint while the HandleDataReceived call is // pending on it. ep->mDelayReleaseCount++; + DeviceLayer::PlatformMgr().UnlockChipStack(); CHIP_ERROR err = ep->GetSystemLayer().ScheduleLambda( [ep, p = System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(buf), pktInfo = pktInfo.get()] { @@ -439,6 +447,7 @@ void UDPEndPointImplLwIP::LwIPReceiveUDPMessage(void * arg, struct udp_pcb * pcb } else { + DeviceLayer::PlatformMgr().LockChipStack(); // On failure to enqueue the processing, we have to tell the filter that // the packet is basically dequeued, if it tries to keep track of the lifecycle. if (sQueueFilter != nullptr) @@ -448,6 +457,7 @@ void UDPEndPointImplLwIP::LwIPReceiveUDPMessage(void * arg, struct udp_pcb * pcb } ep->mDelayReleaseCount--; + DeviceLayer::PlatformMgr().UnlockChipStack(); } } @@ -475,26 +485,25 @@ CHIP_ERROR UDPEndPointImplLwIP::IPv4JoinLeaveMulticastGroupImpl(InterfaceId aInt { #if LWIP_IPV4 && LWIP_IGMP const ip4_addr_t lIPv4Address = aAddress.ToIPv4(); - err_t lStatus; - + struct netif * lNetif = nullptr; + if (aInterfaceId.IsPresent()) { - ScopedLwIPLock lwipLock; + lNetif = FindNetifFromInterfaceId(aInterfaceId); + VerifyOrReturnError(lNetif != nullptr, INET_ERROR_UNKNOWN_INTERFACE); + } - if (aInterfaceId.IsPresent()) + err_t lStatus = RunOnTCPIP([lNetif, &lIPv4Address, join]() { + if (lNetif != nullptr) { - - struct netif * const lNetif = FindNetifFromInterfaceId(aInterfaceId); - VerifyOrReturnError(lNetif != nullptr, INET_ERROR_UNKNOWN_INTERFACE); - - lStatus = join ? igmp_joingroup_netif(lNetif, &lIPv4Address) // - : igmp_leavegroup_netif(lNetif, &lIPv4Address); + return join ? igmp_joingroup_netif(lNetif, &lIPv4Address) // + : igmp_leavegroup_netif(lNetif, &lIPv4Address); } else { - lStatus = join ? igmp_joingroup(IP4_ADDR_ANY4, &lIPv4Address) // - : igmp_leavegroup(IP4_ADDR_ANY4, &lIPv4Address); + return join ? igmp_joingroup(IP4_ADDR_ANY4, &lIPv4Address) // + : igmp_leavegroup(IP4_ADDR_ANY4, &lIPv4Address); } - } + }); if (lStatus == ERR_MEM) { @@ -511,24 +520,25 @@ CHIP_ERROR UDPEndPointImplLwIP::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInt { #ifdef HAVE_IPV6_MULTICAST const ip6_addr_t lIPv6Address = aAddress.ToIPv6(); - err_t lStatus; - + struct netif * lNetif = nullptr; + if (aInterfaceId.IsPresent()) { - ScopedLwIPLock lwipLock; + lNetif = FindNetifFromInterfaceId(aInterfaceId); + VerifyOrReturnError(lNetif != nullptr, INET_ERROR_UNKNOWN_INTERFACE); + } - if (aInterfaceId.IsPresent()) + err_t lStatus = RunOnTCPIP([lNetif, &lIPv6Address, join]() { + if (lNetif != nullptr) { - struct netif * const lNetif = FindNetifFromInterfaceId(aInterfaceId); - VerifyOrReturnError(lNetif != nullptr, INET_ERROR_UNKNOWN_INTERFACE); - lStatus = join ? mld6_joingroup_netif(lNetif, &lIPv6Address) // - : mld6_leavegroup_netif(lNetif, &lIPv6Address); + return join ? mld6_joingroup_netif(lNetif, &lIPv6Address) // + : mld6_leavegroup_netif(lNetif, &lIPv6Address); } else { - lStatus = join ? mld6_joingroup(IP6_ADDR_ANY6, &lIPv6Address) // - : mld6_leavegroup(IP6_ADDR_ANY6, &lIPv6Address); + return join ? mld6_joingroup(IP6_ADDR_ANY6, &lIPv6Address) // + : mld6_leavegroup(IP6_ADDR_ANY6, &lIPv6Address); } - } + }); if (lStatus == ERR_MEM) {