Skip to content

Commit

Permalink
[Group] Implement UDPEndPoint for OpenThread (to enable multicast) (#…
Browse files Browse the repository at this point in the history
…13127)

* Add OT UDPEnPointImpl to enable multicast listening
  • Loading branch information
jepenven-silabs authored Jan 11, 2022
1 parent b7afede commit 1cbec52
Show file tree
Hide file tree
Showing 13 changed files with 473 additions and 11 deletions.
1 change: 1 addition & 0 deletions examples/lighting-app/efr32/args.gni
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ pw_log_BACKEND = "${chip_root}/src/lib/support/pw_log_chip"
pw_assert_BACKEND = "$dir_pw_assert_log"
chip_enable_openthread = true
chip_openthread_ftd = true
chip_system_config_use_open_thread_udp = true
3 changes: 3 additions & 0 deletions examples/platform/efr32/project_include/OpenThreadConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@
#define OPENTHREAD_CONFIG_DHCP6_SERVER_ENABLE 0
#define OPENTHREAD_CONFIG_TCP_ENABLE 0

// Support udp multicast by enabling Multicast Listener Registration (MLR)
#define OPENTHREAD_CONFIG_MLR_ENABLE 1

// Use the SiLabs-supplied default platform configuration for remainder
// of OpenThread config options.
//
Expand Down
11 changes: 7 additions & 4 deletions src/app/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ CHIP_ERROR Server::Init(AppDelegate * delegate, uint16_t secureServicePort, uint
err = mTransports.Init(UdpListenParameters(DeviceLayer::UDPEndPointManager())
.SetAddressType(IPAddressType::kIPv6)
.SetListenPort(mSecuredServicePort)
#if CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_UDP
.SetNativeParams(chip::DeviceLayer::ThreadStackMgrImpl().OTInstance())
#endif // CHIP_SYSTEM_CONFIG_USE_OPEN_THREAD_UDP

#if INET_CONFIG_ENABLE_IPV4
,
Expand All @@ -151,10 +154,10 @@ CHIP_ERROR Server::Init(AppDelegate * delegate, uint16_t secureServicePort, uint
#endif
SuccessOrExit(err);

// Enable Group Listening
// TODO : Fix this once GroupDataProvider is implemented #Issue 11075
// for (iterate through all GroupDataProvider multicast Address)
// {
// Enable Group Listening
// TODO : Fix this once GroupDataProvider is implemented #Issue 11075
// for (iterate through all GroupDataProvider multicast Address)
// {
#ifdef CHIP_ENABLE_GROUP_MESSAGING_TESTS
err = mTransports.MulticastGroupJoinLeave(Transport::PeerAddress::Multicast(1, 1234), true);
SuccessOrExit(err);
Expand Down
40 changes: 34 additions & 6 deletions src/inet/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import("${chip_root}/src/lwip/lwip.gni")
import("${chip_root}/src/platform/device.gni")
import("inet.gni")

if (chip_system_config_use_open_thread_udp) {
import("//build_overrides/openthread.gni")
}

declare_args() {
# Extra header to include in SystemConfig.h for project.
chip_inet_project_config_include = ""
Expand All @@ -50,10 +54,14 @@ buildconfig_header("inet_buildconfig") {
[ "INET_PLATFORM_CONFIG_INCLUDE=${chip_inet_platform_config_include}" ]
}

defines += [
"INET_TCP_END_POINT_IMPL_CONFIG_FILE=<inet/TCPEndPointImpl${chip_system_config_inet}.h>",
"INET_UDP_END_POINT_IMPL_CONFIG_FILE=<inet/UDPEndPointImpl${chip_system_config_inet}.h>",
]
defines += [ "INET_TCP_END_POINT_IMPL_CONFIG_FILE=<inet/TCPEndPointImpl${chip_system_config_inet}.h>" ]
if (chip_system_config_use_open_thread_udp) {
defines += [
"INET_UDP_END_POINT_IMPL_CONFIG_FILE=<inet/UDPEndPointImpl_OpenThread.h>",
]
} else {
defines += [ "INET_UDP_END_POINT_IMPL_CONFIG_FILE=<inet/UDPEndPointImpl${chip_system_config_inet}.h>" ]
}
}

source_set("inet_config_header") {
Expand Down Expand Up @@ -105,6 +113,16 @@ static_library("inet") {
public_deps += [ "${chip_root}/src/lwip" ]
}

if (chip_system_config_use_open_thread_udp) {
if (chip_openthread_ftd) {
public_deps +=
[ "${chip_root}/third_party/openthread/repo:libopenthread-ftd" ]
} else {
public_deps +=
[ "${chip_root}/third_party/openthread/repo:libopenthread-mtd" ]
}
}

if (chip_inet_config_enable_tcp_endpoint) {
sources += [
"TCPEndPoint.cpp",
Expand All @@ -119,10 +137,20 @@ static_library("inet") {
sources += [
"UDPEndPoint.cpp",
"UDPEndPoint.h",
"UDPEndPointImpl${chip_system_config_inet}.cpp",
"UDPEndPointImpl${chip_system_config_inet}.h",
"UDPEndPointImpl.h",
]

if (chip_system_config_use_open_thread_udp) {
sources += [
"UDPEndPointImpl_OpenThread.cpp",
"UDPEndPointImpl_OpenThread.h",
]
} else {
sources += [
"UDPEndPointImpl${chip_system_config_inet}.cpp",
"UDPEndPointImpl${chip_system_config_inet}.h",
]
}
}

if (chip_with_nlfaultinjection) {
Expand Down
9 changes: 9 additions & 0 deletions src/inet/UDPEndPoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
#include <inet/InetLayer.h>
#include <system/SystemPacketBuffer.h>

struct otInstance;

namespace chip {
namespace Inet {

Expand Down Expand Up @@ -245,6 +247,13 @@ class DLL_EXPORT UDPEndPoint : public EndPointBasis<UDPEndPoint>
*/
virtual void Free() = 0;

/**
* Set Network Native Parameters (optional)
*
* Some networking stack requires additionnal parameters
*/
virtual inline void SetNativeParams(void * params) { (void) params; }

protected:
UDPEndPoint(EndPointManager<UDPEndPoint> & endPointManager) :
EndPointBasis(endPointManager), mState(State::kReady), OnMessageReceived(nullptr), OnReceiveError(nullptr)
Expand Down
265 changes: 265 additions & 0 deletions src/inet/UDPEndPointImpl_OpenThread.cpp
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
Loading

0 comments on commit 1cbec52

Please sign in to comment.