Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 1 | /* |
| 2 | * |
| 3 | * Copyright (c) 2020-2021 Project CHIP Authors |
| 4 | * Copyright (c) 2018 Google LLC. |
| 5 | * Copyright (c) 2013-2018 Nest Labs, Inc. |
| 6 | * |
| 7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 8 | * you may not use this file except in compliance with the License. |
| 9 | * You may obtain a copy of the License at |
| 10 | * |
| 11 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 12 | * |
| 13 | * Unless required by applicable law or agreed to in writing, software |
| 14 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 16 | * See the License for the specific language governing permissions and |
| 17 | * limitations under the License. |
| 18 | */ |
| 19 | |
Jean-Francois Penven | fd52919 | 2022-03-25 21:43:47 -0400 | [diff] [blame] | 20 | #include <inet/UDPEndPointImplOpenThread.h> |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 21 | |
| 22 | #include <lib/support/CodeUtils.h> |
| 23 | #include <lib/support/SafeInt.h> |
| 24 | #include <lib/support/logging/CHIPLogging.h> |
| 25 | |
| 26 | #include <platform/OpenThread/OpenThreadUtils.h> |
| 27 | |
| 28 | #include <system/SystemPacketBuffer.h> |
| 29 | |
| 30 | namespace chip { |
| 31 | namespace Inet { |
| 32 | |
Jean-Francois Penven | fa087ea | 2022-04-22 14:53:57 -0400 | [diff] [blame] | 33 | otInstance * globalOtInstance; |
| 34 | |
Boris Zbarsky | 3956a9d | 2022-05-26 14:38:43 -0400 | [diff] [blame] | 35 | namespace { |
| 36 | // We want to reserve space for an IPPacketInfo in our buffer, but it needs to |
Kevin Schoedel | 7b3fb84 | 2022-06-07 20:30:00 -0400 | [diff] [blame] | 37 | // be 4-byte aligned. We ensure the alignment by masking off the low bits of |
| 38 | // the pointer that we get by doing `Start() - sizeof(IPPacketInfo)`. That |
| 39 | // might move it backward by up to kPacketInfoAlignmentBytes, so we need to make |
| 40 | // sure we allocate enough reserved space that this will still be within our |
| 41 | // buffer. |
| 42 | constexpr uint16_t kPacketInfoAlignmentBytes = sizeof(uint32_t) - 1; |
Boris Zbarsky | 3956a9d | 2022-05-26 14:38:43 -0400 | [diff] [blame] | 43 | constexpr uint16_t kPacketInfoReservedSize = sizeof(IPPacketInfo) + kPacketInfoAlignmentBytes; |
| 44 | } // namespace |
| 45 | |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 46 | void UDPEndPointImplOT::handleUdpReceive(void * aContext, otMessage * aMessage, const otMessageInfo * aMessageInfo) |
| 47 | { |
| 48 | UDPEndPointImplOT * ep = static_cast<UDPEndPointImplOT *>(aContext); |
Boris Zbarsky | 3956a9d | 2022-05-26 14:38:43 -0400 | [diff] [blame] | 49 | uint16_t msgLen = otMessageGetLength(aMessage); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 50 | System::PacketBufferHandle payload; |
| 51 | #if CHIP_DETAIL_LOGGING |
| 52 | static uint16_t msgReceivedCount = 0; |
| 53 | char sourceStr[Inet::IPAddress::kMaxStringLength]; |
| 54 | char destStr[Inet::IPAddress::kMaxStringLength]; |
| 55 | #endif |
| 56 | |
Zang MingJie | f5eec6e | 2022-07-14 21:20:54 +0800 | [diff] [blame] | 57 | if (ep->mState == State::kClosed) |
| 58 | return; |
| 59 | |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 60 | if (msgLen > System::PacketBuffer::kMaxSizeWithoutReserve) |
| 61 | { |
| 62 | ChipLogError(Inet, "UDP message too long, discarding. Size received %d", msgLen); |
| 63 | return; |
| 64 | } |
| 65 | |
Boris Zbarsky | 3956a9d | 2022-05-26 14:38:43 -0400 | [diff] [blame] | 66 | payload = System::PacketBufferHandle::New(msgLen, kPacketInfoReservedSize); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 67 | |
| 68 | if (payload.IsNull()) |
| 69 | { |
| 70 | ChipLogError(Inet, "Failed to allocate a System buffer of size %d for UDP Message reception.", msgLen); |
| 71 | return; |
| 72 | } |
| 73 | |
Boris Zbarsky | 3956a9d | 2022-05-26 14:38:43 -0400 | [diff] [blame] | 74 | IPPacketInfo * pktInfo = GetPacketInfo(payload); |
| 75 | if (pktInfo == nullptr) |
| 76 | { |
| 77 | ChipLogError(Inet, "Failed to pre-allocate reserved space for an IPPacketInfo for UDP Message reception."); |
| 78 | return; |
| 79 | } |
| 80 | |
| 81 | pktInfo->SrcAddress = IPAddress::FromOtAddr(aMessageInfo->mPeerAddr); |
| 82 | pktInfo->DestAddress = IPAddress::FromOtAddr(aMessageInfo->mSockAddr); |
| 83 | pktInfo->SrcPort = aMessageInfo->mPeerPort; |
| 84 | pktInfo->DestPort = aMessageInfo->mSockPort; |
| 85 | |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 86 | #if CHIP_DETAIL_LOGGING |
Boris Zbarsky | 3956a9d | 2022-05-26 14:38:43 -0400 | [diff] [blame] | 87 | pktInfo->SrcAddress.ToString(sourceStr, Inet::IPAddress::kMaxStringLength); |
| 88 | pktInfo->DestAddress.ToString(destStr, Inet::IPAddress::kMaxStringLength); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 89 | |
| 90 | ChipLogDetail(Inet, |
Jean-Francois Penven | 316e665 | 2022-04-04 14:23:04 -0400 | [diff] [blame] | 91 | "UDP Message Received packet nb : %d SrcAddr : %s[%d] DestAddr " |
| 92 | ": %s[%d] Payload Length %d", |
Boris Zbarsky | 3956a9d | 2022-05-26 14:38:43 -0400 | [diff] [blame] | 93 | ++msgReceivedCount, sourceStr, pktInfo->SrcPort, destStr, pktInfo->DestPort, msgLen); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 94 | |
| 95 | #endif |
| 96 | |
Boris Zbarsky | 3956a9d | 2022-05-26 14:38:43 -0400 | [diff] [blame] | 97 | if (otMessageRead(aMessage, 0, payload->Start(), msgLen) != msgLen) |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 98 | { |
| 99 | ChipLogError(Inet, "Failed to copy OpenThread buffer into System Packet buffer"); |
| 100 | return; |
| 101 | } |
Boris Zbarsky | 3956a9d | 2022-05-26 14:38:43 -0400 | [diff] [blame] | 102 | payload->SetDataLength(static_cast<uint16_t>(msgLen)); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 103 | |
Jiacheng Guo | ad63a63 | 2022-07-14 21:20:25 +0800 | [diff] [blame] | 104 | // TODO: add thread-safe reference counting for UDP endpoints |
| 105 | auto * buf = std::move(payload).UnsafeRelease(); |
| 106 | CHIP_ERROR err = |
| 107 | ep->GetSystemLayer().ScheduleLambda([ep, buf] { ep->HandleDataReceived(System::PacketBufferHandle::Adopt(buf)); }); |
Boris Zbarsky | e5922b3 | 2022-04-21 12:02:44 -0400 | [diff] [blame] | 108 | if (err != CHIP_NO_ERROR) |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 109 | { |
Boris Zbarsky | e5922b3 | 2022-04-21 12:02:44 -0400 | [diff] [blame] | 110 | // Make sure we properly clean up buf and ep, since our lambda will not |
| 111 | // run. |
| 112 | payload = System::PacketBufferHandle::Adopt(buf); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 113 | } |
| 114 | } |
| 115 | |
| 116 | CHIP_ERROR UDPEndPointImplOT::IPv6Bind(otUdpSocket & socket, const IPAddress & address, uint16_t port, InterfaceId interface) |
| 117 | { |
| 118 | (void) interface; |
| 119 | otError err = OT_ERROR_NONE; |
| 120 | otSockAddr listenSockAddr; |
| 121 | |
| 122 | memset(&socket, 0, sizeof(socket)); |
| 123 | memset(&listenSockAddr, 0, sizeof(listenSockAddr)); |
| 124 | |
| 125 | listenSockAddr.mPort = port; |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 126 | listenSockAddr.mAddress = address.ToIPv6(); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 127 | |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 128 | LockOpenThread(); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 129 | otUdpOpen(mOTInstance, &socket, handleUdpReceive, this); |
| 130 | otUdpBind(mOTInstance, &socket, &listenSockAddr, OT_NETIF_THREAD); |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 131 | UnlockOpenThread(); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 132 | |
| 133 | return chip::DeviceLayer::Internal::MapOpenThreadError(err); |
| 134 | } |
| 135 | |
| 136 | CHIP_ERROR UDPEndPointImplOT::BindImpl(IPAddressType addressType, const IPAddress & addr, uint16_t port, InterfaceId interface) |
| 137 | { |
| 138 | |
| 139 | if (addressType != IPAddressType::kIPv6) |
| 140 | { |
| 141 | return INET_ERROR_WRONG_ADDRESS_TYPE; |
| 142 | } |
| 143 | |
| 144 | ReturnErrorOnFailure(IPv6Bind(mSocket, addr, port, interface)); |
| 145 | mBoundPort = port; |
| 146 | mBoundIntfId = interface; |
| 147 | |
| 148 | return CHIP_NO_ERROR; |
| 149 | } |
| 150 | |
| 151 | InterfaceId UDPEndPointImplOT::GetBoundInterface() const |
| 152 | { |
| 153 | return mBoundIntfId; |
| 154 | } |
| 155 | |
| 156 | uint16_t UDPEndPointImplOT::GetBoundPort() const |
| 157 | { |
| 158 | return mBoundPort; |
| 159 | } |
| 160 | |
| 161 | CHIP_ERROR UDPEndPointImplOT::ListenImpl() |
| 162 | { |
| 163 | // Nothing to do. Callback was set upon Binding call. |
| 164 | return CHIP_NO_ERROR; |
| 165 | } |
| 166 | |
| 167 | void UDPEndPointImplOT::HandleDataReceived(System::PacketBufferHandle && msg) |
| 168 | { |
| 169 | if ((mState == State::kListening) && (OnMessageReceived != nullptr)) |
| 170 | { |
| 171 | const IPPacketInfo * pktInfo = GetPacketInfo(msg); |
| 172 | |
| 173 | if (pktInfo != nullptr) |
| 174 | { |
| 175 | const IPPacketInfo pktInfoCopy = *pktInfo; // copy the address info so that the app can free the |
| 176 | // PacketBuffer without affecting access to address info. |
| 177 | |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 178 | OnMessageReceived(this, std::move(msg), &pktInfoCopy); |
| 179 | } |
| 180 | else |
| 181 | { |
| 182 | if (OnReceiveError != nullptr) |
| 183 | { |
| 184 | OnReceiveError(this, CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG, nullptr); |
| 185 | } |
| 186 | } |
| 187 | } |
| 188 | } |
| 189 | |
Jean-Francois Penven | fa087ea | 2022-04-22 14:53:57 -0400 | [diff] [blame] | 190 | void UDPEndPointImplOT::SetNativeParams(void * params) |
| 191 | { |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 192 | if (params == nullptr) |
| 193 | { |
| 194 | ChipLogError(Inet, "FATAL!! No native parameters provided!!!!!"); |
| 195 | VerifyOrDie(false); |
| 196 | } |
| 197 | |
| 198 | OpenThreadEndpointInitParam * initParams = static_cast<OpenThreadEndpointInitParam *>(params); |
| 199 | mOTInstance = initParams->openThreadInstancePtr; |
| 200 | globalOtInstance = mOTInstance; |
| 201 | |
| 202 | lockOpenThread = initParams->lockCb; |
| 203 | unlockOpenThread = initParams->unlockCb; |
Jean-Francois Penven | fa087ea | 2022-04-22 14:53:57 -0400 | [diff] [blame] | 204 | } |
| 205 | |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 206 | CHIP_ERROR UDPEndPointImplOT::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback) |
| 207 | { |
| 208 | (void) aIPVersion; |
| 209 | (void) aLoopback; |
| 210 | // TODO |
| 211 | return CHIP_ERROR_NOT_IMPLEMENTED; |
| 212 | } |
| 213 | |
| 214 | CHIP_ERROR UDPEndPointImplOT::BindInterfaceImpl(IPAddressType addressType, InterfaceId interfaceId) |
| 215 | { |
| 216 | (void) addressType; |
| 217 | (void) interfaceId; |
| 218 | return CHIP_NO_ERROR; |
| 219 | } |
| 220 | |
| 221 | CHIP_ERROR UDPEndPointImplOT::SendMsgImpl(const IPPacketInfo * aPktInfo, System::PacketBufferHandle && msg) |
| 222 | { |
| 223 | otError error = OT_ERROR_NONE; |
| 224 | otMessage * message; |
| 225 | otMessageInfo messageInfo; |
| 226 | |
| 227 | // For now the entire message must fit within a single buffer. |
| 228 | VerifyOrReturnError(!msg->HasChainedBuffer(), CHIP_ERROR_MESSAGE_TOO_LONG); |
| 229 | |
| 230 | memset(&messageInfo, 0, sizeof(messageInfo)); |
| 231 | |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 232 | messageInfo.mSockAddr = aPktInfo->SrcAddress.ToIPv6(); |
| 233 | messageInfo.mPeerAddr = aPktInfo->DestAddress.ToIPv6(); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 234 | messageInfo.mPeerPort = aPktInfo->DestPort; |
| 235 | |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 236 | LockOpenThread(); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 237 | message = otUdpNewMessage(mOTInstance, NULL); |
| 238 | VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); |
| 239 | |
| 240 | error = otMessageAppend(message, msg->Start(), msg->DataLength()); |
| 241 | |
| 242 | if (error == OT_ERROR_NONE) |
| 243 | { |
| 244 | error = otUdpSend(mOTInstance, &mSocket, message, &messageInfo); |
| 245 | } |
| 246 | |
| 247 | exit: |
| 248 | if (error != OT_ERROR_NONE && message != NULL) |
| 249 | { |
| 250 | otMessageFree(message); |
| 251 | } |
| 252 | |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 253 | UnlockOpenThread(); |
| 254 | |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 255 | return chip::DeviceLayer::Internal::MapOpenThreadError(error); |
| 256 | } |
| 257 | |
| 258 | void UDPEndPointImplOT::CloseImpl() |
| 259 | { |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 260 | LockOpenThread(); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 261 | if (otUdpIsOpen(mOTInstance, &mSocket)) |
| 262 | { |
| 263 | otUdpClose(mOTInstance, &mSocket); |
Zang MingJie | f5eec6e | 2022-07-14 21:20:54 +0800 | [diff] [blame] | 264 | |
| 265 | // In case that there is a UDPEndPointImplOT::handleUdpReceive event |
| 266 | // pending in the event queue (SystemLayer::ScheduleLambda), we |
| 267 | // schedule a release call to the end of the queue, to ensure that the |
| 268 | // queued pointer to UDPEndPointImplOT is not dangling. |
| 269 | Retain(); |
| 270 | CHIP_ERROR err = GetSystemLayer().ScheduleLambda([this] { Release(); }); |
| 271 | if (err != CHIP_NO_ERROR) |
| 272 | { |
| 273 | ChipLogError(Inet, "Unable scedule lambda: %" CHIP_ERROR_FORMAT, err.Format()); |
| 274 | // There is nothing we can do here, accept the chance of racing |
| 275 | Release(); |
| 276 | } |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 277 | } |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 278 | UnlockOpenThread(); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 279 | } |
| 280 | |
| 281 | void UDPEndPointImplOT::Free() |
| 282 | { |
| 283 | Close(); |
| 284 | Release(); |
| 285 | } |
| 286 | |
| 287 | CHIP_ERROR UDPEndPointImplOT::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) |
| 288 | { |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 289 | const otIp6Address otAddress = aAddress.ToIPv6(); |
| 290 | otError err; |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 291 | |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 292 | LockOpenThread(); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 293 | if (join) |
| 294 | { |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 295 | err = otIp6SubscribeMulticastAddress(mOTInstance, &otAddress); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 296 | } |
| 297 | else |
| 298 | { |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 299 | err = otIp6UnsubscribeMulticastAddress(mOTInstance, &otAddress); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 300 | } |
Jean-Francois Penven | 9405c20 | 2022-05-03 15:37:44 -0400 | [diff] [blame] | 301 | |
| 302 | UnlockOpenThread(); |
| 303 | |
| 304 | return chip::DeviceLayer::Internal::MapOpenThreadError(err); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 305 | } |
| 306 | |
| 307 | IPPacketInfo * UDPEndPointImplOT::GetPacketInfo(const System::PacketBufferHandle & aBuffer) |
| 308 | { |
Kevin Schoedel | 7b3fb84 | 2022-06-07 20:30:00 -0400 | [diff] [blame] | 309 | if (!aBuffer->EnsureReservedSize(kPacketInfoReservedSize)) |
| 310 | { |
| 311 | return nullptr; |
| 312 | } |
| 313 | |
| 314 | uintptr_t lStart = (uintptr_t) aBuffer->Start(); |
| 315 | uintptr_t lPacketInfoStart = lStart - sizeof(IPPacketInfo); |
| 316 | |
| 317 | // Align to a 4-byte boundary |
| 318 | return reinterpret_cast<IPPacketInfo *>(lPacketInfoStart & ~kPacketInfoAlignmentBytes); |
Jean-Francois Penven | 1cbec52 | 2022-01-11 11:54:40 -0500 | [diff] [blame] | 319 | } |
| 320 | |
| 321 | } // namespace Inet |
| 322 | } // namespace chip |