Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restyle [Group] Implement UDPEndPoint for OpenThread (to enable multicast) #13308

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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_ot_udp = true
7 changes: 5 additions & 2 deletions src/app/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,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_OT_UDP
.SetOtInstance(chip::DeviceLayer::ThreadStackMgrImpl().OTInstance())
#endif // CHIP_SYSTEM_CONFIG_USE_OT_UDP

#if INET_CONFIG_ENABLE_IPV4
,
Expand All @@ -149,10 +152,10 @@ CHIP_ERROR Server::Init(AppDelegate * delegate, uint16_t secureServicePort, uint
// TODO : Fix this once GroupDataProvider is implemented #Issue 11075
// for (iterate through all GroupDataProvider multicast Address)
// {
#ifdef CHIP_ENABLE_GROUP_MESSAGING_TESTS
//#ifdef CHIP_ENABLE_GROUP_MESSAGING_TESTS
err = mTransports.MulticastGroupJoinLeave(Transport::PeerAddress::Multicast(1, 1234), true);
SuccessOrExit(err);
#endif
//#endif
//}

err = mSessions.Init(&DeviceLayer::SystemLayer(), &mTransports, &mMessageCounterManager);
Expand Down
39 changes: 33 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_ot_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,13 @@ 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_ot_udp) {
defines +=
[ "INET_UDP_END_POINT_IMPL_CONFIG_FILE=<inet/UDPEndPointImplOT.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 +112,16 @@ static_library("inet") {
public_deps += [ "${chip_root}/src/lwip" ]
}

if (chip_system_config_use_ot_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 +136,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_ot_udp) {
sources += [
"UDPEndPointImplOT.cpp",
"UDPEndPointImplOT.h",
]
} else {
sources += [
"UDPEndPointImpl${chip_system_config_inet}.cpp",
"UDPEndPointImpl${chip_system_config_inet}.h",
]
}
}

if (chip_with_nlfaultinjection) {
Expand Down
4 changes: 4 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,8 @@ class DLL_EXPORT UDPEndPoint : public EndPointBasis<UDPEndPoint>
*/
virtual void Free() = 0;

virtual inline void SetOtInstance(otInstance * instance) { (void) instance; }

protected:
UDPEndPoint(EndPointManager<UDPEndPoint> & endPointManager) :
EndPointBasis(endPointManager), mState(State::kReady), OnMessageReceived(nullptr), OnReceiveError(nullptr)
Expand Down
273 changes: 273 additions & 0 deletions src/inet/UDPEndPointImplOT.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
/*
*
* 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.
*/

/**
* This file implements Inet::UDPEndPoint using OpenThread.
*/

#include <inet/UDPEndPointImplOT.h>

#include <lib/support/CodeUtils.h>
#include <lib/support/SafeInt.h>
#include <lib/support/logging/CHIPLogging.h>

#include <platform/OpenThread/OpenThreadUtils.h>
//#include <include/platform/ThreadStackManager.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)
{
ReturnErrorOnFailure(IPv6Bind(mSocket, addr, port, interface));
}
else
{
return INET_ERROR_WRONG_ADDRESS_TYPE;
}

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_NO_ERROR;
}

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