mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 23:57:47 +00:00
[trel] implementing Thread Radio Encapsulation Link (TREL) (#4440)
This commit implements TREL protocol to encapsulate and exchange IEEE 802.15.4 frames over a packet switched network (e.g., a wireless LAN). This commit also provides a TREL IPv6/UDP interface implementation (using link-local IPv6 unicast/multicast addresses to communicate over a subnet). It defines a platform abstraction (`otPlatTrelUdp6*`) for TREL over IPv6/UDP. This commit also provides an implementation of the TREL platform under `examples/posix` focusing on simulating the behavior of the link.
This commit is contained in:
committed by
Jonathan Hui
parent
ffb3fdf9bd
commit
2d36853fe6
+3
-1
@@ -251,7 +251,9 @@ LOCAL_SRC_FILES := \
|
||||
src/core/radio/radio.cpp \
|
||||
src/core/radio/radio_callbacks.cpp \
|
||||
src/core/radio/radio_platform.cpp \
|
||||
src/core/radio/trel.cpp \
|
||||
src/core/radio/trel_interface.cpp \
|
||||
src/core/radio/trel_link.cpp \
|
||||
src/core/radio/trel_packet.cpp \
|
||||
src/core/thread/address_resolver.cpp \
|
||||
src/core/thread/announce_begin_server.cpp \
|
||||
src/core/thread/announce_sender.cpp \
|
||||
|
||||
@@ -69,6 +69,7 @@ add_library(openthread-simulation
|
||||
radio.c
|
||||
spi-stubs.c
|
||||
system.c
|
||||
trel.c
|
||||
uart.c
|
||||
virtual_time/alarm-sim.c
|
||||
virtual_time/platform-sim.c
|
||||
|
||||
@@ -52,6 +52,7 @@ PLATFORM_SOURCES = \
|
||||
radio.c \
|
||||
spi-stubs.c \
|
||||
system.c \
|
||||
trel.c \
|
||||
uart.c \
|
||||
virtual_time/alarm-sim.c \
|
||||
virtual_time/platform-sim.c \
|
||||
|
||||
@@ -231,4 +231,43 @@ void otSimSendUartWriteEvent(const uint8_t *aData, uint16_t aLength);
|
||||
*/
|
||||
bool platformRadioIsTransmitPending(void);
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
/**
|
||||
* This function initializes the TREL service.
|
||||
*
|
||||
* @param[in] aSpeedUpFactor The time speed-up factor.
|
||||
*
|
||||
*/
|
||||
void platformTrelInit(uint32_t aSpeedUpFactor);
|
||||
|
||||
/**
|
||||
* This function shuts down the TREL service.
|
||||
*
|
||||
*/
|
||||
void platformTrelDeinit(void);
|
||||
|
||||
/**
|
||||
* This function updates the file descriptor sets with file descriptors used by the TREL.
|
||||
*
|
||||
* @param[inout] aReadFdSet A pointer to the read file descriptors.
|
||||
* @param[inout] aWriteFdSet A pointer to the write file descriptors.
|
||||
* @param[inout] aTimeout A pointer to the timeout.
|
||||
* @param[inout] aMaxFd A pointer to the max file descriptor.
|
||||
*
|
||||
*/
|
||||
void platformTrelUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd);
|
||||
|
||||
/**
|
||||
* This function performs TREL processing.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aReadFdSet A pointer to the read file descriptors.
|
||||
* @param[in] aWriteFdSet A pointer to the write file descriptors.
|
||||
*
|
||||
*/
|
||||
void platformTrelProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet);
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
#endif // PLATFORM_SIMULATION_H_
|
||||
|
||||
@@ -116,6 +116,9 @@ void otSysInit(int aArgCount, char *aArgVector[])
|
||||
|
||||
platformAlarmInit(speedUpFactor);
|
||||
platformRadioInit();
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
platformTrelInit(speedUpFactor);
|
||||
#endif
|
||||
platformRandomInit();
|
||||
}
|
||||
|
||||
@@ -127,6 +130,9 @@ bool otSysPseudoResetWasRequested(void)
|
||||
void otSysDeinit(void)
|
||||
{
|
||||
platformRadioDeinit();
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
platformTrelDeinit();
|
||||
#endif
|
||||
}
|
||||
|
||||
void otSysProcessDrivers(otInstance *aInstance)
|
||||
@@ -145,6 +151,9 @@ void otSysProcessDrivers(otInstance *aInstance)
|
||||
platformUartUpdateFdSet(&read_fds, &write_fds, &error_fds, &max_fd);
|
||||
platformRadioUpdateFdSet(&read_fds, &write_fds, &max_fd);
|
||||
platformAlarmUpdateTimeout(&timeout);
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
platformTrelUpdateFdSet(&read_fds, &write_fds, &timeout, &max_fd);
|
||||
#endif
|
||||
|
||||
if (otTaskletsArePending(aInstance))
|
||||
{
|
||||
@@ -166,6 +175,9 @@ void otSysProcessDrivers(otInstance *aInstance)
|
||||
}
|
||||
|
||||
platformAlarmProcess(aInstance);
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
platformTrelProcess(aInstance, &read_fds, &write_fds);
|
||||
#endif
|
||||
|
||||
if (gTerminate)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "platform-simulation.h"
|
||||
|
||||
#include <openthread/random_noncrypto.h>
|
||||
#include <openthread/platform/trel-udp6.h>
|
||||
|
||||
#include "utils/code_utils.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
// Change DEBUG_LOG to all extra logging
|
||||
#define DEBUG_LOG 0
|
||||
|
||||
// The IPv4 group for receiving
|
||||
#define TREL_SIM_GROUP "224.0.0.116"
|
||||
#define TREL_SIM_PORT 9200
|
||||
|
||||
#define TREL_MAX_PACKET_SIZE 1800
|
||||
|
||||
#define TREL_MAX_PENDING_TX 5
|
||||
|
||||
typedef struct PendingTx
|
||||
{
|
||||
uint8_t mPacketBuffer[TREL_MAX_PACKET_SIZE];
|
||||
uint16_t mPacketLength;
|
||||
otIp6Address mDestIp6Address;
|
||||
} PendingTx;
|
||||
|
||||
static uint8_t sNumPendingTx = 0;
|
||||
static PendingTx sPendingTx[TREL_MAX_PENDING_TX];
|
||||
|
||||
static int sTxFd = -1;
|
||||
static int sRxFd = -1;
|
||||
static uint16_t sPortOffset = 0;
|
||||
static bool sEnabled = true;
|
||||
|
||||
#if DEBUG_LOG
|
||||
static void dumpBuffer(const uint8_t *aBuffer, uint16_t aLength)
|
||||
{
|
||||
fprintf(stderr, "[ (len:%d) ", aLength);
|
||||
|
||||
while (aLength--)
|
||||
{
|
||||
fprintf(stderr, "%02x ", *aBuffer++);
|
||||
}
|
||||
|
||||
fprintf(stderr, "]");
|
||||
}
|
||||
#endif
|
||||
|
||||
static void initFds(void)
|
||||
{
|
||||
int fd;
|
||||
int one = 1;
|
||||
struct sockaddr_in sockaddr;
|
||||
struct ip_mreqn mreq;
|
||||
|
||||
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||
|
||||
otEXPECT_ACTION((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1, perror("socket(sTxFd)"));
|
||||
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons((uint16_t)(TREL_SIM_PORT + sPortOffset + gNodeId));
|
||||
sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||
|
||||
otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &sockaddr.sin_addr, sizeof(sockaddr.sin_addr)) != -1,
|
||||
perror("setsockopt(sTxFd, IP_MULTICAST_IF)"));
|
||||
|
||||
otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one)) != -1,
|
||||
perror("setsockopt(sTxFd, IP_MULTICAST_LOOP)"));
|
||||
|
||||
otEXPECT_ACTION(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != -1, perror("bind(sTxFd)"));
|
||||
|
||||
// Tx fd is successfully initialized.
|
||||
sTxFd = fd;
|
||||
|
||||
otEXPECT_ACTION((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != -1, perror("socket(sRxFd)"));
|
||||
|
||||
otEXPECT_ACTION(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != -1,
|
||||
perror("setsockopt(sRxFd, SO_REUSEADDR)"));
|
||||
otEXPECT_ACTION(setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) != -1,
|
||||
perror("setsockopt(sRxFd, SO_REUSEPORT)"));
|
||||
|
||||
memset(&mreq, 0, sizeof(mreq));
|
||||
inet_pton(AF_INET, TREL_SIM_GROUP, &mreq.imr_multiaddr);
|
||||
|
||||
// Always use loopback device to send simulation packets.
|
||||
mreq.imr_address.s_addr = inet_addr("127.0.0.1");
|
||||
|
||||
otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &mreq.imr_address, sizeof(mreq.imr_address)) != -1,
|
||||
perror("setsockopt(sRxFd, IP_MULTICAST_IF)"));
|
||||
otEXPECT_ACTION(setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) != -1,
|
||||
perror("setsockopt(sRxFd, IP_ADD_MEMBERSHIP)"));
|
||||
|
||||
sockaddr.sin_family = AF_INET;
|
||||
sockaddr.sin_port = htons((uint16_t)(TREL_SIM_PORT + sPortOffset));
|
||||
sockaddr.sin_addr.s_addr = inet_addr(TREL_SIM_GROUP);
|
||||
|
||||
otEXPECT_ACTION(bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != -1, perror("bind(sRxFd)"));
|
||||
|
||||
// Rx fd is successfully initialized.
|
||||
sRxFd = fd;
|
||||
|
||||
exit:
|
||||
if (sRxFd == -1 || sTxFd == -1)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static void deinitFds(void)
|
||||
{
|
||||
if (sRxFd != -1)
|
||||
{
|
||||
close(sRxFd);
|
||||
}
|
||||
|
||||
if (sTxFd != -1)
|
||||
{
|
||||
close(sTxFd);
|
||||
}
|
||||
}
|
||||
|
||||
void sendPendingTxPackets(void)
|
||||
{
|
||||
ssize_t rval;
|
||||
struct sockaddr_in sockaddr;
|
||||
|
||||
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||
sockaddr.sin_family = AF_INET;
|
||||
inet_pton(AF_INET, TREL_SIM_GROUP, &sockaddr.sin_addr);
|
||||
|
||||
sockaddr.sin_port = htons((uint16_t)(TREL_SIM_PORT + sPortOffset));
|
||||
|
||||
for (uint8_t i = 0; i < sNumPendingTx; i++)
|
||||
{
|
||||
#if DEBUG_LOG
|
||||
fprintf(stderr, "\n[trel-udp] Sending packet (num:%d)", i);
|
||||
dumpBuffer(sPendingTx[i].mPacketBuffer, sPendingTx[i].mPacketLength);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
rval = sendto(sTxFd, sPendingTx[i].mPacketBuffer, sPendingTx[i].mPacketLength, 0, (struct sockaddr *)&sockaddr,
|
||||
sizeof(sockaddr));
|
||||
|
||||
if (rval < 0)
|
||||
{
|
||||
perror("sendto(sTxFd)");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
sNumPendingTx = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// otPlatTrel
|
||||
|
||||
void otPlatTrelUdp6Init(otInstance *aInstance, const otIp6Address *aUnicastAddress, uint16_t aPort)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aUnicastAddress);
|
||||
OT_UNUSED_VARIABLE(aPort);
|
||||
}
|
||||
|
||||
void otPlatTrelUdp6UpdateAddress(otInstance *aInstance, const otIp6Address *aUnicastAddress)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aUnicastAddress);
|
||||
}
|
||||
|
||||
void otPlatTrelUdp6SubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aMulticastAddress)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aMulticastAddress);
|
||||
}
|
||||
|
||||
otError otPlatTrelUdp6SendTo(otInstance * aInstance,
|
||||
const uint8_t * aBuffer,
|
||||
uint16_t aLength,
|
||||
const otIp6Address *aDestAddress)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
otEXPECT(sEnabled);
|
||||
otEXPECT_ACTION(sNumPendingTx < TREL_MAX_PENDING_TX, error = OT_ERROR_ABORT);
|
||||
|
||||
memcpy(sPendingTx[sNumPendingTx].mPacketBuffer, aBuffer, aLength);
|
||||
sPendingTx[sNumPendingTx].mPacketLength = aLength;
|
||||
memcpy(&sPendingTx[sNumPendingTx].mDestIp6Address, aDestAddress, sizeof(otIp6Address));
|
||||
sNumPendingTx++;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError otPlatTrelUdp6SetTestMode(otInstance *aInstance, bool aEnable)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
sEnabled = aEnable;
|
||||
|
||||
if (!sEnabled)
|
||||
{
|
||||
sNumPendingTx = 0;
|
||||
}
|
||||
|
||||
return OT_ERROR_NONE;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// platformTrel system
|
||||
|
||||
void platformTrelInit(uint32_t aSpeedUpFactor)
|
||||
{
|
||||
char *str;
|
||||
|
||||
str = getenv("PORT_OFFSET");
|
||||
|
||||
if (str != NULL)
|
||||
{
|
||||
char *endptr;
|
||||
|
||||
sPortOffset = (uint16_t)strtol(str, &endptr, 0);
|
||||
|
||||
if (*endptr != '\0')
|
||||
{
|
||||
fprintf(stderr, "\nInvalid PORT_OFFSET: %s\n", str);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sPortOffset *= (MAX_NETWORK_SIZE + 1);
|
||||
}
|
||||
|
||||
initFds();
|
||||
|
||||
OT_UNUSED_VARIABLE(aSpeedUpFactor);
|
||||
}
|
||||
|
||||
void platformTrelDeinit(void)
|
||||
{
|
||||
deinitFds();
|
||||
}
|
||||
|
||||
void platformTrelUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct timeval *aTimeout, int *aMaxFd)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aTimeout);
|
||||
|
||||
// Always ready to receive
|
||||
if (aReadFdSet != NULL)
|
||||
{
|
||||
FD_SET(sRxFd, aReadFdSet);
|
||||
|
||||
if (aMaxFd != NULL && *aMaxFd < sRxFd)
|
||||
{
|
||||
*aMaxFd = sRxFd;
|
||||
}
|
||||
}
|
||||
|
||||
if ((aWriteFdSet != NULL) && (sNumPendingTx > 0))
|
||||
{
|
||||
FD_SET(sTxFd, aWriteFdSet);
|
||||
|
||||
if (aMaxFd != NULL && *aMaxFd < sTxFd)
|
||||
{
|
||||
*aMaxFd = sTxFd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void platformTrelProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet)
|
||||
{
|
||||
if (FD_ISSET(sTxFd, aWriteFdSet) && (sNumPendingTx > 0))
|
||||
{
|
||||
sendPendingTxPackets();
|
||||
}
|
||||
|
||||
if (FD_ISSET(sRxFd, aReadFdSet))
|
||||
{
|
||||
uint8_t rxPacketBuffer[TREL_MAX_PACKET_SIZE];
|
||||
uint16_t rxPacketLength;
|
||||
ssize_t rval;
|
||||
|
||||
rval = recvfrom(sRxFd, (char *)rxPacketBuffer, sizeof(rxPacketBuffer), 0, NULL, NULL);
|
||||
|
||||
if (rval < 0)
|
||||
{
|
||||
perror("recvfrom(sRxFd)");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
rxPacketLength = (uint16_t)(rval);
|
||||
|
||||
#if DEBUG_LOG
|
||||
fprintf(stderr, "\n[trel-udp6] recvdPacket()");
|
||||
dumpBuffer(rxPacketBuffer, rxPacketLength);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
if (sEnabled)
|
||||
{
|
||||
otPlatTrelUdp6HandleReceived(aInstance, rxPacketBuffer, rxPacketLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is added for RCP build to be built ok
|
||||
OT_TOOL_WEAK void otPlatTrelUdp6HandleReceived(otInstance *aInstance, uint8_t *aBuffer, uint16_t aLength)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aBuffer);
|
||||
OT_UNUSED_VARIABLE(aLength);
|
||||
|
||||
assert(false);
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
@@ -100,6 +100,7 @@ ot_platform_headers = \
|
||||
openthread/platform/settings.h \
|
||||
openthread/platform/messagepool.h \
|
||||
openthread/platform/toolchain.h \
|
||||
openthread/platform/trel-udp6.h \
|
||||
$(NULL)
|
||||
|
||||
ot_platformdir = $(includedir)/openthread/platform
|
||||
|
||||
@@ -105,6 +105,7 @@ source_set("openthread") {
|
||||
"platform/spi-slave.h",
|
||||
"platform/time.h",
|
||||
"platform/toolchain.h",
|
||||
"platform/trel-udp6.h",
|
||||
"platform/uart.h",
|
||||
"platform/udp.h",
|
||||
"random_crypto.h",
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
* This file includes the platform abstraction for Thread Radio Encapsulation Link (TREL) using an IPv6/UDP interface.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef OPENTHREAD_PLATFORM_TREL_UDP6_H_
|
||||
#define OPENTHREAD_PLATFORM_TREL_UDP6_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <openthread/error.h>
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/ip6.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @addtogroup plat-trel
|
||||
*
|
||||
* @brief
|
||||
* This module includes the platform abstraction for Thread Radio Encapsulation Link (TREL) using an IPv6/UDP
|
||||
* interface.
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This function initializes the TREL IPv6/UDP interface.
|
||||
*
|
||||
* This function is called before any other TREL platform functions.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aUnicastAddress The unicast address to add to interface and use as tx source and rx destination.
|
||||
* @param[in] aUdpPort A UDP port number to use.
|
||||
*
|
||||
*/
|
||||
void otPlatTrelUdp6Init(otInstance *aInstance, const otIp6Address *aUnicastAddress, uint16_t aUdpPort);
|
||||
|
||||
/**
|
||||
* This function updates the unicast IPv6 address for TREL IPv6/UDP interface.
|
||||
*
|
||||
* The interface should only have one unicast IPv6 address. Calling this function replaces any previously set unicast
|
||||
* IPv6 address (during initialization from `otPlatTrelUdp6Init` or earlier calls to `otPlatTrelUdp6UpdateAddress()`).
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aUnicastAddress The unicast address to add to interface and use for as tx source and rx destination.
|
||||
*
|
||||
*/
|
||||
void otPlatTrelUdp6UpdateAddress(otInstance *aInstance, const otIp6Address *aUnicastAddress);
|
||||
|
||||
/**
|
||||
* This function subscribes the TREL IPv6/UDP interface to a new multicast address.
|
||||
*
|
||||
* This function may be called multiple times to subscribe to different addresses. The interface should accept/receive
|
||||
* packets destined to any previously subscribed multicast address in addition to the unicast address added from the
|
||||
* `otPlatTrelUdp6Init()` function when interface was initialized.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aMulticastAddress A multicast IPv6 address.
|
||||
*
|
||||
*/
|
||||
void otPlatTrelUdp6SubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aMulticastAddress);
|
||||
|
||||
/**
|
||||
* This function requests a packet to be sent to a given destination.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aBuffer A pointer to buffer containing the packet to send.
|
||||
* @param[in] aLength Packet length (number of bytes).
|
||||
* @param[in] aDestAddress The destination IPv6 address (can be a unicast or a multicast IPv6 address).
|
||||
*
|
||||
* @retval OT_ERROR_NONE The tx request was handled successfully.
|
||||
* @retval OT_ERROR_ABORT The interface is not ready and tx was aborted
|
||||
*
|
||||
*/
|
||||
otError otPlatTrelUdp6SendTo(otInstance * aInstance,
|
||||
const uint8_t * aBuffer,
|
||||
uint16_t aLength,
|
||||
const otIp6Address *aDestAddress);
|
||||
|
||||
/**
|
||||
* This function is a callback from platform to notify of a received packet.
|
||||
*
|
||||
* @note The buffer content (up to its specified length) may get changed during processing by OpenThread core (e.g.,
|
||||
* decrypted in place), so the platform implementation should expect that after returning from this function the
|
||||
* packet @p aBuffer content may have been altered.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aBuffer A buffer containing the received packet.
|
||||
* @param[in] aLength Packet length (number of bytes).
|
||||
*
|
||||
*/
|
||||
extern void otPlatTrelUdp6HandleReceived(otInstance *aInstance, uint8_t *aBuffer, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* This optional function is intended for testing only. It changes the test mode status for TREL interface.
|
||||
*
|
||||
* This function requests TREL interface to be temporarily disabled or enabled. When disabled all traffic flow through
|
||||
* the TREL interface should be silently dropped.
|
||||
*
|
||||
* A default weak implementation of this method is provided by OpenThread (returning NOT_IMPLEMENTED).
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance structure.
|
||||
* @param[in] aEnable Indicates whether to enable/disable the TREL interface.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully changed the TREL interface test status (enabled/disabled).
|
||||
* @retval OT_ERROR_NOT_IMPLEMENTED This function is not provided by the platform.
|
||||
*
|
||||
*/
|
||||
otError otPlatTrelUdp6SetTestMode(otInstance *aInstance, bool aEnable);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // end of extern "C"
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_PLATFORM_TREL_UDP6_H_
|
||||
+6
-2
@@ -496,8 +496,12 @@ openthread_core_files = [
|
||||
"radio/radio.hpp",
|
||||
"radio/radio_callbacks.cpp",
|
||||
"radio/radio_platform.cpp",
|
||||
"radio/trel.cpp",
|
||||
"radio/trel.hpp",
|
||||
"radio/trel_interface.cpp",
|
||||
"radio/trel_interface.hpp",
|
||||
"radio/trel_link.cpp",
|
||||
"radio/trel_link.hpp",
|
||||
"radio/trel_packet.cpp",
|
||||
"radio/trel_packet.hpp",
|
||||
"thread/address_resolver.cpp",
|
||||
"thread/address_resolver.hpp",
|
||||
"thread/announce_begin_server.cpp",
|
||||
|
||||
@@ -144,7 +144,9 @@ set(COMMON_SOURCES
|
||||
radio/radio.cpp
|
||||
radio/radio_callbacks.cpp
|
||||
radio/radio_platform.cpp
|
||||
radio/trel.cpp
|
||||
radio/trel_interface.cpp
|
||||
radio/trel_link.cpp
|
||||
radio/trel_packet.cpp
|
||||
thread/address_resolver.cpp
|
||||
thread/announce_begin_server.cpp
|
||||
thread/announce_sender.cpp
|
||||
|
||||
@@ -221,7 +221,9 @@ SOURCES_COMMON = \
|
||||
radio/radio.cpp \
|
||||
radio/radio_callbacks.cpp \
|
||||
radio/radio_platform.cpp \
|
||||
radio/trel.cpp \
|
||||
radio/trel_interface.cpp \
|
||||
radio/trel_link.cpp \
|
||||
radio/trel_packet.cpp \
|
||||
thread/address_resolver.cpp \
|
||||
thread/announce_begin_server.cpp \
|
||||
thread/announce_sender.cpp \
|
||||
@@ -457,7 +459,9 @@ HEADERS_COMMON = \
|
||||
net/tcp.hpp \
|
||||
net/udp6.hpp \
|
||||
radio/radio.hpp \
|
||||
radio/trel.hpp \
|
||||
radio/trel_interface.hpp \
|
||||
radio/trel_link.hpp \
|
||||
radio/trel_packet.hpp \
|
||||
thread/address_resolver.hpp \
|
||||
thread/announce_begin_server.hpp \
|
||||
thread/announce_sender.hpp \
|
||||
|
||||
@@ -515,6 +515,11 @@ template <> inline Trel::Link &Instance::Get(void)
|
||||
{
|
||||
return mThreadNetif.mMac.mLinks.mTrel;
|
||||
}
|
||||
|
||||
template <> inline Trel::Interface &Instance::Get(void)
|
||||
{
|
||||
return mThreadNetif.mMac.mLinks.mTrel.mInterface;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
#include "mac/mac_links.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
#include "mac/sub_mac.hpp"
|
||||
#include "radio/trel.hpp"
|
||||
#include "radio/trel_link.hpp"
|
||||
#include "thread/key_manager.hpp"
|
||||
#include "thread/link_quality.hpp"
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "radio/trel.hpp"
|
||||
#include "radio/trel_link.hpp"
|
||||
#if !OPENTHREAD_RADIO || OPENTHREAD_CONFIG_MAC_SOFTWARE_TX_SECURITY_ENABLE
|
||||
#include "crypto/aes_ccm.hpp"
|
||||
#endif
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "mac/mac_frame.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
#include "mac/sub_mac.hpp"
|
||||
#include "radio/trel.hpp"
|
||||
#include "radio/trel_link.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Mac {
|
||||
@@ -377,6 +377,9 @@ public:
|
||||
mSubMac.SetExtAddress(aExtAddress);
|
||||
#else
|
||||
mExtAddress = aExtAddress;
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTrel.HandleExtAddressChange();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements Thread Radio Encapsulation Link (TREL).
|
||||
*/
|
||||
|
||||
#include "trel.hpp"
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "common/locator-getters.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
namespace ot {
|
||||
namespace Trel {
|
||||
|
||||
Link::Link(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
{
|
||||
memset(&mTxFrame, 0, sizeof(mTxFrame));
|
||||
mTxFrame.mPsdu = &mFrameBuffer[kHeaderSize];
|
||||
mTxFrame.SetLength(0);
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
mTxFrame.SetRadioType(Mac::kRadioTypeTrel);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Link::Send(void)
|
||||
{
|
||||
Get<Mac::Mac>().RecordFrameTransmitStatus(mTxFrame, NULL, OT_ERROR_ABORT, 0, false);
|
||||
Get<Mac::Mac>().HandleTransmitDone(mTxFrame, NULL, OT_ERROR_ABORT);
|
||||
}
|
||||
|
||||
} // namespace Trel
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for Thread Radio Encapsulation Link (TREL).
|
||||
*/
|
||||
|
||||
#ifndef TREL_HPP_
|
||||
#define TREL_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include "common/locator.hpp"
|
||||
#include "mac/mac_frame.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
namespace ot {
|
||||
namespace Trel {
|
||||
|
||||
/**
|
||||
* @addtogroup core-trel
|
||||
*
|
||||
* @brief
|
||||
* This module includes definitions for Thread Radio Encapsulation Link (TREL)
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class represents a Thread Radio Encapsulation Link (TREL).
|
||||
*
|
||||
*/
|
||||
class Link : public InstanceLocator
|
||||
{
|
||||
friend class Instance;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kMtuSize = 1600,
|
||||
kFcsSize = 0,
|
||||
};
|
||||
|
||||
explicit Link(Instance &aInstance);
|
||||
|
||||
void SetPanId(Mac::PanId) {}
|
||||
|
||||
void Enable(void) {}
|
||||
void Disable(void) {}
|
||||
|
||||
void Sleep(void) {}
|
||||
void Receive(uint8_t) {}
|
||||
void Send(void);
|
||||
|
||||
Mac::TxFrame &GetTransmitFrame(void) { return mTxFrame; }
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kHeaderSize = 10,
|
||||
};
|
||||
|
||||
Mac::TxFrame mTxFrame;
|
||||
uint8_t mFrameBuffer[kHeaderSize + kMtuSize];
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
} // namespace Trel
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
#endif // TREL_HPP_
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements Thread Radio Encapsulation Link (TREL) interface.
|
||||
*/
|
||||
|
||||
#include "trel_interface.hpp"
|
||||
|
||||
#include <openthread/platform/trel-udp6.h>
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "common/locator-getters.hpp"
|
||||
#include "common/logging.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
namespace ot {
|
||||
namespace Trel {
|
||||
|
||||
Interface::Interface(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mInitialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
void Interface::Init(void)
|
||||
{
|
||||
Ip6::Address ip6Address;
|
||||
|
||||
VerifyOrExit(!mInitialized);
|
||||
|
||||
ip6Address.SetToLinkLocalAddress(Get<Mac::Mac>().GetExtAddress());
|
||||
otPlatTrelUdp6Init(&GetInstance(), &ip6Address, kUdpPort);
|
||||
|
||||
CreateMulticastIp6Address(ip6Address);
|
||||
otPlatTrelUdp6SubscribeMulticastAddress(&GetInstance(), &ip6Address);
|
||||
|
||||
mInitialized = true;
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Interface::HandleExtAddressChange(void)
|
||||
{
|
||||
Ip6::Address ip6Address;
|
||||
|
||||
VerifyOrExit(mInitialized);
|
||||
|
||||
ip6Address.SetToLinkLocalAddress(Get<Mac::Mac>().GetExtAddress());
|
||||
otPlatTrelUdp6UpdateAddress(&GetInstance(), &ip6Address);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
otError Interface::Send(const Packet &aPacket)
|
||||
{
|
||||
Ip6::Address destIp6Address;
|
||||
|
||||
switch (aPacket.GetHeader().GetType())
|
||||
{
|
||||
case Header::kTypeBroadcast:
|
||||
CreateMulticastIp6Address(destIp6Address);
|
||||
break;
|
||||
|
||||
case Header::kTypeUnicast:
|
||||
case Header::kTypeAck:
|
||||
destIp6Address.SetToLinkLocalAddress(aPacket.GetHeader().GetDestination());
|
||||
break;
|
||||
}
|
||||
|
||||
return otPlatTrelUdp6SendTo(&GetInstance(), aPacket.GetBuffer(), aPacket.GetLength(), &destIp6Address);
|
||||
}
|
||||
|
||||
void Interface::HandleReceived(uint8_t *aBuffer, uint16_t aLength)
|
||||
{
|
||||
mRxPacket.Init(aBuffer, aLength);
|
||||
Get<Link>().ProcessReceivedPacket(mRxPacket);
|
||||
}
|
||||
|
||||
void Interface::CreateMulticastIp6Address(Ip6::Address &aIp6Address)
|
||||
{
|
||||
// Use ff02::1 (Link-local All Nodes multicast address).
|
||||
aIp6Address.SetToLinkLocalAllNodesMulticast();
|
||||
}
|
||||
|
||||
} // namespace Trel
|
||||
} // namespace ot
|
||||
|
||||
extern "C" void otPlatTrelUdp6HandleReceived(otInstance *aInstance, uint8_t *aBuffer, uint16_t aLength)
|
||||
{
|
||||
ot::Instance &instance = *static_cast<ot::Instance *>(aInstance);
|
||||
|
||||
VerifyOrExit(instance.IsInitialized());
|
||||
instance.Get<ot::Trel::Interface>().HandleReceived(aBuffer, aLength);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" OT_TOOL_WEAK otError otPlatTrelUdp6SetTestMode(otInstance *aInstance, bool aEnable)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aEnable);
|
||||
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for Thread Radio Encapsulation Link (TREL) interface.
|
||||
*/
|
||||
|
||||
#ifndef TREL_INTERFACE_HPP_
|
||||
#define TREL_INTERFACE_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include "common/locator.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
#include "net/ip6_address.hpp"
|
||||
#include "radio/trel_packet.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
namespace ot {
|
||||
namespace Trel {
|
||||
|
||||
/**
|
||||
* This class represents a TREL link interface.
|
||||
*
|
||||
*/
|
||||
class Interface : public InstanceLocator
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes an `Interface` object
|
||||
*
|
||||
* @param[in] aInstance A reference to the OpenThread instance.
|
||||
*
|
||||
*/
|
||||
explicit Interface(Instance &aInstance);
|
||||
|
||||
/**
|
||||
* This method initializes the interface.
|
||||
*
|
||||
* This method should be called after OpenThread instance itself is fully initialized, allowing the `Init()` method
|
||||
* to use method from `Instance` and any of its containing objects.
|
||||
*
|
||||
*/
|
||||
void Init(void);
|
||||
|
||||
/**
|
||||
* This method indicates whether the interface is initialized or not.
|
||||
*
|
||||
* @returns TRUE if the interface is initialized, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsInitialized(void) const { return mInitialized; }
|
||||
|
||||
/**
|
||||
* This method notifies the interface that device's extended MAC address has changed for it to update any
|
||||
* internal address/state.
|
||||
*
|
||||
*/
|
||||
void HandleExtAddressChange(void);
|
||||
|
||||
/**
|
||||
* This method sends a packet over the interface.
|
||||
*
|
||||
* @note There is no expected callback from the interface to notify completion of send.
|
||||
*
|
||||
* @param[in] aPacket A packet to send.
|
||||
*
|
||||
* @retval OT_ERROR_NONE The frame was sent successfully.
|
||||
* @retval OT_ERROR_ABORT The interface is not ready and send was aborted.
|
||||
*
|
||||
*/
|
||||
otError Send(const Packet &aPacket);
|
||||
|
||||
/**
|
||||
* This method is a callback from platform layer to handle a received packet over the interface.
|
||||
*
|
||||
* @param[in] aBuffer A pointer to buffer containing the received packet.
|
||||
* @param[in] aLength The length (number of bytes) in the received packet.
|
||||
*
|
||||
*/
|
||||
void HandleReceived(uint8_t *aBuffer, uint16_t aLength);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kUdpPort = 19788, // UDP port (same as MLE port).
|
||||
};
|
||||
|
||||
void CreateMulticastIp6Address(Ip6::Address &aIp6Address);
|
||||
|
||||
bool mInitialized;
|
||||
Packet mRxPacket;
|
||||
};
|
||||
|
||||
} // namespace Trel
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
#endif // TREL_INTERFACE_HPP_
|
||||
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements Thread Radio Encapsulation Link (TREL).
|
||||
*/
|
||||
|
||||
#include "trel_link.hpp"
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "common/locator-getters.hpp"
|
||||
#include "common/logging.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
namespace ot {
|
||||
namespace Trel {
|
||||
|
||||
Link::Link(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mState(kStateDisabled)
|
||||
, mRxChannel(0)
|
||||
, mPanId(Mac::kPanIdBroadcast)
|
||||
, mTxPacketNumber(0)
|
||||
, mTxTasklet(aInstance, HandleTxTasklet, this)
|
||||
, mTimer(aInstance, HandleTimer, this)
|
||||
, mInterface(aInstance)
|
||||
{
|
||||
memset(&mTxFrame, 0, sizeof(mTxFrame));
|
||||
memset(&mRxFrame, 0, sizeof(mRxFrame));
|
||||
memset(mAckFrameBuffer, 0, sizeof(mAckFrameBuffer));
|
||||
|
||||
mTxFrame.mPsdu = &mTxPacketBuffer[kMaxHeaderSize];
|
||||
mTxFrame.SetLength(0);
|
||||
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
mTxFrame.SetRadioType(Mac::kRadioTypeTrel);
|
||||
mRxFrame.SetRadioType(Mac::kRadioTypeTrel);
|
||||
#endif
|
||||
|
||||
// `mTxTasklet` is used for initializing the interface (in addition
|
||||
// to handling `Send()` requests). Invoking `Interface::Init()` from
|
||||
// a tasklet ensures that it happens after the constructors for
|
||||
// `Instance` and all its objects are done, allowing the interface
|
||||
// to safely use any of the core object methods (e.g., get the
|
||||
// randomly generated MAC address).
|
||||
|
||||
mTxTasklet.Post();
|
||||
mTimer.Start(kAckWaitWindow);
|
||||
}
|
||||
|
||||
void Link::Enable(void)
|
||||
{
|
||||
if (mState == kStateDisabled)
|
||||
{
|
||||
SetState(kStateSleep);
|
||||
}
|
||||
}
|
||||
|
||||
void Link::Disable(void)
|
||||
{
|
||||
if (mState != kStateDisabled)
|
||||
{
|
||||
SetState(kStateDisabled);
|
||||
}
|
||||
}
|
||||
|
||||
void Link::Sleep(void)
|
||||
{
|
||||
OT_ASSERT(mState != kStateDisabled);
|
||||
SetState(kStateSleep);
|
||||
}
|
||||
|
||||
void Link::Receive(uint8_t aChannel)
|
||||
{
|
||||
OT_ASSERT(mState != kStateDisabled);
|
||||
mRxChannel = aChannel;
|
||||
SetState(kStateReceive);
|
||||
}
|
||||
|
||||
void Link::Send(void)
|
||||
{
|
||||
OT_ASSERT(mState != kStateDisabled);
|
||||
|
||||
SetState(kStateTransmit);
|
||||
mTxTasklet.Post();
|
||||
}
|
||||
|
||||
void Link::HandleTxTasklet(Tasklet &aTasklet)
|
||||
{
|
||||
aTasklet.GetOwner<Link>().HandleTxTasklet();
|
||||
}
|
||||
|
||||
void Link::HandleTxTasklet(void)
|
||||
{
|
||||
if (!mInterface.IsInitialized())
|
||||
{
|
||||
mInterface.Init();
|
||||
}
|
||||
|
||||
BeginTransmit();
|
||||
}
|
||||
|
||||
void Link::BeginTransmit(void)
|
||||
{
|
||||
Mac::Address destAddr;
|
||||
Mac::PanId destPanId;
|
||||
Header::Type type;
|
||||
Packet txPacket;
|
||||
Neighbor * neighbor = nullptr;
|
||||
Mac::RxFrame *ackFrame = nullptr;
|
||||
|
||||
VerifyOrExit(mState == kStateTransmit);
|
||||
|
||||
// After sending a frame on a given channel we should
|
||||
// continue to rx on same channel
|
||||
mRxChannel = mTxFrame.GetChannel();
|
||||
|
||||
VerifyOrExit(!mTxFrame.IsEmpty(), InvokeSendDone(OT_ERROR_ABORT));
|
||||
|
||||
IgnoreError(mTxFrame.GetDstAddr(destAddr));
|
||||
|
||||
if (destAddr.IsNone() || destAddr.IsBroadcast())
|
||||
{
|
||||
type = Header::kTypeBroadcast;
|
||||
}
|
||||
else
|
||||
{
|
||||
type = Header::kTypeUnicast;
|
||||
neighbor = Get<NeighborTable>().FindNeighbor(destAddr, Neighbor::kInStateAnyExceptInvalid);
|
||||
|
||||
if (destAddr.IsShort())
|
||||
{
|
||||
if (neighbor != nullptr)
|
||||
{
|
||||
destAddr.SetExtended(neighbor->GetExtAddress());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Send as a broadcast since we don't know the dest
|
||||
// ext address to include in the packet header.
|
||||
type = Header::kTypeBroadcast;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mTxFrame.GetDstPanId(destPanId) != OT_ERROR_NONE)
|
||||
{
|
||||
destPanId = Mac::kPanIdBroadcast;
|
||||
}
|
||||
|
||||
txPacket.Init(type, mTxFrame.GetPsdu(), mTxFrame.GetLength());
|
||||
|
||||
if (neighbor == nullptr)
|
||||
{
|
||||
txPacket.GetHeader().SetAckMode(Header::kNoAck);
|
||||
txPacket.GetHeader().SetPacketNumber(mTxPacketNumber++);
|
||||
}
|
||||
else
|
||||
{
|
||||
txPacket.GetHeader().SetAckMode(Header::kAckRequested);
|
||||
txPacket.GetHeader().SetPacketNumber(neighbor->mTrelTxPacketNumber++);
|
||||
neighbor->mTrelCurrentPendingAcks++;
|
||||
}
|
||||
|
||||
txPacket.GetHeader().SetChannel(mTxFrame.GetChannel());
|
||||
txPacket.GetHeader().SetPanId(destPanId);
|
||||
txPacket.GetHeader().SetSource(Get<Mac::Mac>().GetExtAddress());
|
||||
|
||||
if (type == Header::kTypeUnicast)
|
||||
{
|
||||
OT_ASSERT(destAddr.IsExtended());
|
||||
txPacket.GetHeader().SetDestination(destAddr.GetExtended());
|
||||
}
|
||||
|
||||
otLogDebgMac("Trel: BeginTransmit() [%s] plen:%d", txPacket.GetHeader().ToString().AsCString(),
|
||||
txPacket.GetPayloadLength());
|
||||
|
||||
VerifyOrExit(mInterface.Send(txPacket) == OT_ERROR_NONE, InvokeSendDone(OT_ERROR_ABORT));
|
||||
|
||||
if (mTxFrame.GetAckRequest())
|
||||
{
|
||||
uint16_t fcf = Mac::Frame::kFcfFrameAck;
|
||||
|
||||
if (!Get<Mle::MleRouter>().IsRxOnWhenIdle())
|
||||
{
|
||||
fcf |= Mac::Frame::kFcfFramePending;
|
||||
}
|
||||
|
||||
// Prepare the ack frame (FCF followed by sequence number)
|
||||
Encoding::LittleEndian::WriteUint16(fcf, mAckFrameBuffer);
|
||||
mAckFrameBuffer[sizeof(fcf)] = mTxFrame.GetSequence();
|
||||
|
||||
mRxFrame.mPsdu = mAckFrameBuffer;
|
||||
mRxFrame.mLength = k154AckFrameSize;
|
||||
mRxFrame.mChannel = mTxFrame.GetChannel();
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
mRxFrame.mRadioType = Mac::kRadioTypeTrel;
|
||||
#endif
|
||||
mRxFrame.mInfo.mRxInfo.mTimestamp = 0;
|
||||
mRxFrame.mInfo.mRxInfo.mRssi = OT_RADIO_RSSI_INVALID;
|
||||
mRxFrame.mInfo.mRxInfo.mLqi = OT_RADIO_LQI_NONE;
|
||||
mRxFrame.mInfo.mRxInfo.mAckedWithFramePending = false;
|
||||
|
||||
ackFrame = &mRxFrame;
|
||||
}
|
||||
|
||||
InvokeSendDone(OT_ERROR_NONE, ackFrame);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Link::InvokeSendDone(otError aError, Mac::RxFrame *aAckFrame)
|
||||
{
|
||||
SetState(kStateReceive);
|
||||
|
||||
Get<Mac::Mac>().RecordFrameTransmitStatus(mTxFrame, aAckFrame, aError, /* aRetryCount */ 0, /* aWillRetx */ false);
|
||||
Get<Mac::Mac>().HandleTransmitDone(mTxFrame, aAckFrame, aError);
|
||||
}
|
||||
|
||||
void Link::HandleTimer(Timer &aTimer)
|
||||
{
|
||||
aTimer.GetOwner<Link>().HandleTimer();
|
||||
}
|
||||
|
||||
void Link::HandleTimer(void)
|
||||
{
|
||||
mTimer.Start(kAckWaitWindow);
|
||||
|
||||
#if OPENTHREAD_FTD
|
||||
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
|
||||
{
|
||||
HandleTimer(child);
|
||||
}
|
||||
|
||||
for (Router &router : Get<RouterTable>().Iterate())
|
||||
{
|
||||
HandleTimer(router);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Parent and ParentCandidate should also be updated as neighbors.
|
||||
// Parent is considered only when the device is detached or child.
|
||||
// When device becomes a router/leader the parent entry is copied
|
||||
// into the router table but the MLE parent may still stay in
|
||||
// valid state. Note that "Parent Candidate" may be in use on a
|
||||
// router/leader during a partition merge, so it is always treated
|
||||
// as a neighbor.
|
||||
|
||||
switch (Get<Mle::MleRouter>().GetRole())
|
||||
{
|
||||
case Mle::kRoleDisabled:
|
||||
break;
|
||||
|
||||
case Mle::kRoleDetached:
|
||||
case Mle::kRoleChild:
|
||||
HandleTimer(Get<Mle::MleRouter>().GetParent());
|
||||
|
||||
// Fall through
|
||||
|
||||
case Mle::kRoleRouter:
|
||||
case Mle::kRoleLeader:
|
||||
HandleTimer(Get<Mle::MleRouter>().GetParentCandidate());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Link::HandleTimer(Neighbor &aNeighbor)
|
||||
{
|
||||
VerifyOrExit(!aNeighbor.IsStateInvalid());
|
||||
|
||||
// Any remaining previous pending ack has timed out.
|
||||
|
||||
while (aNeighbor.mTrelPreviousPendingAcks > 0)
|
||||
{
|
||||
aNeighbor.mTrelPreviousPendingAcks--;
|
||||
|
||||
ReportDeferredAckStatus(aNeighbor, OT_ERROR_NO_ACK);
|
||||
VerifyOrExit(!aNeighbor.IsStateInvalid());
|
||||
}
|
||||
|
||||
aNeighbor.mTrelPreviousPendingAcks = aNeighbor.mTrelCurrentPendingAcks;
|
||||
aNeighbor.mTrelCurrentPendingAcks = 0;
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Link::ProcessReceivedPacket(Packet &aPacket)
|
||||
{
|
||||
Header::Type type;
|
||||
|
||||
VerifyOrExit(aPacket.IsHeaderValid());
|
||||
|
||||
type = aPacket.GetHeader().GetType();
|
||||
|
||||
if (type != Header::kTypeAck)
|
||||
{
|
||||
// No need to check state or channel for a TREL ack packet.
|
||||
// Note that TREL ack may be received much later than the tx
|
||||
// and device can be on a different rx channel.
|
||||
|
||||
VerifyOrExit((mState == kStateReceive) || (mState == kStateTransmit));
|
||||
VerifyOrExit(aPacket.GetHeader().GetChannel() == mRxChannel);
|
||||
}
|
||||
|
||||
if (mPanId != Mac::kPanIdBroadcast)
|
||||
{
|
||||
Mac::PanId rxPanId = aPacket.GetHeader().GetPanId();
|
||||
|
||||
VerifyOrExit((rxPanId == mPanId) || (rxPanId == Mac::kPanIdBroadcast));
|
||||
}
|
||||
|
||||
// Drop packets originating from same device.
|
||||
VerifyOrExit(aPacket.GetHeader().GetSource() != Get<Mac::Mac>().GetExtAddress());
|
||||
|
||||
if (type != Header::kTypeBroadcast)
|
||||
{
|
||||
VerifyOrExit(aPacket.GetHeader().GetDestination() == Get<Mac::Mac>().GetExtAddress());
|
||||
|
||||
if (type == Header::kTypeAck)
|
||||
{
|
||||
HandleAck(aPacket);
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
otLogDebgMac("Trel: ReceivedPacket() [%s] plen:%d", aPacket.GetHeader().ToString().AsCString(),
|
||||
aPacket.GetPayloadLength());
|
||||
|
||||
if (aPacket.GetHeader().GetAckMode() == Header::kAckRequested)
|
||||
{
|
||||
SendAck(aPacket);
|
||||
}
|
||||
|
||||
mRxFrame.mPsdu = aPacket.GetPayload();
|
||||
mRxFrame.mLength = aPacket.GetPayloadLength();
|
||||
mRxFrame.mChannel = aPacket.GetHeader().GetChannel();
|
||||
#if OPENTHREAD_CONFIG_MULTI_RADIO
|
||||
mRxFrame.mRadioType = Mac::kRadioTypeTrel;
|
||||
#endif
|
||||
mRxFrame.mInfo.mRxInfo.mTimestamp = 0;
|
||||
mRxFrame.mInfo.mRxInfo.mRssi = kRxRssi;
|
||||
mRxFrame.mInfo.mRxInfo.mLqi = OT_RADIO_LQI_NONE;
|
||||
mRxFrame.mInfo.mRxInfo.mAckedWithFramePending = true;
|
||||
|
||||
Get<Mac::Mac>().HandleReceivedFrame(&mRxFrame, OT_ERROR_NONE);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Link::HandleAck(Packet &aAckPacket)
|
||||
{
|
||||
otError ackError;
|
||||
Mac::Address srcAddress;
|
||||
Neighbor * neighbor;
|
||||
uint32_t ackNumber;
|
||||
|
||||
otLogDebgMac("Trel: HandleAck() [%s]", aAckPacket.GetHeader().ToString().AsCString());
|
||||
|
||||
srcAddress.SetExtended(aAckPacket.GetHeader().GetSource());
|
||||
neighbor = Get<NeighborTable>().FindNeighbor(srcAddress, Neighbor::kInStateAnyExceptInvalid);
|
||||
VerifyOrExit(neighbor != nullptr);
|
||||
|
||||
ackNumber = aAckPacket.GetHeader().GetPacketNumber();
|
||||
|
||||
// Verify that neighbor is waiting for acks and the received ack
|
||||
// number is within the range of expected ack numbers.
|
||||
|
||||
VerifyOrExit(neighbor->IsRxAckNumberValid(ackNumber));
|
||||
|
||||
do
|
||||
{
|
||||
// Check whether the received ack number matches the next
|
||||
// expected one. If it does not, it indicates that some of
|
||||
// packets missed their acks.
|
||||
|
||||
ackError = (ackNumber == neighbor->GetExpectedTrelAckNumber()) ? OT_ERROR_NONE : OT_ERROR_NO_ACK;
|
||||
|
||||
neighbor->DecrementPendingTrelAckCount();
|
||||
|
||||
ReportDeferredAckStatus(*neighbor, ackError);
|
||||
VerifyOrExit(!neighbor->IsStateInvalid());
|
||||
|
||||
} while (ackError == OT_ERROR_NO_ACK);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Link::SendAck(Packet &aRxPacket)
|
||||
{
|
||||
Packet ackPacket;
|
||||
|
||||
ackPacket.Init(mAckPacketBuffer, sizeof(mAckPacketBuffer));
|
||||
|
||||
ackPacket.GetHeader().Init(Header::kTypeAck);
|
||||
ackPacket.GetHeader().SetAckMode(Header::kNoAck);
|
||||
ackPacket.GetHeader().SetChannel(aRxPacket.GetHeader().GetChannel());
|
||||
ackPacket.GetHeader().SetPanId(aRxPacket.GetHeader().GetPanId());
|
||||
ackPacket.GetHeader().SetPacketNumber(aRxPacket.GetHeader().GetPacketNumber());
|
||||
ackPacket.GetHeader().SetSource(Get<Mac::Mac>().GetExtAddress());
|
||||
ackPacket.GetHeader().SetDestination(aRxPacket.GetHeader().GetSource());
|
||||
|
||||
otLogDebgMac("Trel: SendAck [%s]", ackPacket.GetHeader().ToString().AsCString());
|
||||
|
||||
IgnoreError(mInterface.Send(ackPacket));
|
||||
}
|
||||
|
||||
void Link::ReportDeferredAckStatus(Neighbor &aNeighbor, otError aError)
|
||||
{
|
||||
otLogDebgMac("Trel: ReportDeferredAckStatus(): %s for %s", aNeighbor.GetExtAddress().ToString().AsCString(),
|
||||
otThreadErrorToString(aError));
|
||||
|
||||
Get<MeshForwarder>().HandleDeferredAck(aNeighbor, aError);
|
||||
}
|
||||
|
||||
void Link::SetState(State aState)
|
||||
{
|
||||
if (mState != aState)
|
||||
{
|
||||
otLogDebgMac("Trel: State: %s -> %s", StateToString(mState), StateToString(aState));
|
||||
mState = aState;
|
||||
}
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START
|
||||
|
||||
const char *Link::StateToString(State aState)
|
||||
{
|
||||
static const char *kStateStrings[] = {
|
||||
"Disabled", // kStateDisabled
|
||||
"Sleep", // kStateSleep
|
||||
"Receive", // kStateReceive
|
||||
"Transmit", // kStateTransmit
|
||||
};
|
||||
|
||||
return (static_cast<uint8_t>(aState) < OT_ARRAY_LENGTH(kStateStrings)) ? kStateStrings[aState] : "Unknown";
|
||||
}
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
} // namespace Trel
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for Thread Radio Encapsulation Link (TREL).
|
||||
*/
|
||||
|
||||
#ifndef TREL_LINK_HPP_
|
||||
#define TREL_LINK_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include "common/encoding.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/tasklet.hpp"
|
||||
#include "common/timer.hpp"
|
||||
#include "mac/mac_frame.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
#include "radio/trel_interface.hpp"
|
||||
#include "radio/trel_packet.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
namespace ot {
|
||||
|
||||
class Neighbor;
|
||||
|
||||
namespace Trel {
|
||||
|
||||
/**
|
||||
* @addtogroup core-trel
|
||||
*
|
||||
* @brief
|
||||
* This module includes definitions for Thread Radio Encapsulation Link (TREL)
|
||||
*
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class represents a Thread Radio Encapsulation Link (TREL).
|
||||
*
|
||||
*/
|
||||
class Link : public InstanceLocator
|
||||
{
|
||||
friend class ot::Instance;
|
||||
friend class Interface;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kMtuSize = OT_RADIO_FRAME_MAX_SIZE, ///< MTU size for TREL frame.
|
||||
kFcsSize = 2, ///< FCS size for TREL frame.
|
||||
};
|
||||
|
||||
/**
|
||||
* This constructor initializes the `Link` object.
|
||||
*
|
||||
* @param[in] aInstance A reference to the OpenThread instance.
|
||||
*
|
||||
*/
|
||||
explicit Link(Instance &aInstance);
|
||||
|
||||
/**
|
||||
* This method sets the PAN Identifier.
|
||||
*
|
||||
* @param[in] aPanId A PAN Identifier.
|
||||
*
|
||||
*/
|
||||
void SetPanId(Mac::PanId aPanId) { mPanId = aPanId; }
|
||||
|
||||
/**
|
||||
* This method notifies TREL radio link that device's extended MAC address has changed for it to update any
|
||||
* internal address/state.
|
||||
*
|
||||
*/
|
||||
void HandleExtAddressChange(void) { mInterface.HandleExtAddressChange(); }
|
||||
|
||||
/**
|
||||
* This method enables the TREL radio link.
|
||||
*
|
||||
*/
|
||||
void Enable(void);
|
||||
|
||||
/**
|
||||
* This method disables the TREL radio link.
|
||||
*
|
||||
*/
|
||||
void Disable(void);
|
||||
|
||||
/**
|
||||
* This method requests TREL radio link to transition to Sleep mode
|
||||
*
|
||||
*/
|
||||
void Sleep(void);
|
||||
|
||||
/**
|
||||
* This method requests TREL radio link to transition to Receive mode on a given channel.
|
||||
*
|
||||
* `Mac::HandleReceivedFrame()` is used to notify MAC layer upon receiving a frame.
|
||||
*
|
||||
* @param[in] aChannel The channel to receive on.
|
||||
*
|
||||
*/
|
||||
void Receive(uint8_t aChannel);
|
||||
|
||||
/**
|
||||
* This method gets the radio transmit frame for TREL radio link.
|
||||
*
|
||||
* @returns The transmit frame.
|
||||
*
|
||||
*/
|
||||
Mac::TxFrame &GetTransmitFrame(void) { return mTxFrame; }
|
||||
|
||||
/**
|
||||
* This method requests a frame to be sent over TREL radio link.
|
||||
*
|
||||
* The frame should be already placed in `GetTransmitFrame()` frame.
|
||||
*
|
||||
* `Mac::RecordFrameTransmitStatus()` and `Mac::HandleTransmitDone()` are used to notify the success or error status
|
||||
* of frame transmission upon completion of send.
|
||||
*
|
||||
*/
|
||||
void Send(void);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kMaxHeaderSize = sizeof(Header),
|
||||
k154AckFrameSize = 3 + kFcsSize,
|
||||
kRxRssi = -20, // The RSSI value used for received frames on TREL radio link.
|
||||
kAckWaitWindow = 750, // (in msec)
|
||||
};
|
||||
|
||||
enum State : uint8_t
|
||||
{
|
||||
kStateDisabled,
|
||||
kStateSleep,
|
||||
kStateReceive,
|
||||
kStateTransmit,
|
||||
};
|
||||
|
||||
void SetState(State aState);
|
||||
void BeginTransmit(void);
|
||||
void InvokeSendDone(otError aError) { InvokeSendDone(aError, nullptr); }
|
||||
void InvokeSendDone(otError aError, Mac::RxFrame *aAckFrame);
|
||||
void ProcessReceivedPacket(Packet &aPacket);
|
||||
void HandleAck(Packet &aAckPacket);
|
||||
void SendAck(Packet &aRxPacket);
|
||||
void ReportDeferredAckStatus(Neighbor &aNeighbor, otError aError);
|
||||
void HandleTimer(Neighbor &aNeighbor);
|
||||
|
||||
static void HandleTxTasklet(Tasklet &aTasklet);
|
||||
void HandleTxTasklet(void);
|
||||
|
||||
static void HandleTimer(Timer &aTimer);
|
||||
void HandleTimer(void);
|
||||
|
||||
static const char *StateToString(State aState);
|
||||
|
||||
State mState;
|
||||
uint8_t mRxChannel;
|
||||
Mac::PanId mPanId;
|
||||
uint32_t mTxPacketNumber;
|
||||
Tasklet mTxTasklet;
|
||||
TimerMilli mTimer;
|
||||
Interface mInterface;
|
||||
Mac::RxFrame mRxFrame;
|
||||
Mac::TxFrame mTxFrame;
|
||||
uint8_t mTxPacketBuffer[kMaxHeaderSize + kMtuSize];
|
||||
uint8_t mAckPacketBuffer[kMaxHeaderSize];
|
||||
uint8_t mAckFrameBuffer[k154AckFrameSize];
|
||||
};
|
||||
|
||||
/**
|
||||
* This class defines all the neighbor info required for TREL link.
|
||||
*
|
||||
* `Neighbor` class publicly inherits from this class.
|
||||
*
|
||||
*/
|
||||
class NeighborInfo
|
||||
{
|
||||
friend class Link;
|
||||
|
||||
private:
|
||||
uint32_t GetPendingTrelAckCount(void) const { return (mTrelPreviousPendingAcks + mTrelCurrentPendingAcks); }
|
||||
|
||||
void DecrementPendingTrelAckCount(void)
|
||||
{
|
||||
if (mTrelPreviousPendingAcks != 0)
|
||||
{
|
||||
mTrelPreviousPendingAcks--;
|
||||
}
|
||||
else if (mTrelCurrentPendingAcks != 0)
|
||||
{
|
||||
mTrelCurrentPendingAcks--;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t GetExpectedTrelAckNumber(void) const { return mTrelTxPacketNumber - GetPendingTrelAckCount(); }
|
||||
|
||||
bool IsRxAckNumberValid(uint32_t aAckNumber) const
|
||||
{
|
||||
// Note that calculating the difference between `aAckNumber`
|
||||
// and `GetExpectedTrelAckNumber` will correctly handle the
|
||||
// roll-over of packet number value.
|
||||
|
||||
return (GetPendingTrelAckCount() != 0) && (aAckNumber - GetExpectedTrelAckNumber() < GetPendingTrelAckCount());
|
||||
}
|
||||
|
||||
uint32_t mTrelTxPacketNumber; // Next packet number to use for tx
|
||||
uint16_t mTrelCurrentPendingAcks; // Number of pending acks for current interval.
|
||||
uint16_t mTrelPreviousPendingAcks; // Number of pending acks for previous interval.
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
*/
|
||||
|
||||
} // namespace Trel
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
#endif // TREL_LINK_HPP_
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file implements Thread Radio Encapsulation Link (TREL) packet.
|
||||
*/
|
||||
|
||||
#include "trel_packet.hpp"
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/debug.hpp"
|
||||
#include "common/instance.hpp"
|
||||
#include "common/locator-getters.hpp"
|
||||
#include "common/logging.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
namespace ot {
|
||||
namespace Trel {
|
||||
|
||||
void Header::SetAckMode(AckMode aAckMode)
|
||||
{
|
||||
switch (aAckMode)
|
||||
{
|
||||
case kNoAck:
|
||||
mControl &= ~kAckModeFlag;
|
||||
break;
|
||||
|
||||
case kAckRequested:
|
||||
mControl |= kAckModeFlag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t Header::GetSize(Type aType)
|
||||
{
|
||||
uint16_t size = sizeof(Header);
|
||||
|
||||
switch (aType)
|
||||
{
|
||||
case kTypeBroadcast:
|
||||
size -= sizeof(Mac::ExtAddress); // Exclude mDestination field.
|
||||
break;
|
||||
|
||||
case kTypeUnicast:
|
||||
case kTypeAck:
|
||||
break;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
Header::InfoString Header::ToString(void) const
|
||||
{
|
||||
Type type = GetType();
|
||||
InfoString string;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case kTypeBroadcast:
|
||||
IgnoreError(string.Set("broadcast ch:%d", GetChannel()));
|
||||
break;
|
||||
|
||||
case kTypeUnicast:
|
||||
IgnoreError(string.Set("unicast ch:%d", GetChannel()));
|
||||
break;
|
||||
|
||||
case kTypeAck:
|
||||
IgnoreError(string.Set("ack"));
|
||||
break;
|
||||
}
|
||||
|
||||
IgnoreError(
|
||||
string.Append(" panid:%04x num:%lu src:%s", GetPanId(), GetPacketNumber(), GetSource().ToString().AsCString()));
|
||||
|
||||
if ((type == kTypeUnicast) || (type == kTypeAck))
|
||||
{
|
||||
IgnoreError(string.Append(" dst:%s", GetDestination().ToString().AsCString()));
|
||||
}
|
||||
|
||||
if ((type == kTypeUnicast) || (type == kTypeBroadcast))
|
||||
{
|
||||
IgnoreError(string.Append(GetAckMode() == kNoAck ? " no-ack" : " ack-req"));
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
void Packet::Init(uint8_t *aBuffer, uint16_t aLength)
|
||||
{
|
||||
mBuffer = aBuffer;
|
||||
mLength = aLength;
|
||||
}
|
||||
|
||||
void Packet::Init(Header::Type aType, uint8_t *mPayload, uint16_t mPayloadLength)
|
||||
{
|
||||
uint16_t headerSize = Header::GetSize(aType);
|
||||
|
||||
// The payload buffer should reserve enough bytes for
|
||||
// header (depending on type) before the payload.
|
||||
|
||||
Init(mPayload - headerSize, mPayloadLength + headerSize);
|
||||
GetHeader().Init(aType);
|
||||
}
|
||||
|
||||
bool Packet::IsHeaderValid(void) const
|
||||
{
|
||||
return ((mBuffer != nullptr) && (mLength > 0) && GetHeader().IsVersionValid() &&
|
||||
(mLength >= GetHeader().GetLength()));
|
||||
}
|
||||
|
||||
} // namespace Trel
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
* Copyright (c) 2019, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for Thread Radio Encapsulation Link (TREL) Packet
|
||||
*/
|
||||
|
||||
#ifndef TREL_PACKET_HPP_
|
||||
#define TREL_PACKET_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include "common/encoding.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/string.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
namespace ot {
|
||||
namespace Trel {
|
||||
|
||||
/**
|
||||
* This class represents a TREL radio link packet encapsulation header.
|
||||
*
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class Header
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This enumeration defines packet types.
|
||||
*
|
||||
*/
|
||||
enum Type
|
||||
{
|
||||
kTypeBroadcast = 0, ///< A TREL broadcast packet.
|
||||
kTypeUnicast = 1, ///< A TREL unicast packet.
|
||||
kTypeAck = 2, ///< A TREL Ack packet.
|
||||
};
|
||||
|
||||
/**
|
||||
* This enumeration represents Ack Mode field in TREL header.
|
||||
*
|
||||
*/
|
||||
enum AckMode
|
||||
{
|
||||
kNoAck, ///< No TREL Ack is requested.
|
||||
kAckRequested, ///< A TREL Ack is requested.
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
kInfoStringSize = 128, ///< Max chars needed for the info string representation (@sa ToInfoString()).
|
||||
};
|
||||
|
||||
/**
|
||||
* This type defines the fixed-length `String` object returned from `ToString()` method.
|
||||
*
|
||||
*/
|
||||
typedef String<kInfoStringSize> InfoString;
|
||||
|
||||
/**
|
||||
* This method initializes the header.
|
||||
*
|
||||
* @param[in] aType The header type.
|
||||
*
|
||||
*/
|
||||
void Init(Type aType) { mControl = aType + kVersion; }
|
||||
|
||||
/**
|
||||
* This method checks whether the version field in header is valid or not
|
||||
*
|
||||
* @returns TRUE if the version field is valid, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
bool IsVersionValid(void) const { return (mControl & kVersionMask) == kVersion; }
|
||||
|
||||
/**
|
||||
* This method gets the packet type.
|
||||
*
|
||||
* @returns The packet type.
|
||||
*
|
||||
*/
|
||||
Type GetType(void) const { return static_cast<Type>(mControl & kTypeMask); }
|
||||
|
||||
/**
|
||||
* This method gets the header length based on its type.
|
||||
*
|
||||
* @returns the header length (number of bytes).
|
||||
*
|
||||
*/
|
||||
uint16_t GetLength(void) const { return GetSize(GetType()); }
|
||||
|
||||
/**
|
||||
* This method gets the Ack Mode field from the header.
|
||||
*
|
||||
* @returns The Ack Mode field.
|
||||
*
|
||||
*/
|
||||
AckMode GetAckMode(void) const { return (mControl & kAckModeFlag) ? kAckRequested : kNoAck; }
|
||||
|
||||
/**
|
||||
* This method sets the Ack Mode field in the header.
|
||||
*
|
||||
* @param[in] aAckMode The Ack Mode field
|
||||
*
|
||||
*/
|
||||
void SetAckMode(AckMode aAckMode);
|
||||
|
||||
/**
|
||||
* This method gets the channel field from the header.
|
||||
*
|
||||
* @returns The channel field.
|
||||
*
|
||||
*/
|
||||
uint8_t GetChannel(void) const { return mChannel; }
|
||||
|
||||
/**
|
||||
* This method sets the channel field in the header.
|
||||
*
|
||||
* @param[in] aChannel A channel.
|
||||
*
|
||||
*/
|
||||
void SetChannel(uint8_t aChannel) { mChannel = aChannel; }
|
||||
|
||||
/**
|
||||
* This method gets the PAN Identifier field from the header.
|
||||
*
|
||||
* @returns The PAN Identifier field.
|
||||
*
|
||||
*/
|
||||
Mac::PanId GetPanId(void) const { return Encoding::BigEndian::HostSwap16(mPanId); }
|
||||
|
||||
/**
|
||||
* This method sets the PAN Identifier field in the header.
|
||||
*
|
||||
* @param[in] aPanId A PAN Identifier.
|
||||
*
|
||||
*/
|
||||
void SetPanId(Mac::PanId aPanId) { mPanId = Encoding::BigEndian::HostSwap16(aPanId); }
|
||||
|
||||
/**
|
||||
* This method gets the packet number field from the header.
|
||||
*
|
||||
* @returns The packet number field.
|
||||
*
|
||||
*/
|
||||
uint32_t GetPacketNumber(void) const { return Encoding::BigEndian::HostSwap32(mPacketNumber); }
|
||||
|
||||
/**
|
||||
* This method sets the packet number field in the header.
|
||||
*
|
||||
* @param[in] aPacketNumber The packet number.
|
||||
*
|
||||
*/
|
||||
void SetPacketNumber(uint32_t aPacketNumber) { mPacketNumber = Encoding::BigEndian::HostSwap32(aPacketNumber); }
|
||||
|
||||
/**
|
||||
* This method gets the source MAC address field from the header.
|
||||
*
|
||||
* @returns The source MAC address field.
|
||||
*
|
||||
*/
|
||||
const Mac::ExtAddress &GetSource(void) const { return mSource; }
|
||||
|
||||
/**
|
||||
* This method sets the source MAC address filed in the header.
|
||||
*
|
||||
* @param[in] aSource A MAC extended address to set as source.
|
||||
*
|
||||
*/
|
||||
void SetSource(const Mac::ExtAddress &aSource) { mSource = aSource; }
|
||||
|
||||
/**
|
||||
* This method gets the destination MAC address field from the header.
|
||||
*
|
||||
* This method MUST be used with a unicast of ack type packet, otherwise its behavior is undefined.
|
||||
*
|
||||
* @returns The destination MAC address field.
|
||||
*
|
||||
*/
|
||||
const Mac::ExtAddress &GetDestination(void) const { return mDestination; }
|
||||
|
||||
/**
|
||||
* This method sets the destination MAC address field in the header.
|
||||
*
|
||||
* This method MUST be used with a unicast of ack type packet, otherwise its behavior is undefined.
|
||||
*
|
||||
* @param[in] aDest A MAC extended address to set as destination.
|
||||
*
|
||||
*/
|
||||
void SetDestination(const Mac::ExtAddress &aDest) { mDestination = aDest; }
|
||||
|
||||
/**
|
||||
* This static method gets the size (number of bytes) in header of given packet type.
|
||||
*
|
||||
* @param[in] aType The packet type.
|
||||
*
|
||||
* @returns The fixed header size (number of bytes) for @p aType packet.
|
||||
*
|
||||
*/
|
||||
static uint16_t GetSize(Type aType);
|
||||
|
||||
/**
|
||||
* This method returns a string representation of header.
|
||||
*
|
||||
* @returns An `InfoString` representation of header.
|
||||
*
|
||||
*/
|
||||
InfoString ToString(void) const;
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kTypeMask = (3 << 0), // Bits 0-1 specify packet `Type`
|
||||
kAckModeFlag = (1 << 2), // Bit 2 indicate "ack mode" (TREL ack requested or not).
|
||||
kVersionMask = (7 << 5), // Bits 5-7 specify the version.
|
||||
kVersion = (0 << 5), // Current TREL header version.
|
||||
};
|
||||
|
||||
// All header fields are big-endian.
|
||||
|
||||
uint8_t mControl;
|
||||
uint8_t mChannel;
|
||||
uint16_t mPanId;
|
||||
uint32_t mPacketNumber;
|
||||
Mac::ExtAddress mSource;
|
||||
Mac::ExtAddress mDestination; // Present in `kTypeAck` or `kTypeUnicast` packet types.
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
/**
|
||||
* This class represent a TREL radio link packet.
|
||||
*
|
||||
*/
|
||||
class Packet
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This method initializes the `Packet` with a given buffer and length.
|
||||
*
|
||||
* @param[in] aBuffer A pointer to a buffer containing the entire packet (header and payload).
|
||||
* @param[in] aLength Length (number of bytes) of the packet (including header and payload).
|
||||
*
|
||||
*/
|
||||
void Init(uint8_t *aBuffer, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* This method initializes the `Packet` with a specified header type and given a payload.
|
||||
*
|
||||
* The payload buffer @p aPayload should have space reserved before the start of payload for the packet header.
|
||||
* This method will initialize the header with the given type @p aType. Rest of header fields can be updated after
|
||||
* initializing the packet.
|
||||
*
|
||||
* @param[in] aType The packet type.
|
||||
* @param[in] aPayload A pointer to a buffer containing the packet payload. Buffer should have space reserved
|
||||
* for header before the payload.
|
||||
* @param[in] aPayloadLength The length (number of bytes) in the payload only (not including the header).
|
||||
*
|
||||
*/
|
||||
|
||||
void Init(Header::Type aType, uint8_t *aPayload, uint16_t aPayloadLength);
|
||||
|
||||
/**
|
||||
* This method gets a pointer to buffer containing the packet.
|
||||
*
|
||||
* @returns A pointer to buffer containing the packet.
|
||||
*
|
||||
*/
|
||||
uint8_t *GetBuffer(void) { return mBuffer; }
|
||||
|
||||
/**
|
||||
* This method gets a pointer to buffer containing the packet.
|
||||
*
|
||||
* @returns A pointer to buffer containing the packet.
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetBuffer(void) const { return mBuffer; }
|
||||
|
||||
/**
|
||||
* This method gets the length of packet.
|
||||
*
|
||||
* @returns The length (number of bytes) of packet (header and payload).
|
||||
*
|
||||
*/
|
||||
uint16_t GetLength(void) const { return mLength; }
|
||||
|
||||
/**
|
||||
* This method checks whether or not the packet header is valid.
|
||||
*
|
||||
* @retval TRUE The packet header is valid and well-formed.
|
||||
* @retval FALSE The packet header is not valid.
|
||||
*
|
||||
*/
|
||||
bool IsHeaderValid(void) const;
|
||||
|
||||
/**
|
||||
* This method gets the packet header.
|
||||
*
|
||||
* @returns A reference to the packet header as `Header`.
|
||||
*
|
||||
*/
|
||||
Header &GetHeader(void) { return *reinterpret_cast<Header *>(mBuffer); }
|
||||
|
||||
/**
|
||||
* This method gets the packet header.
|
||||
*
|
||||
* @returns A reference to the packet header as `Header`.
|
||||
*
|
||||
*/
|
||||
const Header &GetHeader(void) const { return *reinterpret_cast<const Header *>(mBuffer); }
|
||||
|
||||
/**
|
||||
* This method gets a pointer to start of packet payload.
|
||||
*
|
||||
* @returns A pointer to start of packet payload (after header).
|
||||
*
|
||||
*/
|
||||
uint8_t *GetPayload(void) { return mBuffer + GetHeader().GetLength(); }
|
||||
|
||||
/**
|
||||
* This method gets a pointer to start of packet payload.
|
||||
*
|
||||
* @returns A pointer to start of packet payload (after header).
|
||||
*
|
||||
*/
|
||||
const uint8_t *GetPayload(void) const { return mBuffer + GetHeader().GetLength(); }
|
||||
|
||||
/**
|
||||
* This method gets the payload length.
|
||||
*
|
||||
* @returns The packet payload length (number of bytes).
|
||||
*
|
||||
*/
|
||||
uint16_t GetPayloadLength(void) const { return mLength - GetHeader().GetLength(); }
|
||||
|
||||
private:
|
||||
uint8_t *mBuffer;
|
||||
uint16_t mLength;
|
||||
};
|
||||
|
||||
} // namespace Trel
|
||||
} // namespace ot
|
||||
|
||||
#endif // #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
#endif // TREL_PACKET_HPP_
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "common/timer.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
#include "net/ip6.hpp"
|
||||
#include "radio/trel_link.hpp"
|
||||
#include "thread/csl_tx_scheduler.hpp"
|
||||
#include "thread/indirect_sender.hpp"
|
||||
#include "thread/link_metrics.hpp"
|
||||
@@ -69,6 +70,10 @@ class Neighbor : public InstanceLocatorInit
|
||||
,
|
||||
public RadioSelector::NeighborInfo
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
,
|
||||
public Trel::NeighborInfo
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -610,4 +610,47 @@ void otPlatOtnsStatus(const char *aStatus)
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_OTNS_ENABLE
|
||||
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
void otPlatTrelUdp6Init(otInstance *aInstance, const otIp6Address *aUnicastAddress, uint16_t aUdpPort)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aUnicastAddress);
|
||||
OT_UNUSED_VARIABLE(aUdpPort);
|
||||
}
|
||||
|
||||
void otPlatTrelUdp6UpdateAddress(otInstance *aInstance, const otIp6Address *aUnicastAddress)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aUnicastAddress);
|
||||
}
|
||||
|
||||
void otPlatTrelUdp6SubscribeMulticastAddress(otInstance *aInstance, const otIp6Address *aMulticastAddress)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aMulticastAddress);
|
||||
}
|
||||
|
||||
otError otPlatTrelUdp6SendTo(otInstance * aInstance,
|
||||
const uint8_t * aBuffer,
|
||||
uint16_t aLength,
|
||||
const otIp6Address *aDestAddress)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aBuffer);
|
||||
OT_UNUSED_VARIABLE(aLength);
|
||||
OT_UNUSED_VARIABLE(aDestAddress);
|
||||
|
||||
return OT_ERROR_ABORT;
|
||||
}
|
||||
|
||||
otError otPlatTrelUdp6SetTestMode(otInstance *aInstance, bool aEnable)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
OT_UNUSED_VARIABLE(aEnable);
|
||||
return OT_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
|
||||
} // extern "C"
|
||||
|
||||
Reference in New Issue
Block a user