-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Group] Implement UDPEndPoint for OpenThread (to enable multicast) (#…
…13127) * Add OT UDPEnPointImpl to enable multicast listening
- Loading branch information
1 parent
b7afede
commit 1cbec52
Showing
13 changed files
with
473 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,265 @@ | ||
/* | ||
* | ||
* Copyright (c) 2020-2021 Project CHIP Authors | ||
* Copyright (c) 2018 Google LLC. | ||
* Copyright (c) 2013-2018 Nest Labs, Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#include <inet/UDPEndPointImpl_OpenThread.h> | ||
|
||
#include <lib/support/CodeUtils.h> | ||
#include <lib/support/SafeInt.h> | ||
#include <lib/support/logging/CHIPLogging.h> | ||
|
||
#include <platform/OpenThread/OpenThreadUtils.h> | ||
|
||
#include <system/SystemPacketBuffer.h> | ||
|
||
namespace chip { | ||
namespace Inet { | ||
|
||
void UDPEndPointImplOT::handleUdpReceive(void * aContext, otMessage * aMessage, const otMessageInfo * aMessageInfo) | ||
{ | ||
UDPEndPointImplOT * ep = static_cast<UDPEndPointImplOT *>(aContext); | ||
IPPacketInfo pktInfo; | ||
uint16_t msgLen = otMessageGetLength(aMessage); | ||
System::PacketBufferHandle payload; | ||
#if CHIP_DETAIL_LOGGING | ||
static uint16_t msgReceivedCount = 0; | ||
char sourceStr[Inet::IPAddress::kMaxStringLength]; | ||
char destStr[Inet::IPAddress::kMaxStringLength]; | ||
#endif | ||
|
||
if (msgLen > System::PacketBuffer::kMaxSizeWithoutReserve) | ||
{ | ||
ChipLogError(Inet, "UDP message too long, discarding. Size received %d", msgLen); | ||
return; | ||
} | ||
|
||
pktInfo.SrcAddress = chip::DeviceLayer::Internal::ToIPAddress(aMessageInfo->mPeerAddr); | ||
pktInfo.DestAddress = chip::DeviceLayer::Internal::ToIPAddress(aMessageInfo->mSockAddr); | ||
pktInfo.SrcPort = aMessageInfo->mPeerPort; | ||
pktInfo.DestPort = aMessageInfo->mSockPort; | ||
|
||
payload = System::PacketBufferHandle::New(msgLen, 0); | ||
|
||
if (payload.IsNull()) | ||
{ | ||
ChipLogError(Inet, "Failed to allocate a System buffer of size %d for UDP Message reception.", msgLen); | ||
return; | ||
} | ||
|
||
#if CHIP_DETAIL_LOGGING | ||
pktInfo.SrcAddress.ToString(sourceStr, Inet::IPAddress::kMaxStringLength); | ||
pktInfo.DestAddress.ToString(destStr, Inet::IPAddress::kMaxStringLength); | ||
|
||
ChipLogDetail(Inet, | ||
"UDP Message Received packet nb : %d with the following data :\r\nSrcAddr : %s\r\nSrc Port : %d\r\n\r\nDestAddr " | ||
": %s\r\nDest Port %d\r\nPayload Length %d", | ||
++msgReceivedCount, sourceStr, pktInfo.SrcPort, destStr, pktInfo.DestPort, msgLen); | ||
|
||
#endif | ||
|
||
memcpy(payload->Start(), &pktInfo, sizeof(IPPacketInfo)); | ||
|
||
if (otMessageRead(aMessage, 0, payload->Start() + sizeof(IPPacketInfo), msgLen) != msgLen) | ||
{ | ||
ChipLogError(Inet, "Failed to copy OpenThread buffer into System Packet buffer"); | ||
return; | ||
} | ||
payload->SetDataLength(msgLen + sizeof(IPPacketInfo)); | ||
|
||
ep->Retain(); | ||
CHIP_ERROR err = ep->GetSystemLayer().ScheduleLambda([ep, p = System::LwIPPacketBufferView::UnsafeGetLwIPpbuf(payload)] { | ||
ep->HandleDataReceived(System::PacketBufferHandle::Adopt(p)); | ||
ep->Release(); | ||
}); | ||
if (err == CHIP_NO_ERROR) | ||
{ | ||
// If ScheduleLambda() succeeded, it has ownership of the buffer, so we need to release it (without freeing it). | ||
static_cast<void>(std::move(payload).UnsafeRelease()); | ||
} | ||
else | ||
{ | ||
ep->Release(); | ||
} | ||
} | ||
|
||
CHIP_ERROR UDPEndPointImplOT::IPv6Bind(otUdpSocket & socket, const IPAddress & address, uint16_t port, InterfaceId interface) | ||
{ | ||
(void) interface; | ||
otError err = OT_ERROR_NONE; | ||
otSockAddr listenSockAddr; | ||
|
||
memset(&socket, 0, sizeof(socket)); | ||
memset(&listenSockAddr, 0, sizeof(listenSockAddr)); | ||
|
||
listenSockAddr.mPort = port; | ||
listenSockAddr.mAddress = chip::DeviceLayer::Internal::ToOpenThreadIP6Address(address); | ||
|
||
otUdpOpen(mOTInstance, &socket, handleUdpReceive, this); | ||
otUdpBind(mOTInstance, &socket, &listenSockAddr, OT_NETIF_THREAD); | ||
|
||
return chip::DeviceLayer::Internal::MapOpenThreadError(err); | ||
} | ||
|
||
CHIP_ERROR UDPEndPointImplOT::BindImpl(IPAddressType addressType, const IPAddress & addr, uint16_t port, InterfaceId interface) | ||
{ | ||
|
||
if (addressType != IPAddressType::kIPv6) | ||
{ | ||
return INET_ERROR_WRONG_ADDRESS_TYPE; | ||
} | ||
|
||
ReturnErrorOnFailure(IPv6Bind(mSocket, addr, port, interface)); | ||
mBoundPort = port; | ||
mBoundIntfId = interface; | ||
|
||
return CHIP_NO_ERROR; | ||
} | ||
|
||
InterfaceId UDPEndPointImplOT::GetBoundInterface() const | ||
{ | ||
return mBoundIntfId; | ||
} | ||
|
||
uint16_t UDPEndPointImplOT::GetBoundPort() const | ||
{ | ||
return mBoundPort; | ||
} | ||
|
||
CHIP_ERROR UDPEndPointImplOT::ListenImpl() | ||
{ | ||
// Nothing to do. Callback was set upon Binding call. | ||
return CHIP_NO_ERROR; | ||
} | ||
|
||
void UDPEndPointImplOT::HandleDataReceived(System::PacketBufferHandle && msg) | ||
{ | ||
if ((mState == State::kListening) && (OnMessageReceived != nullptr)) | ||
{ | ||
const IPPacketInfo * pktInfo = GetPacketInfo(msg); | ||
|
||
if (pktInfo != nullptr) | ||
{ | ||
const IPPacketInfo pktInfoCopy = *pktInfo; // copy the address info so that the app can free the | ||
// PacketBuffer without affecting access to address info. | ||
|
||
msg->ConsumeHead(sizeof(IPPacketInfo)); | ||
OnMessageReceived(this, std::move(msg), &pktInfoCopy); | ||
} | ||
else | ||
{ | ||
if (OnReceiveError != nullptr) | ||
{ | ||
OnReceiveError(this, CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG, nullptr); | ||
} | ||
} | ||
} | ||
} | ||
|
||
CHIP_ERROR UDPEndPointImplOT::SetMulticastLoopback(IPVersion aIPVersion, bool aLoopback) | ||
{ | ||
(void) aIPVersion; | ||
(void) aLoopback; | ||
// TODO | ||
return CHIP_ERROR_NOT_IMPLEMENTED; | ||
} | ||
|
||
CHIP_ERROR UDPEndPointImplOT::BindInterfaceImpl(IPAddressType addressType, InterfaceId interfaceId) | ||
{ | ||
(void) addressType; | ||
(void) interfaceId; | ||
return CHIP_NO_ERROR; | ||
} | ||
|
||
CHIP_ERROR UDPEndPointImplOT::SendMsgImpl(const IPPacketInfo * aPktInfo, System::PacketBufferHandle && msg) | ||
{ | ||
otError error = OT_ERROR_NONE; | ||
otMessage * message; | ||
otMessageInfo messageInfo; | ||
|
||
// For now the entire message must fit within a single buffer. | ||
VerifyOrReturnError(!msg->HasChainedBuffer(), CHIP_ERROR_MESSAGE_TOO_LONG); | ||
|
||
memset(&messageInfo, 0, sizeof(messageInfo)); | ||
|
||
messageInfo.mSockAddr = chip::DeviceLayer::Internal::ToOpenThreadIP6Address(aPktInfo->SrcAddress); | ||
messageInfo.mPeerAddr = chip::DeviceLayer::Internal::ToOpenThreadIP6Address(aPktInfo->DestAddress); | ||
messageInfo.mPeerPort = aPktInfo->DestPort; | ||
|
||
message = otUdpNewMessage(mOTInstance, NULL); | ||
VerifyOrExit(message != NULL, error = OT_ERROR_NO_BUFS); | ||
|
||
error = otMessageAppend(message, msg->Start(), msg->DataLength()); | ||
|
||
if (error == OT_ERROR_NONE) | ||
{ | ||
error = otUdpSend(mOTInstance, &mSocket, message, &messageInfo); | ||
} | ||
|
||
exit: | ||
if (error != OT_ERROR_NONE && message != NULL) | ||
{ | ||
otMessageFree(message); | ||
} | ||
|
||
return chip::DeviceLayer::Internal::MapOpenThreadError(error); | ||
} | ||
|
||
void UDPEndPointImplOT::CloseImpl() | ||
{ | ||
if (otUdpIsOpen(mOTInstance, &mSocket)) | ||
{ | ||
otUdpClose(mOTInstance, &mSocket); | ||
} | ||
} | ||
|
||
void UDPEndPointImplOT::Free() | ||
{ | ||
Close(); | ||
Release(); | ||
} | ||
|
||
CHIP_ERROR UDPEndPointImplOT::IPv6JoinLeaveMulticastGroupImpl(InterfaceId aInterfaceId, const IPAddress & aAddress, bool join) | ||
{ | ||
const otIp6Address otAddress = chip::DeviceLayer::Internal::ToOpenThreadIP6Address(aAddress); | ||
|
||
if (join) | ||
{ | ||
return chip::DeviceLayer::Internal::MapOpenThreadError(otIp6SubscribeMulticastAddress(mOTInstance, &otAddress)); | ||
} | ||
else | ||
{ | ||
return chip::DeviceLayer::Internal::MapOpenThreadError(otIp6UnsubscribeMulticastAddress(mOTInstance, &otAddress)); | ||
} | ||
} | ||
|
||
IPPacketInfo * UDPEndPointImplOT::GetPacketInfo(const System::PacketBufferHandle & aBuffer) | ||
{ | ||
if (!aBuffer->EnsureReservedSize(sizeof(IPPacketInfo))) | ||
{ | ||
return nullptr; | ||
} | ||
|
||
uintptr_t lStart = (uintptr_t) aBuffer->Start(); | ||
uintptr_t lPacketInfoStart = lStart - sizeof(IPPacketInfo); | ||
|
||
// Align to a 4-byte boundary | ||
return reinterpret_cast<IPPacketInfo *>(lPacketInfoStart & ~(sizeof(uint32_t) - 1)); | ||
} | ||
|
||
} // namespace Inet | ||
} // namespace chip |
Oops, something went wrong.