blob: 6ba9df994c4f5fa84b879b3484989f210a4e0717 [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
*
* 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 "Server.h"
#include "FreeRTOS.h"
#include "nrf_log.h"
#include "task.h"
#include <string.h>
#include <sys/param.h>
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>
#include <inet/IPAddress.h>
#include <inet/InetError.h>
#include <inet/InetLayer.h>
#include <platform/CHIPDeviceLayer.h>
#include <support/CodeUtils.h>
#include <support/ErrorStr.h>
#include <system/SystemPacketBuffer.h>
#include <transport/SecureSessionMgr.h>
#include <transport/UDP.h>
#if CHIP_ENABLE_OPENTHREAD
#include <openthread/message.h>
#include <openthread/udp.h>
#include <platform/OpenThread/OpenThreadUtils.h>
#include <platform/ThreadStackManager.h>
#include <platform/internal/DeviceNetworkInfo.h>
#include <platform/nRF5/ThreadStackManagerImpl.h>
#endif
#include "attribute-storage.h"
#include "gen/znet-bookkeeping.h"
#include "util.h"
#include <app/chip-zcl-zpro-codec.h>
using namespace ::chip;
using namespace ::chip::Inet;
using namespace ::chip::Transport;
using namespace ::chip::DeviceLayer;
// Transport Callbacks
namespace {
#ifndef EXAMPLE_SERVER_NODEID
// "nRF5"
#define EXAMPLE_SERVER_NODEID 0x3546526e
#endif // EXAMPLE_SERVER_NODEID
char deviceName[128];
constexpr uint16_t kUDPBroadcastPort = 23367;
const uint8_t local_private_key[] = { 0xc6, 0x1a, 0x2f, 0x89, 0x36, 0x67, 0x2b, 0x26, 0x12, 0x47, 0x4f,
0x11, 0x0e, 0x34, 0x15, 0x81, 0x81, 0x12, 0xfc, 0x36, 0xeb, 0x65,
0x61, 0x07, 0xaa, 0x63, 0xe8, 0xc5, 0x22, 0xac, 0x52, 0xa1 };
const uint8_t remote_public_key[] = { 0x04, 0x30, 0x77, 0x2c, 0xe7, 0xd4, 0x0a, 0xf2, 0xf3, 0x19, 0xbd, 0xfb, 0x1f,
0xcc, 0x88, 0xd9, 0x83, 0x25, 0x89, 0xf2, 0x09, 0xf3, 0xab, 0xe4, 0x33, 0xb6,
0x7a, 0xff, 0x73, 0x3b, 0x01, 0x35, 0x34, 0x92, 0x73, 0x14, 0x59, 0x0b, 0xbd,
0x44, 0x72, 0x1b, 0xcd, 0xb9, 0x02, 0x53, 0xd9, 0xaf, 0xcc, 0x1a, 0xcd, 0xae,
0xe8, 0x87, 0x2e, 0x52, 0x3b, 0x98, 0xf0, 0xa1, 0x88, 0x4a, 0xe3, 0x03, 0x75 };
class ServerCallback : public SecureSessionMgrCallback
{
public:
virtual void OnMessageReceived(const MessageHeader & header, Transport::PeerConnectionState * state,
System::PacketBuffer * buffer, SecureSessionMgrBase * mgr)
{
const size_t data_len = buffer->DataLength();
char src_addr[PeerAddress::kMaxToStringSize];
// as soon as a client connects, assume it is connected
VerifyOrExit(buffer != NULL, NRF_LOG_INFO("Received data but couldn't process it..."));
VerifyOrExit(header.GetSourceNodeId().HasValue(), NRF_LOG_INFO("Unknown source for received message"));
VerifyOrExit(state->GetPeerNodeId() != kUndefinedNodeId, NRF_LOG_INFO("Unknown source for received message"));
state->GetPeerAddress().ToString(src_addr, sizeof(src_addr));
NRF_LOG_INFO("Packet received from %s: %zu bytes", src_addr, static_cast<size_t>(data_len));
HandleDataModelMessage(header, buffer, mgr);
buffer = NULL;
exit:
// SendTo calls Free on the buffer without an AddRef, if SendTo was not called, free the buffer.
if (buffer != NULL)
{
System::PacketBuffer::Free(buffer);
}
}
virtual void OnNewConnection(Transport::PeerConnectionState * state, SecureSessionMgrBase * mgr)
{
CHIP_ERROR err;
NRF_LOG_INFO("Received a new connection.");
err = state->GetSecureSession().TemporaryManualKeyExchange(remote_public_key, sizeof(remote_public_key), local_private_key,
sizeof(local_private_key));
VerifyOrExit(err == CHIP_NO_ERROR, NRF_LOG_INFO("Failed to setup encryption"));
exit:
return;
}
private:
/**
* Handle a message that should be processed via our data model processing
* codepath.
*
* @param [in] buffer The buffer holding the message. This function guarantees
* that it will free the buffer before returning.
*/
void HandleDataModelMessage(const MessageHeader & header, System::PacketBuffer * buffer, SecureSessionMgrBase * mgr)
{
EmberApsFrame frame;
bool ok = extractApsFrame(buffer->Start(), buffer->DataLength(), &frame) > 0;
if (ok)
{
NRF_LOG_INFO("APS frame processing success!");
}
else
{
NRF_LOG_INFO("APS frame processing failure!");
System::PacketBuffer::Free(buffer);
return;
}
ChipResponseDestination responseDest(header.GetSourceNodeId().Value(), mgr);
uint8_t * message;
uint16_t messageLen = extractMessage(buffer->Start(), buffer->DataLength(), &message);
ok = emberAfProcessMessage(&frame,
0, // type
message, messageLen,
&responseDest, // source identifier
NULL);
System::PacketBuffer::Free(buffer);
if (ok)
{
NRF_LOG_INFO("Data model processing success!");
}
else
{
NRF_LOG_INFO("Data model processing failure!");
}
}
};
static ServerCallback gCallbacks;
} // namespace
void SetDeviceName(const char * newDeviceName)
{
strncpy(deviceName, newDeviceName, sizeof(deviceName) - 1);
}
void PublishService()
{
chip::Inet::IPAddress addr;
if (!ConnectivityMgrImpl().IsThreadAttached())
{
return;
}
ThreadStackMgrImpl().LockThreadStack();
otError error = OT_ERROR_NONE;
otMessageInfo messageInfo;
otUdpSocket mSocket;
otMessage * message = nullptr;
memset(&mSocket, 0, sizeof(mSocket));
memset(&messageInfo, 0, sizeof(messageInfo));
// Use mesh local EID by default, if we have GUA, use that IP address.
memcpy(&messageInfo.mSockAddr, otThreadGetMeshLocalEid(ThreadStackMgrImpl().OTInstance()), sizeof(messageInfo.mSockAddr));
// Select a address to send
const otNetifAddress * otAddrs = otIp6GetUnicastAddresses(ThreadStackMgrImpl().OTInstance());
for (const otNetifAddress * otAddr = otAddrs; otAddr != NULL; otAddr = otAddr->mNext)
{
addr = chip::DeviceLayer::Internal::ToIPAddress(otAddr->mAddress);
if (otAddr->mValid && addr.IsIPv6GlobalUnicast())
{
memcpy(&messageInfo.mSockAddr, &(otAddr->mAddress), sizeof(otAddr->mAddress));
break;
}
}
message = otUdpNewMessage(ThreadStackMgrImpl().OTInstance(), nullptr);
otIp6AddressFromString("ff03::1", &messageInfo.mPeerAddr);
messageInfo.mPeerPort = kUDPBroadcastPort;
otMessageAppend(message, deviceName, static_cast<uint16_t>(strlen(deviceName)));
error = otUdpSend(ThreadStackMgrImpl().OTInstance(), &mSocket, message, &messageInfo);
if (error != OT_ERROR_NONE && message != nullptr)
{
otMessageFree(message);
NRF_LOG_INFO("Failed to otUdpSend: %d", error);
}
ThreadStackMgrImpl().UnlockThreadStack();
}
void InitDataModelHandler()
{
emberAfEndpointConfigure();
emAfInit();
}
// The echo server assumes the platform's networking has been setup already
void StartServer(DemoSessionManager * sessions)
{
CHIP_ERROR err = CHIP_NO_ERROR;
err = sessions->Init(EXAMPLE_SERVER_NODEID, &DeviceLayer::SystemLayer,
UdpListenParameters(&DeviceLayer::InetLayer).SetAddressType(kIPAddressType_IPv6));
SuccessOrExit(err);
sessions->SetDelegate(&gCallbacks);
exit:
if (err != CHIP_NO_ERROR)
{
NRF_LOG_ERROR("ERROR setting up transport: %s", ErrorStr(err));
}
else
{
NRF_LOG_INFO("Lock Server Listening...");
}
}