[time-sync] network-wide time synchronization service (#2618)

OpenThread network-wide time synchronization service is an experimental feature, not part of the standard Thread protocol.

Feature Overview:
 * All the nodes in the same Thread partition sync to the same Thread network-wide time;
 * Microsecond level time synchronization precision;
 * Flexible time accuracy and time sync period configuration;
 * APIs for application layer use case, support both CLI and NCP version.

The feature is wrapped by OPENTHREAD_CONFIG_ENABLE_TIME_SYNC, there's no change to current Thread 1.1
implementation if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC is not enabled.

If OPENTHREAD_CONFIG_ENABLE_TIME_SYNC is enabled, the node could:
 * Attach to a time sync enabled network, otherwise
 * Attach to a standard Thread 1.1 network, otherwise
 * Form a new time sync enabled network

In addition, if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED is also enable, the node could only:
 * Attach to a time sync enabled network, otherwise
 * Form a new time sync enabled network

Note:
Currently, the feature is only supported on nRF52840 and posix platforms. And the network time
is only synced among Routers and REEDs, the SEDs will be supported later as an optional feature.
This commit is contained in:
Shu Chen
2018-06-26 13:46:32 -05:00
committed by Jonathan Hui
parent 292349c4d3
commit e69019f962
44 changed files with 2283 additions and 97 deletions
+17 -1
View File
@@ -43,6 +43,7 @@
#include <openthread/platform/alarm-micro.h>
#include <openthread/platform/alarm-milli.h>
#include <openthread/platform/diag.h>
#include <openthread/platform/time.h>
#include "platform.h"
@@ -67,6 +68,8 @@
#define US_PER_OVERFLOW (512UL * US_PER_S) ///< Time that has passed between overflow events. On full RTC speed, it occurs every 512 s.
#define MS_PER_S 1000UL
#define XTAL_ACCURACY 40 // The crystal used on nRF52840PDK has ±20ppm accuracy.
// clang-format on
typedef enum { kMsTimer, kUsTimer, k802154Timer, kNumTimers } AlarmIndex;
@@ -88,7 +91,8 @@ typedef struct
static volatile uint32_t sOverflowCounter; ///< Counter of RTC overflowCounter, incremented by 2 on each OVERFLOW event.
static volatile uint8_t sMutex; ///< Mutex for write access to @ref sOverflowCounter.
static volatile uint64_t sTimeOffset = 0; ///< Time overflowCounter to keep track of current time (in millisecond).
static AlarmData sTimerData[kNumTimers]; ///< Data of the timers.
static AlarmData sTimerData[kNumTimers]; ///< Data of the timers.
static const AlarmChannelData sChannelData[kNumTimers] = //
{ //
[kMsTimer] =
@@ -563,3 +567,15 @@ void RTC_IRQ_HANDLER(void)
}
}
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
uint64_t otPlatTimeGet(void)
{
return nrf5AlarmGetCurrentTime();
}
uint16_t otPlatTimeGetXtalAccuracy(void)
{
return XTAL_ACCURACY;
}
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
@@ -158,15 +158,26 @@
*/
#define OPENTHREAD_CONFIG_HEAP_SIZE_NO_DTLS 2048
/**
* @def OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
*
* Define as 1 to enable the time synchronization service feature.
*
* @note If it's enabled, plaforms must support interrupt context and concurrent access AES.
*
*/
#define OPENTHREAD_CONFIG_ENABLE_TIME_SYNC 0
/**
* @def NRF_MBEDTLS_AES_ALT_INTERRUPT_CONTEXT
*
* Define as 1 to enable AES usage in interrupt context and AES-256, by introducing a software AES under platform layer.
*
* @note This feature must be enabled to support AES-256 used by Commissioner and Joiner.
* @note This feature must be enabled to support AES-256 used by Commissioner and Joiner, and AES usage in interrupt context
* used by time synchronization service.
*
*/
#if OPENTHREAD_ENABLE_COMMISSIONER || OPENTHREAD_ENABLE_JOINER
#if OPENTHREAD_ENABLE_COMMISSIONER || OPENTHREAD_ENABLE_JOINER || OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
#define NRF_MBEDTLS_AES_ALT_INTERRUPT_CONTEXT 1
#else
#define NRF_MBEDTLS_AES_ALT_INTERRUPT_CONTEXT 0
@@ -495,15 +495,17 @@
#endif
/**
* @def NRF_MBEDTLS_AES_ALT_INTERRUPT_CONTEXT
* @def NRF_802154_TX_STARTED_NOTIFY_ENABLED
*
* Define as 1 to enable AES usage in interrupt context.
* If notification of started transmission should be enabled in the driver.
*
* @note A software AES is enabled to support AES usage in interrupt context.
* @note This feature is enabled by default if OpenThread time synchronization service is enabled.
*
*/
#ifndef NRF_MBEDTLS_AES_ALT_INTERRUPT_CONTEXT
#define NRF_MBEDTLS_AES_ALT_INTERRUPT_CONTEXT 0
#ifndef NRF_802154_TX_STARTED_NOTIFY_ENABLED
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
#define NRF_802154_TX_STARTED_NOTIFY_ENABLED 1
#endif
#endif
#endif // PLATFORM_CONFIG_H_
+53 -3
View File
@@ -43,9 +43,11 @@
#include <common/code_utils.hpp>
#include <platform-config.h>
#include <openthread/platform/alarm-micro.h>
#include <openthread/platform/diag.h>
#include <openthread/platform/logging.h>
#include <openthread/platform/radio.h>
#include <openthread/platform/time.h>
#include "platform-nrf5.h"
#include "platform.h"
@@ -78,6 +80,12 @@ static otRadioFrame sReceivedFrames[NRF_802154_RX_BUFFERS];
static otRadioFrame sTransmitFrame;
static uint8_t sTransmitPsdu[OT_RADIO_FRAME_MAX_SIZE + 1];
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
static otRadioIeInfo sTransmitIeInfo;
static otRadioIeInfo sReceivedIeInfos[NRF_802154_RX_BUFFERS];
static otInstance * sInstance = NULL;
#endif
static otRadioFrame sAckFrame;
static int8_t sDefaultTxPower;
@@ -103,6 +111,9 @@ static void dataInit(void)
sDisabled = true;
sTransmitFrame.mPsdu = sTransmitPsdu + 1;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
sTransmitFrame.mIeInfo = &sTransmitIeInfo;
#endif
sReceiveError = OT_ERROR_NONE;
@@ -322,7 +333,9 @@ otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
{
(void)aInstance;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
sInstance = aInstance;
#endif
otError result = OT_ERROR_NONE;
@@ -661,7 +674,11 @@ void nrf5RadioProcess(otInstance *aInstance)
}
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
void nrf_802154_received_timestamp_raw(uint8_t *p_data, int8_t power, uint8_t lqi, uint32_t time)
#else
void nrf_802154_received_raw(uint8_t *p_data, int8_t power, uint8_t lqi)
#endif
{
otRadioFrame *receivedFrame = NULL;
@@ -670,14 +687,17 @@ void nrf_802154_received_raw(uint8_t *p_data, int8_t power, uint8_t lqi)
if (sReceivedFrames[i].mPsdu == NULL)
{
receivedFrame = &sReceivedFrames[i];
memset(receivedFrame, 0, sizeof(*receivedFrame));
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
receivedFrame->mIeInfo = &sReceivedIeInfos[i];
#endif
break;
}
}
assert(receivedFrame != NULL);
memset(receivedFrame, 0, sizeof(*receivedFrame));
receivedFrame->mPsdu = &p_data[1];
receivedFrame->mLength = p_data[0];
receivedFrame->mInfo.mRxInfo.mRssi = power;
@@ -688,6 +708,12 @@ void nrf_802154_received_raw(uint8_t *p_data, int8_t power, uint8_t lqi)
receivedFrame->mInfo.mRxInfo.mMsec = timestamp / US_PER_MS;
receivedFrame->mInfo.mRxInfo.mUsec = timestamp - receivedFrame->mInfo.mRxInfo.mMsec * US_PER_MS;
#endif
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
// Get the timestamp when the SFD was received.
uint32_t offset =
(int32_t)otPlatAlarmMicroGetNow() - (int32_t)nrf_802154_first_symbol_timestamp_get(time, p_data[0]);
receivedFrame->mIeInfo->mTimestamp = otPlatTimeGet() - offset;
#endif
PlatformEventSignalPending();
}
@@ -775,3 +801,27 @@ int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
(void)aInstance;
return NRF52840_RECEIVE_SENSITIVITY;
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
void nrf_802154_tx_started(const uint8_t *aFrame)
{
assert(aFrame == sTransmitPsdu);
if (sTransmitFrame.mIeInfo->mTimeIeOffset != 0)
{
uint8_t *timeIe = sTransmitFrame.mPsdu + sTransmitFrame.mIeInfo->mTimeIeOffset;
uint64_t time = otPlatTimeGet() + sTransmitFrame.mIeInfo->mNetworkTimeOffset;
*timeIe = sTransmitFrame.mIeInfo->mTimeSyncSeq;
*(++timeIe) = (uint8_t)(time & 0xff);
for (uint8_t i = 1; i < sizeof(uint64_t); i++)
{
time = time >> 8;
*(++timeIe) = (uint8_t)(time & 0xff);
}
otPlatRadioFrameUpdated(sInstance, &sTransmitFrame);
}
}
#endif
+20 -9
View File
@@ -60,15 +60,19 @@ void platformAlarmInit(uint32_t aSpeedUpFactor)
gettimeofday(&sStart, NULL);
}
uint32_t otPlatAlarmMilliGetNow(void)
uint64_t platformGetNow(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
timersub(&tv, &sStart, &tv);
return (uint32_t)(((uint64_t)tv.tv_sec * sSpeedUpFactor * MS_PER_S) +
((uint64_t)tv.tv_usec * sSpeedUpFactor / US_PER_MS));
return (uint64_t)tv.tv_sec * sSpeedUpFactor * US_PER_S + (uint64_t)tv.tv_usec * sSpeedUpFactor;
}
uint32_t otPlatAlarmMilliGetNow(void)
{
return (uint32_t)(platformGetNow() / US_PER_MS);
}
void otPlatAlarmMilliStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt)
@@ -86,12 +90,7 @@ void otPlatAlarmMilliStop(otInstance *aInstance)
uint32_t otPlatAlarmMicroGetNow(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
timersub(&tv, &sStart, &tv);
return (uint32_t)(tv.tv_sec * US_PER_S + tv.tv_usec) * sSpeedUpFactor;
return (uint32_t)platformGetNow();
}
void otPlatAlarmMicroStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt)
@@ -196,4 +195,16 @@ void platformAlarmProcess(otInstance *aInstance)
#endif // OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_TIMER
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
uint64_t otPlatTimeGet(void)
{
return platformGetNow();
}
uint16_t otPlatTimeGetXtalAccuracy(void)
{
return 0;
}
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
#endif // OPENTHREAD_POSIX_VIRTUAL_TIME == 0
+38
View File
@@ -30,10 +30,12 @@
#if OPENTHREAD_POSIX_VIRTUAL_TIME == 0
#include <openthread/platform/alarm-micro.h>
#include <openthread/platform/alarm-milli.h>
#include <openthread/platform/diag.h>
#include <openthread/platform/radio.h>
#include <openthread/platform/random.h>
#include <openthread/platform/time.h>
#include "utils/code_utils.h"
@@ -109,6 +111,11 @@ static otRadioFrame sReceiveFrame;
static otRadioFrame sTransmitFrame;
static otRadioFrame sAckFrame;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
static otRadioIeInfo sTransmitIeInfo;
static otRadioIeInfo sReceivedIeInfo;
#endif
static uint8_t sExtendedAddress[OT_EXT_ADDRESS_SIZE];
static uint16_t sShortAddress;
static uint16_t sPanid;
@@ -423,6 +430,14 @@ void platformRadioInit(void)
sReceiveFrame.mPsdu = sReceiveMessage.mPsdu;
sTransmitFrame.mPsdu = sTransmitMessage.mPsdu;
sAckFrame.mPsdu = sAckMessage.mPsdu;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
sTransmitFrame.mIeInfo = &sTransmitIeInfo;
sReceiveFrame.mIeInfo = &sReceivedIeInfo;
#else
sTransmitFrame.mIeInfo = NULL;
sReceiveFrame.mIeInfo = NULL;
#endif
}
void platformRadioDeinit(void)
@@ -560,6 +575,10 @@ void radioReceive(otInstance *aInstance)
sReceiveFrame.mInfo.mRxInfo.mUsec = 0; // Don't support microsecond timer for now.
#endif
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
sReceiveFrame.mIeInfo->mTimestamp = otPlatTimeGet();
#endif
sReceiveFrame.mLength = (uint8_t)(rval - 1);
if (sAckWait && sTransmitFrame.mChannel == sReceiveMessage.mChannel && isFrameTypeAck(sReceiveFrame.mPsdu) &&
@@ -579,6 +598,25 @@ void radioReceive(otInstance *aInstance)
void radioSendMessage(otInstance *aInstance)
{
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
if (sTransmitFrame.mIeInfo->mTimeIeOffset != 0)
{
uint8_t *timeIe = sTransmitFrame.mPsdu + sTransmitFrame.mIeInfo->mTimeIeOffset;
uint64_t time = otPlatTimeGet() + sTransmitFrame.mIeInfo->mNetworkTimeOffset;
*timeIe = sTransmitFrame.mIeInfo->mTimeSyncSeq;
*(++timeIe) = (uint8_t)(time & 0xff);
for (uint8_t i = 0; i < sizeof(uint64_t); i++)
{
time = time >> 8;
*(++timeIe) = (uint8_t)(time & 0xff);
}
otPlatRadioFrameUpdated(aInstance, &sTransmitFrame);
}
#endif
sTransmitMessage.mChannel = sTransmitFrame.mChannel;
otPlatRadioTxStarted(aInstance, &sTransmitFrame);
+1
View File
@@ -72,6 +72,7 @@ openthread_headers = \
message.h \
ncp.h \
netdata.h \
network_time.h \
openthread.h \
server.h \
tasklet.h \
+138
View File
@@ -0,0 +1,138 @@
/*
* Copyright (c) 2018, 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 defines the OpenThread Network Time Synchronization Service API.
*/
#ifndef OPENTHREAD_NETWORK_TIME_H_
#define OPENTHREAD_NETWORK_TIME_H_
#include <openthread/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup api-network-time
*
* @brief
* This module includes functions that control network time synchronization service.
*
* @{
*
*/
/**
* This enum represents OpenThread time synchronization status.
*
*/
typedef enum otNetworkTimeStatus {
OT_NETWORK_TIME_UNSYNCHRONIZED = -1, ///< The device hasn't attached to a network.
OT_NETWORK_TIME_RESYNC_NEEDED = 0, ///< The device hasnt received time sync for more than two periods time.
OT_NETWORK_TIME_SYNCHRONIZED = 1, ///< The device network time is synchronized.
} otNetworkTimeStatus;
/**
* zero is considered as invalid time synchronization sequence.
*
*/
#define OT_TIME_SYNC_INVALID_SEQ 0
/**
* Get the Thread network time.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[inout] aNetworkTime The Thread network time in microseconds.
*
* @returns The time synchronization status.
*
*/
otNetworkTimeStatus otNetworkTimeGet(otInstance *aInstance, uint64_t &aNetworkTime);
/**
* Set the time synchronization period.
*
* This function can only be called while Thread protocols are disabled.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aTimeSyncPeriod The time synchronization period, in seconds.
*
* @retval OT_ERROR_NONE Successfully set the time sync period.
* @retval OT_ERROR_INVALID_STATE Thread protocols are enabled.
*
*/
otError otNetworkTimeSetSyncPeriod(otInstance *aInstance, uint16_t aTimeSyncPeriod);
/**
* Get the time synchronization period.
*
* @param[in] aInstance The OpenThread instance structure.
*
* @returns The time synchronization period.
*
*/
uint16_t otNetworkTimeGetSyncPeriod(otInstance *aInstance);
/**
* Set the time synchronization XTAL accuracy threshold for Router-Capable device.
*
* This function can only be called while Thread protocols are disabled.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aXTALThreshold The XTAL accuracy threshold for Router, in PPM.
*
* @retval OT_ERROR_NONE Successfully set the time sync period.
* @retval OT_ERROR_INVALID_STATE Thread protocols are enabled.
*
*/
otError otNetworkTimeSetXtalThreshold(otInstance *aInstance, uint16_t aXTALThreshold);
/**
* Get the time synchronization XTAL accuracy threshold for Router.
*
* @param[in] aInstance The OpenThread instance structure.
*
* @returns The XTAL accuracy threshold for Router, in PPM.
*
*/
uint16_t otNetworkTimeGetXtalThreshold(otInstance *aInstance);
/**
* @}
*
*/
#ifdef __cplusplus
} // extern "C"
#endif
#endif // OPENTHREAD_NETWORK_TIME_H_
+1
View File
@@ -38,6 +38,7 @@ ot_platform_headers = \
logging.h \
radio.h \
random.h \
time.h \
uart.h \
spi-slave.h \
settings.h \
+29 -4
View File
@@ -92,15 +92,27 @@ typedef enum otRadioCaps {
OT_RADIO_CAPS_CSMA_BACKOFF = 8, ///< Radio supports CSMA backoff for frame transmission (but no retry).
} otRadioCaps;
/**
* This structure represents the IEEE 802.15.4 Header IE (Information Element) related information of a radio frame.
*/
typedef struct otRadioIeInfo
{
uint8_t mTimeIeOffset; ///< The Time IE offset from the start of PSDU.
uint8_t mTimeSyncSeq; ///< The Time sync sequence.
uint64_t mTimestamp; ///< The time in microseconds when the SFD was received.
int64_t mNetworkTimeOffset; ///< The time offset to the Thread network time.
} otRadioIeInfo;
/**
* This structure represents an IEEE 802.15.4 radio frame.
*/
typedef struct otRadioFrame
{
uint8_t *mPsdu; ///< The PSDU.
uint8_t mLength; ///< Length of the PSDU.
uint8_t mChannel; ///< Channel used to transmit/receive the frame.
bool mDidTx : 1; ///< Set to true if this frame sent from the radio. Ignored by radio driver.
uint8_t * mPsdu; ///< The PSDU.
uint8_t mLength; ///< Length of the PSDU.
uint8_t mChannel; ///< Channel used to transmit/receive the frame.
bool mDidTx : 1; ///< Set to true if this frame sent from the radio. Ignored by radio driver.
otRadioIeInfo *mIeInfo; ///< The pointer to the Header IE(s) related information.
/**
* The union of transmit and receive information for a radio frame.
@@ -564,6 +576,19 @@ extern void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanM
*/
int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance);
/**
* The radio driver calls this method to notify OpenThread to process transmit security for the frame,
* this happens when the frame includes Header IE(s) that were updated before transmission.
*
* @note This function will be called from interrupt context, it should only read/write data passed in
* via @p aFrame, but should not read/write any state within OpenThread.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aFrame The radio frame which neeeds to process transmit security.
*
*/
extern void otPlatRadioFrameUpdated(otInstance *aInstance, otRadioFrame *aFrame);
/**
* @}
*
+81
View File
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2018, 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 the time service.
*/
#ifndef TIME_H_
#define TIME_H_
#include <stdint.h>
#include <openthread/types.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup plat-time
*
* @brief
* This module includes the platform abstraction for the time service.
*
* @{
*
*/
/**
* Get the current time (64bits width).
*
* @returns The current time in microseconds.
*
*/
uint64_t otPlatTimeGet(void);
/**
* Get the device's XTAL accuracy.
*
* @returns The device's XTAL accuracy, in ppm.
*
*/
uint16_t otPlatTimeGetXtalAccuracy(void);
/**
* @}
*
*/
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TIME_H_
+4
View File
@@ -1160,6 +1160,10 @@ typedef struct otThreadLinkInfo
int8_t mRss; ///< Received Signal Strength in dBm.
uint8_t mLqi; ///< Link Quality Indicator for a received message.
bool mLinkSecurity; ///< Indicates whether or not link security is enabled.
// Applicable/Required only when time sync feature (`OPENTHREAD_CONFIG_ENABLE_TIME_SYNC`) is enabled.
uint8_t mTimeSyncSeq; ///< The time sync sequence.
int64_t mNetworkTimeOffset; ///< The time offset to the Thread network time, in microseconds.
} otThreadLinkInfo;
#ifdef OTDLL
+26
View File
@@ -47,6 +47,7 @@ OpenThread test scripts use the CLI to execute test cases.
* [networkdiagnostic](#networkdiagnostic-get-addr-type-)
* [networkidtimeout](#networkidtimeout)
* [networkname](#networkname)
* [networktime](#networktime)
* [panid](#panid)
* [parent](#parent)
* [parentpriority](#parentpriority)
@@ -605,6 +606,31 @@ Set network name.
Done
```
### networktime
Get the Thread network time and the time sync parameters.
```bash
> networktime
Network Time: 21084154us (synchronized)
Time Sync Period: 100s
XTAL Threshold: 300ppm
Done
```
### networktime \<timesyncperiod\> \<xtalthreshold\>
Set time sync parameters
* timesyncperiod: The time synchronization period, in seconds.
* xtalthreshold: The XTAL accuracy threshold for a device to become Router-Capable device, in PPM.
```bash
> networktime 100 300
Done
```
### dataset panid \<panid\>
Set panid.
+60
View File
@@ -45,6 +45,9 @@
#include <openthread/icmp6.h>
#include <openthread/joiner.h>
#include <openthread/link.h>
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
#include <openthread/network_time.h>
#endif
#include <openthread/openthread.h>
#if OPENTHREAD_FTD
@@ -177,6 +180,9 @@ const struct Command Interpreter::sCommands[] = {
{"networkidtimeout", &Interpreter::ProcessNetworkIdTimeout},
#endif
{"networkname", &Interpreter::ProcessNetworkName},
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
{"networktime", &Interpreter::ProcessNetworkTime},
#endif
{"panid", &Interpreter::ProcessPanId},
{"parent", &Interpreter::ProcessParent},
#if OPENTHREAD_FTD
@@ -1579,6 +1585,60 @@ exit:
AppendResult(error);
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
void Interpreter::ProcessNetworkTime(int argc, char *argv[])
{
otError error = OT_ERROR_NONE;
long value;
if (argc == 0)
{
uint64_t time;
otNetworkTimeStatus networkTimeStatus;
networkTimeStatus = otNetworkTimeGet(mInstance, time);
mServer->OutputFormat("Network Time: %dus", time);
switch (networkTimeStatus)
{
case OT_NETWORK_TIME_UNSYNCHRONIZED:
mServer->OutputFormat(" (unsynchronized)\r\n");
break;
case OT_NETWORK_TIME_RESYNC_NEEDED:
mServer->OutputFormat(" (resync needed)\r\n");
break;
case OT_NETWORK_TIME_SYNCHRONIZED:
mServer->OutputFormat(" (synchronized)\r\n");
break;
default:
break;
}
mServer->OutputFormat("Time Sync Period: %ds\r\n", otNetworkTimeGetSyncPeriod(mInstance));
mServer->OutputFormat("XTAL Threshold: %dppm\r\n", otNetworkTimeGetXtalThreshold(mInstance));
}
else if (argc == 2)
{
SuccessOrExit(error = ParseLong(argv[0], value));
SuccessOrExit(error = otNetworkTimeSetSyncPeriod(mInstance, static_cast<uint16_t>(value)));
SuccessOrExit(error = ParseLong(argv[1], value));
SuccessOrExit(error = otNetworkTimeSetXtalThreshold(mInstance, static_cast<uint16_t>(value)));
}
else
{
ExitNow(error = OT_ERROR_INVALID_ARGS);
}
exit:
AppendResult(error);
}
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
void Interpreter::ProcessPanId(int argc, char *argv[])
{
otError error = OT_ERROR_NONE;
+3
View File
@@ -266,6 +266,9 @@ private:
void ProcessNetworkIdTimeout(int argc, char *argv[]);
#endif
void ProcessNetworkName(int argc, char *argv[]);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
void ProcessNetworkTime(int argc, char *argv[]);
#endif
void ProcessPanId(int argc, char *argv[]);
void ProcessParent(int argc, char *argv[]);
#if OPENTHREAD_FTD
+3
View File
@@ -114,6 +114,7 @@ SOURCES_COMMON = \
api/link_raw_api.cpp \
api/message_api.cpp \
api/netdata_api.cpp \
api/network_time_api.cpp \
api/server_api.cpp \
api/tasklet_api.cpp \
api/thread_api.cpp \
@@ -195,6 +196,7 @@ SOURCES_COMMON = \
thread/src_match_controller.cpp \
thread/thread_netif.cpp \
thread/tmf_proxy.cpp \
thread/time_sync_service.cpp \
thread/topology.cpp \
utils/channel_manager.cpp \
utils/channel_monitor.cpp \
@@ -326,6 +328,7 @@ HEADERS_COMMON = \
thread/thread_tlvs.hpp \
thread/thread_uri_paths.hpp \
thread/tmf_proxy.hpp \
thread/time_sync_service.hpp \
thread/topology.hpp \
utils/channel_manager.hpp \
utils/channel_monitor.hpp \
+9
View File
@@ -729,6 +729,15 @@ uint16_t otLinkGetShortAddress(otInstance *aInstance)
return static_cast<Instance *>(aInstance)->GetLinkRaw().GetShortAddress();
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
void otPlatRadioFrameUpdated(otInstance *aInstance, otRadioFrame *aFrame)
{
// Note: For now this functionality is not supported in Radio Only mode.
(void)aInstance;
(void)aFrame;
}
#endif
#endif // OPENTHREAD_RADIO
#endif // OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
+92
View File
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2018, 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 the OpenThread Network Time Synchronization Service API.
*/
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
#include "openthread/network_time.h"
#include "common/instance.hpp"
using namespace ot;
otNetworkTimeStatus otNetworkTimeGet(otInstance *aInstance, uint64_t &aNetworkTime)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetThreadNetif().GetTimeSync().GetTime(aNetworkTime);
}
otError otNetworkTimeSetSyncPeriod(otInstance *aInstance, uint16_t aTimeSyncPeriod)
{
otError error = OT_ERROR_NONE;
Instance &instance = *static_cast<Instance *>(aInstance);
VerifyOrExit(instance.GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
error = OT_ERROR_INVALID_STATE);
instance.GetThreadNetif().GetTimeSync().SetTimeSyncPeriod(aTimeSyncPeriod);
exit:
return error;
}
uint16_t otNetworkTimeGetSyncPeriod(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetThreadNetif().GetTimeSync().GetTimeSyncPeriod();
}
otError otNetworkTimeSetXtalThreshold(otInstance *aInstance, uint16_t aXtalThreshold)
{
otError error = OT_ERROR_NONE;
Instance &instance = *static_cast<Instance *>(aInstance);
VerifyOrExit(instance.GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DISABLED,
error = OT_ERROR_INVALID_STATE);
instance.GetThreadNetif().GetTimeSync().SetXtalThreshold(aXtalThreshold);
exit:
return error;
}
uint16_t otNetworkTimeGetXtalThreshold(otInstance *aInstance)
{
Instance &instance = *static_cast<Instance *>(aInstance);
return instance.GetThreadNetif().GetTimeSync().GetXtalThreshold();
}
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
+3
View File
@@ -668,6 +668,9 @@ Message *Message::Clone(uint16_t aLength) const
messageCopy->SetSubType(GetSubType());
messageCopy->SetPriority(GetPriority());
messageCopy->SetLinkSecurityEnabled(IsLinkSecurityEnabled());
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
messageCopy->SetTimeSync(IsTimeSync());
#endif
exit:
+59
View File
@@ -114,6 +114,11 @@ struct MessageInfo
uint8_t mPriority : 2; ///< Identifies the message priority level (lower value is higher priority).
bool mInPriorityQ : 1; ///< Indicates whether the message is queued in normal or priority queue.
bool mTxSuccess : 1; ///< Indicates whether the direct tx of the message was successful.
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
bool mTimeSync : 1; ///< Indicates whether the message is also used for time sync purpose.
uint8_t mTimeSyncSeq; ///< The time sync sequence.
int64_t mNetworkTimeOffset; ///< The time offset to the Thread network time, in microseconds.
#endif
};
/**
@@ -710,6 +715,60 @@ public:
return (!mBuffer.mHead.mInfo.mInPriorityQ) ? mBuffer.mHead.mInfo.mQueue.mMessage : NULL;
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
/**
* This method indicates whether or not the message is also used for time sync purpose.
*
* @retval TRUE If the message is also used for time sync purpose.
* @retval FALSE If the message is not used for time sync purpose.
*
*/
bool IsTimeSync(void) const { return mBuffer.mHead.mInfo.mTimeSync; }
/**
* This method sets whether or not the message is also used for time sync purpose.
*
* @param[in] aEnabled TRUE if the message is also used for time sync purpose, FALSE otherwise.
*
*/
void SetTimeSync(bool aEnabled) { mBuffer.mHead.mInfo.mTimeSync = aEnabled; }
/**
* This method sets the offset to network time.
*
* @param[in] aNetworkTimeOffset The offset to network time.
*
*/
void SetNetworkTimeOffset(int64_t aNetworkTimeOffset)
{
mBuffer.mHead.mInfo.mNetworkTimeOffset = aNetworkTimeOffset;
}
/**
* This method gets the offset to network time.
*
* @returns The offset to network time.
*
*/
int64_t GetNetworkTimeOffset(void) const { return mBuffer.mHead.mInfo.mNetworkTimeOffset; }
/**
* This method sets the time sync sequence.
*
* @param[in] aTimeSyncSeq The time sync sequence.
*
*/
void SetTimeSyncSeq(uint8_t aTimeSyncSeq) { mBuffer.mHead.mInfo.mTimeSyncSeq = aTimeSyncSeq; }
/**
* This method gets the time sync sequence.
*
* @returns The time sync sequence.
*
*/
uint8_t GetTimeSyncSeq(void) const { return mBuffer.mHead.mInfo.mTimeSyncSeq; }
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
private:
/**
* This method returns a pointer to the message pool to which this message belongs
+81 -1
View File
@@ -1104,7 +1104,11 @@ void Mac::BeginTransmit(void)
{
otError error = OT_ERROR_NONE;
bool applyTransmitSecurity = true;
bool processTransmitAesCcm = true;
Frame & sendFrame(*GetOperationFrame());
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
uint8_t timeIeOffset = 0;
#endif
VerifyOrExit(mEnabled, error = OT_ERROR_ABORT);
@@ -1161,10 +1165,24 @@ void Mac::BeginTransmit(void)
break;
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
timeIeOffset = GetTimeIeOffset(sendFrame);
sendFrame.SetTimeIeOffset(timeIeOffset);
if (timeIeOffset != 0)
{
// Transmit security will be processed after time IE content is updated.
processTransmitAesCcm = false;
sendFrame.SetTimeSyncSeq(GetNetif().GetTimeSync().GetTimeSyncSeq());
sendFrame.SetNetworkTimeOffset(GetNetif().GetTimeSync().GetNetworkTimeOffset());
}
#endif
if (applyTransmitSecurity)
{
// Security Processing
ProcessTransmitSecurity(sendFrame, true);
ProcessTransmitSecurity(sendFrame, processTransmitAesCcm);
}
}
@@ -1923,6 +1941,15 @@ void Mac::HandleReceivedFrame(Frame *aFrame, otError aError)
netif.GetMeshForwarder().GetDataPollManager().CheckFramePending(*aFrame);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
if (aFrame->GetVersion() == Frame::kFcfFrameVersion2015)
{
ProcessTimeIe(*aFrame);
}
#endif
if (neighbor != NULL)
{
#if OPENTHREAD_ENABLE_MAC_FILTER
@@ -2287,5 +2314,58 @@ void Mac::LogFrameTxFailure(const Frame &, otError) const
#endif // #if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_MAC == 1)
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
void Mac::ProcessTimeIe(Frame &aFrame)
{
TimeIe *timeIe = reinterpret_cast<TimeIe *>(aFrame.GetTimeIe());
VerifyOrExit(timeIe != NULL);
aFrame.SetNetworkTimeOffset(static_cast<int64_t>(timeIe->GetTime()) - static_cast<int64_t>(aFrame.GetTimestamp()));
aFrame.SetTimeSyncSeq(timeIe->GetSequence());
exit:
return;
}
uint8_t Mac::GetTimeIeOffset(Frame &aFrame)
{
uint8_t offset = 0;
uint8_t *base = aFrame.GetPsdu();
uint8_t *cur = NULL;
cur = aFrame.GetTimeIe();
VerifyOrExit(cur != NULL);
cur += sizeof(VendorIeHeader);
offset = cur - base;
exit:
return offset;
}
/**
* This function will be called from interrupt context, it should only read/write data passed in
* via @p aFrame, but should not read/write any state within OpenThread.
*/
extern "C" void otPlatRadioFrameUpdated(otInstance *aInstance, otRadioFrame *aFrame)
{
Instance * instance = static_cast<Instance *>(aInstance);
Frame frame = *static_cast<Frame *>(aFrame);
const ExtAddress *extAddress = NULL;
VerifyOrExit(instance->IsInitialized());
if (frame.GetSecurityEnabled() == true)
{
extAddress = &instance->GetThreadNetif().GetMac().GetExtAddress();
instance->GetThreadNetif().GetMac().ProcessTransmitAesCcm(frame, extAddress);
}
exit:
return;
}
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
} // namespace Mac
} // namespace ot
+6
View File
@@ -37,6 +37,7 @@
#include "openthread-core-config.h"
#include <openthread/platform/radio.h>
#include <openthread/platform/time.h>
#include "common/locator.hpp"
#include "common/tasklet.hpp"
@@ -986,6 +987,11 @@ private:
void LogFrameTxFailure(const Frame &aFrame, otError aError) const;
void LogBeacon(const char *aActionText, const BeaconPayload &aBeaconPayload) const;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
void ProcessTimeIe(Frame &aFrame);
uint8_t GetTimeIeOffset(Frame &aFrame);
#endif
static const char *OperationToString(Operation aOperation);
Operation mOperation;
+187 -39
View File
@@ -111,27 +111,23 @@ otError Frame::InitMacHeader(uint16_t aFcf, uint8_t aSecurityControl)
assert(false);
}
// Source PAN + Address
// Source PAN
if (IsSrcPanIdPresent(aFcf))
{
length += sizeof(PanId);
}
// Source Address
switch (aFcf & kFcfSrcAddrMask)
{
case kFcfSrcAddrNone:
break;
case kFcfSrcAddrShort:
if ((aFcf & kFcfPanidCompression) == 0)
{
length += sizeof(PanId);
}
length += sizeof(ShortAddress);
break;
case kFcfSrcAddrExt:
if ((aFcf & kFcfPanidCompression) == 0)
{
length += sizeof(PanId);
}
length += sizeof(ExtAddress);
break;
@@ -363,6 +359,30 @@ exit:
return index;
}
bool Frame::IsSrcPanIdPresent(uint16_t aFcf) const
{
bool srcPanIdPresent = false;
if ((aFcf & kFcfSrcAddrMask) != kFcfSrcAddrNone && (aFcf & kFcfPanidCompression) == 0)
{
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
// Handle a special case in IEEE 802.15.4-2015, when Pan ID Compression is 0, but Src Pan ID is not present:
// Dest Address: Extended
// Source Address: Extended
// Dest Pan ID: Present
// Src Pan ID: Not Present
// Pan ID Compression: 0
if ((aFcf & kFcfFrameVersionMask) != kFcfFrameVersion2015 || (aFcf & kFcfDstAddrMask) != kFcfDstAddrExt ||
(aFcf & kFcfSrcAddrMask) != kFcfSrcAddrExt)
#endif
{
srcPanIdPresent = true;
}
}
return srcPanIdPresent;
}
otError Frame::GetSrcPanId(PanId &aPanId) const
{
otError error = OT_ERROR_NONE;
@@ -408,7 +428,7 @@ uint8_t Frame::FindSrcAddrIndex(void) const
}
// Source PAN
if ((fcf & kFcfPanidCompression) == 0)
if (IsSrcPanIdPresent(fcf))
{
index += sizeof(PanId);
}
@@ -515,24 +535,20 @@ uint8_t Frame::FindSecurityHeaderIndex(void) const
break;
}
// Source PAN + Address
// Source PAN
if (IsSrcPanIdPresent(fcf))
{
index += sizeof(PanId);
}
// Source Address
switch (fcf & kFcfSrcAddrMask)
{
case kFcfSrcAddrShort:
if ((fcf & kFcfPanidCompression) == 0)
{
index += sizeof(PanId);
}
index += sizeof(ShortAddress);
break;
case kFcfSrcAddrExt:
if ((fcf & kFcfPanidCompression) == 0)
{
index += sizeof(PanId);
}
index += sizeof(ExtAddress);
break;
}
@@ -784,7 +800,7 @@ otError Frame::SetPayloadLength(uint8_t aLength)
return OT_ERROR_NONE;
}
uint8_t Frame::FindPayloadIndex(void) const
uint8_t Frame::SkipSecurityHeaderIndex(void) const
{
uint8_t index = 0;
uint16_t fcf;
@@ -816,27 +832,23 @@ uint8_t Frame::FindPayloadIndex(void) const
ExitNow(index = kInvalidIndex);
}
// Source PAN + Address
// Source PAN
if (IsSrcPanIdPresent(fcf))
{
index += sizeof(PanId);
}
// Source Address
switch (fcf & kFcfSrcAddrMask)
{
case kFcfSrcAddrNone:
break;
case kFcfSrcAddrShort:
if ((fcf & kFcfPanidCompression) == 0)
{
index += sizeof(PanId);
}
index += sizeof(ShortAddress);
break;
case kFcfSrcAddrExt:
if ((fcf & kFcfPanidCompression) == 0)
{
index += sizeof(PanId);
}
index += sizeof(ExtAddress);
break;
@@ -873,6 +885,49 @@ uint8_t Frame::FindPayloadIndex(void) const
}
}
exit:
return index;
}
uint8_t Frame::FindPayloadIndex(void) const
{
uint16_t fcf = GetFrameControlField();
uint8_t index = SkipSecurityHeaderIndex();
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
uint8_t *cur = NULL;
uint8_t *footer = GetFooter();
#endif
VerifyOrExit(index != kInvalidIndex);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
cur = GetPsdu() + index;
if (IsIePresent())
{
while (cur + sizeof(HeaderIe) <= footer)
{
HeaderIe *ie = reinterpret_cast<HeaderIe *>(cur);
uint8_t len = static_cast<uint8_t>(ie->GetLength());
cur += sizeof(HeaderIe);
index += sizeof(HeaderIe);
VerifyOrExit(cur + len <= footer, index = kInvalidIndex);
cur += len;
index += len;
if (ie->GetId() == kHeaderIeTermination2)
{
break;
}
}
// Assume no Payload IE in current implementation
}
#endif
// Command ID
if ((fcf & kFcfFrameTypeMask) == kFcfFrameMacCmd)
{
@@ -894,10 +949,10 @@ exit:
return payload;
}
const uint8_t *Frame::GetPayload(void) const
uint8_t *Frame::GetPayload(void) const
{
uint8_t index = FindPayloadIndex();
const uint8_t *payload = GetPsdu() + index;
uint8_t index = FindPayloadIndex();
uint8_t *payload = GetPsdu() + index;
VerifyOrExit(index != kInvalidIndex, payload = NULL);
@@ -910,11 +965,104 @@ uint8_t *Frame::GetFooter(void)
return GetPsdu() + GetPsduLength() - GetFooterLength();
}
const uint8_t *Frame::GetFooter(void) const
uint8_t *Frame::GetFooter(void) const
{
return GetPsdu() + GetPsduLength() - GetFooterLength();
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
uint8_t Frame::FindHeaderIeIndex(void) const
{
uint8_t index;
VerifyOrExit(IsIePresent(), index = kInvalidIndex);
index = SkipSecurityHeaderIndex();
exit:
return index;
}
otError Frame::AppendHeaderIe(HeaderIe *aIeList, uint8_t aIeCount)
{
otError error = OT_ERROR_NONE;
uint8_t index = FindHeaderIeIndex();
uint8_t *cur;
uint8_t *base;
VerifyOrExit(index != kInvalidIndex, error = OT_ERROR_FAILED);
cur = GetPsdu() + index;
base = cur;
for (uint8_t i = 0; i < aIeCount; i++)
{
memcpy(cur, &aIeList[i], sizeof(HeaderIe));
cur += sizeof(HeaderIe);
cur += aIeList[i].GetLength();
}
SetPsduLength(GetPsduLength() + cur - base);
exit:
return error;
}
uint8_t *Frame::GetHeaderIe(uint8_t aIeId) const
{
uint8_t index = FindHeaderIeIndex();
uint8_t *cur = NULL;
uint8_t *payload = GetPayload();
VerifyOrExit(index != kInvalidIndex);
cur = GetPsdu() + index;
while (cur + sizeof(HeaderIe) <= payload)
{
HeaderIe *ie = reinterpret_cast<HeaderIe *>(cur);
uint8_t len = static_cast<uint8_t>(ie->GetLength());
if (ie->GetId() == aIeId)
{
break;
}
cur += sizeof(HeaderIe);
VerifyOrExit(cur + len <= payload, cur = NULL);
cur += len;
}
if (cur == payload)
{
cur = NULL;
}
exit:
return cur;
}
uint8_t *Frame::GetTimeIe(void) const
{
TimeIe * timeIe = NULL;
uint8_t *cur = NULL;
uint8_t oui[kVendorOuiSize] = {kVendorOuiNest & 0xff, (kVendorOuiNest >> 8) & 0xff, (kVendorOuiNest >> 16) & 0xff};
cur = GetHeaderIe(kHeaderIeVendor);
VerifyOrExit(cur != NULL);
cur += sizeof(HeaderIe);
timeIe = reinterpret_cast<TimeIe *>(cur);
VerifyOrExit(memcmp(oui, timeIe->GetVendorOui(), kVendorOuiSize) == 0, cur = NULL);
VerifyOrExit(timeIe->GetSubType() == kVendorIeTime, cur = NULL);
exit:
return cur;
}
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
Frame::InfoString Frame::ToInfoString(void) const
{
InfoString string;
+297 -4
View File
@@ -377,6 +377,76 @@ private:
Type mType; ///< The address type (Short, Extended, or none).
};
/**
* This class implements IEEE 802.15.4 IE (Information Element) generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class HeaderIe
{
public:
enum
{
kIdOffset = 7,
kIdMask = 0xff << kIdOffset,
kLengthOffset = 0,
kLengthMask = 0x7f << kLengthOffset,
};
/**
* This method initializes the Header IE.
*
*/
void Init(void) { mHeaderIe = 0; }
/**
* This method returns the IE Element Id.
*
* @returns the IE Element Id.
*
*/
uint16_t GetId(void) const { return (ot::Encoding::LittleEndian::HostSwap16(mHeaderIe) & kIdMask) >> kIdOffset; }
/**
* This method sets the IE Element Id.
*
* @param[in] aID The IE Element Id.
*
*/
void SetId(uint16_t aId)
{
mHeaderIe = ot::Encoding::LittleEndian::HostSwap16(
(ot::Encoding::LittleEndian::HostSwap16(mHeaderIe) & ~kIdMask) | ((aId << kIdOffset) & kIdMask));
}
/**
* This method returns the IE content length.
*
* @returns the IE content length.
*
*/
uint16_t GetLength(void) const
{
return (ot::Encoding::LittleEndian::HostSwap16(mHeaderIe) & kLengthMask) >> kLengthOffset;
}
/**
* This method sets the IE content length.
*
* @param[in] aLength The IE content length.
*
*/
void SetLength(uint16_t aLength)
{
mHeaderIe =
ot::Encoding::LittleEndian::HostSwap16((ot::Encoding::LittleEndian::HostSwap16(mHeaderIe) & ~kLengthMask) |
((aLength << kLengthOffset) & kLengthMask));
}
private:
uint16_t mHeaderIe;
} OT_TOOL_PACKED_END;
/**
* This class implements IEEE 802.15.4 MAC frame generation and parsing.
*
@@ -403,12 +473,14 @@ public:
kFcfFramePending = 1 << 4,
kFcfAckRequest = 1 << 5,
kFcfPanidCompression = 1 << 6,
kFcfIePresent = 1 << 9,
kFcfDstAddrNone = 0 << 10,
kFcfDstAddrShort = 2 << 10,
kFcfDstAddrExt = 3 << 10,
kFcfDstAddrMask = 3 << 10,
kFcfFrameVersion2006 = 1 << 12,
kFcfFrameVersionMask = 3 << 13,
kFcfFrameVersion2015 = 2 << 12,
kFcfFrameVersionMask = 3 << 12,
kFcfSrcAddrNone = 0 << 14,
kFcfSrcAddrShort = 2 << 14,
kFcfSrcAddrExt = 3 << 14,
@@ -453,6 +525,12 @@ public:
kMacCmdCoordinatorRealignment = 8,
kMacCmdGtsRequest = 9,
kHeaderIeVendor = 0x00,
kHeaderIeTermination2 = 0x7f,
kVendorOuiNest = 0x18b430,
kVendorOuiSize = 3,
kVendorIeTime = 0x01,
kInfoStringSize = 110, ///< Max chars needed for the info string representation (@sa ToInfoString()).
};
@@ -491,6 +569,14 @@ public:
*/
uint8_t GetType(void) const { return GetPsdu()[0] & kFcfFrameTypeMask; }
/**
* This method returns the IEEE 802.15.4 Frame Version.
*
* @returns The IEEE 802.15.4 Frame Version.
*
*/
uint16_t GetVersion(void) const { return GetFrameControlField() & kFcfFrameVersionMask; };
/**
* This method indicates whether or not security is enabled.
*
@@ -534,6 +620,15 @@ public:
*/
void SetAckRequest(bool aAckRequest);
/**
* This method indicates whether or not IEs present.
*
* @retval TRUE If IEs present.
* @retval FALSE If no IE present.
*
*/
bool IsIePresent(void) const { return (GetFrameControlField() & kFcfIePresent) != 0; };
/**
* This method returns the Sequence Number value.
*
@@ -610,6 +705,14 @@ public:
*/
otError SetDstAddr(const Address &aAddress);
/**
* This method indicates whether or not the Src PanId is present.
*
* @returns TRUE if the Src PanId is present, FALSE otherwise.
*
*/
bool IsSrcPanIdPresent(uint16_t aFcf) const;
/**
* This method gets the Source PAN Identifier.
*
@@ -980,7 +1083,7 @@ public:
* @returns A pointer to the PSDU.
*
*/
const uint8_t *GetPsdu(void) const { return mPsdu; }
uint8_t *GetPsdu(void) const { return mPsdu; }
/**
* This method returns a pointer to the MAC Header.
@@ -1012,7 +1115,7 @@ public:
* @returns A pointer to the MAC Payload.
*
*/
const uint8_t *GetPayload(void) const;
uint8_t *GetPayload(void) const;
/**
* This method returns a pointer to the MAC Footer.
@@ -1028,7 +1131,88 @@ public:
* @returns A pointer to the MAC Footer.
*
*/
const uint8_t *GetFooter(void) const;
uint8_t *GetFooter(void) const;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
/**
* This method sets the Time IE offset.
*
* @param[in] aOffset The Time IE offset, 0 means no Time IE.
*
*/
void SetTimeIeOffset(uint8_t aOffset) { mIeInfo->mTimeIeOffset = aOffset; }
/**
* This method sets the offset to network time.
*
* @param[in] aNetworkTimeOffset The offset to network time.
*
*/
void SetNetworkTimeOffset(int64_t aNetworkTimeOffset) { mIeInfo->mNetworkTimeOffset = aNetworkTimeOffset; }
/**
* This method gets the offset to network time.
*
* @returns The offset to network time.
*
*/
int64_t GetNetworkTimeOffset(void) const { return mIeInfo->mNetworkTimeOffset; }
/**
* This method sets the time sync sequence.
*
* @param[in] aTimeSyncSeq The time sync sequence.
*
*/
void SetTimeSyncSeq(uint8_t aTimeSyncSeq) { mIeInfo->mTimeSyncSeq = aTimeSyncSeq; }
/**
* This method gets the time sync sequence.
*
* @returns The time sync sequence.
*
*/
uint8_t GetTimeSyncSeq(void) const { return mIeInfo->mTimeSyncSeq; }
/**
* This method returns the timestamp when the SFD was received.
*
* @returns The timestamp when the SFD was received, in microseconds.
*
*/
uint64_t GetTimestamp(void) const { return mIeInfo->mTimestamp; }
/**
* This method appends Header IEs to MAC header.
*
* @param[in] aIeList The pointer to the Header IEs array.
* @param[in] aIeCount The number of Header IEs in the array.
*
* @retval OT_ERROR_NONE Successfully appended the Header IEs.
* @retval OT_ERROR_FAILED If IE Present bit is not set.
*
*/
otError AppendHeaderIe(HeaderIe *aIeList, uint8_t aIeCount);
/**
* This method returns a pointer to the Header IE.
*
* @param[in] aIeId The Element Id of the Header IE.
*
* @returns A pointer to the Header IE, NULL if not found.
*
*/
uint8_t *GetHeaderIe(uint8_t aIeId) const;
/**
* This method returns a pointer to the vendor specific Time IE.
*
* @returns A pointer to the Time IE, NULL if not found.
*
*/
uint8_t *GetTimeIe(void) const;
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
/**
* This method returns information about the frame object as an `InfoString` object.
@@ -1051,7 +1235,11 @@ private:
uint8_t FindSrcPanIdIndex(void) const;
uint8_t FindSrcAddrIndex(void) const;
uint8_t FindSecurityHeaderIndex(void) const;
uint8_t SkipSecurityHeaderIndex(void) const;
uint8_t FindPayloadIndex(void) const;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
uint8_t FindHeaderIeIndex(void) const;
#endif
static uint8_t GetKeySourceLength(uint8_t aKeyIdMode);
};
@@ -1271,6 +1459,111 @@ private:
uint8_t mExtendedPanId[kExtPanIdSize];
} OT_TOOL_PACKED_END;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
/**
* This class implements vendor specific Header IE generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class VendorIeHeader
{
public:
/**
* This method returns the Vendor OUI.
*
* @returns the Vendor OUI.
*
*/
const uint8_t *GetVendorOui(void) const { return mVendorOui; }
/**
* This method sets the Vendor OUI.
*
* @param[in] aVendorOui A pointer to the Vendor OUI.
*
*/
void SetVendorOui(uint8_t *aVendorOui) { memcpy(mVendorOui, aVendorOui, Frame::kVendorOuiSize); }
/**
* This method returns the Vendor IE sub-type.
*
* @returns the Vendor IE sub-type.
*
*/
uint8_t GetSubType(void) const { return mSubType; }
/**
* This method sets the Vendor IE sub-type.
*
* @param[in] the Vendor IE sub-type.
*
*/
void SetSubType(uint8_t aSubType) { mSubType = aSubType; }
private:
uint8_t mVendorOui[Frame::kVendorOuiSize];
uint8_t mSubType;
} OT_TOOL_PACKED_END;
/**
* This class implements Time Header IE generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class TimeIe : public VendorIeHeader
{
public:
/**
* This method initializes the time IE.
*
*/
void Init(void)
{
uint8_t oui[3] = {Frame::kVendorOuiNest & 0xff, (Frame::kVendorOuiNest >> 8) & 0xff,
(Frame::kVendorOuiNest >> 16) & 0xff};
SetVendorOui(oui);
SetSubType(Frame::kVendorIeTime);
}
/**
* This method returns the time sync sequence.
*
* @returns the time sync sequence.
*
*/
uint8_t GetSequence(void) const { return mSequence; }
/**
* This method sets the tine sync sequence.
*
* @param[in] aSequence The time sync sequence.
*
*/
void SetSequence(uint8_t aSequence) { mSequence = aSequence; }
/**
* This method returns the network time.
*
* @returns the network time, in microseconds.
*
*/
uint64_t GetTime(void) const { return ot::Encoding::LittleEndian::HostSwap64(mTime); }
/**
* This method sets the network time.
*
* @param[in] aTime The network time.
*
*/
void SetTime(uint64_t aTime) { mTime = ot::Encoding::LittleEndian::HostSwap64(aTime); }
private:
uint8_t mSequence;
uint64_t mTime;
} OT_TOOL_PACKED_END;
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
/**
* @}
*
+50
View File
@@ -1632,4 +1632,54 @@
#define OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE 256
#endif
/**
* @def OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
*
* Define as 1 to enable the time synchronization service feature.
*
* @note If it's enabled, plaforms must support interrupt context and concurrent access AES.
*
*/
#ifndef OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
#define OPENTHREAD_CONFIG_ENABLE_TIME_SYNC 0
#endif
/**
* @def OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
*
* Define as 1 to require time synchronization when attaching to a network. If the device is router capable
* and cannot find a neighboring router supporting time synchronization, the device will form a new partition.
* If the device is not router capable, the device will remain an orphan.
*
* Applicable only if time synchronization service feature is enabled (i.e., OPENTHREAD_CONFIG_ENABLE_TIME_SYNC is set)
*
*/
#ifndef OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
#define OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED 0
#endif
/**
* @def OPENTHREAD_CONFIG_TIME_SYNC_PERIOD
*
* Specifies the default period of time synchronization, in seconds.
*
* Applicable only if time synchronization service feature is enabled (i.e., OPENTHREAD_CONFIG_ENABLE_TIME_SYNC is set)
*
*/
#ifndef OPENTHREAD_CONFIG_TIME_SYNC_PERIOD
#define OPENTHREAD_CONFIG_TIME_SYNC_PERIOD 30
#endif
/**
* @def OPENTHREAD_CONFIG_TIME_SYNC_XTAL_THRESHOLD
*
* Specifies the default XTAL threshold for a device to become Router in time synchronization enabled network, in PPM.
*
* Applicable only if time synchronization service feature is enabled (i.e., OPENTHREAD_CONFIG_ENABLE_TIME_SYNC is set)
*
*/
#ifndef OPENTHREAD_CONFIG_TIME_SYNC_XTAL_THRESHOLD
#define OPENTHREAD_CONFIG_TIME_SYNC_XTAL_THRESHOLD 300
#endif
#endif // OPENTHREAD_CORE_DEFAULT_CONFIG_H_
+69 -2
View File
@@ -622,6 +622,9 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
uint16_t dstpan;
uint8_t secCtl = Mac::Frame::kSecNone;
otError error = OT_ERROR_NONE;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
Mac::HeaderIe ieList[2];
#endif
if (mAddMeshHeader)
{
@@ -635,7 +638,20 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
}
// initialize MAC header
fcf = Mac::Frame::kFcfFrameData | Mac::Frame::kFcfFrameVersion2006;
fcf = Mac::Frame::kFcfFrameData;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
if (aMessage.IsTimeSync())
{
fcf |= Mac::Frame::kFcfFrameVersion2015 | Mac::Frame::kFcfIePresent;
}
else
#endif
{
fcf |= Mac::Frame::kFcfFrameVersion2006;
}
fcf |= (mMacDest.IsShort()) ? Mac::Frame::kFcfDstAddrShort : Mac::Frame::kFcfDstAddrExt;
fcf |= (mMacSource.IsShort()) ? Mac::Frame::kFcfSrcAddrShort : Mac::Frame::kFcfSrcAddrExt;
@@ -687,7 +703,21 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
if (dstpan == netif.GetMac().GetPanId())
{
fcf |= Mac::Frame::kFcfPanidCompression;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
// Handle a special case in IEEE 802.15.4-2015, when Pan ID Compression is 0, but Src Pan ID is not present:
// Dest Address: Extended
// Src Address: Extended
// Dest Pan ID: Present
// Src Pan ID: Not Present
// Pan ID Compression: 0
if ((fcf & Mac::Frame::kFcfFrameVersionMask) != Mac::Frame::kFcfFrameVersion2015 ||
(fcf & Mac::Frame::kFcfDstAddrMask) != Mac::Frame::kFcfDstAddrExt ||
(fcf & Mac::Frame::kFcfSrcAddrMask) != Mac::Frame::kFcfSrcAddrExt)
#endif
{
fcf |= Mac::Frame::kFcfPanidCompression;
}
}
aFrame.InitMacHeader(fcf, secCtl);
@@ -696,6 +726,28 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
aFrame.SetDstAddr(mMacDest);
aFrame.SetSrcAddr(mMacSource);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
if (aMessage.IsTimeSync())
{
Mac::TimeIe *ie;
uint8_t * cur = NULL;
ieList[0].Init();
ieList[0].SetId(Mac::Frame::kHeaderIeVendor);
ieList[0].SetLength(sizeof(Mac::TimeIe));
ieList[1].Init();
ieList[1].SetId(Mac::Frame::kHeaderIeTermination2);
ieList[1].SetLength(0);
aFrame.AppendHeaderIe(ieList, 2);
cur = aFrame.GetHeaderIe(Mac::Frame::kHeaderIeVendor);
ie = reinterpret_cast<Mac::TimeIe *>(cur + sizeof(Mac::HeaderIe));
ie->Init();
}
#endif
payload = aFrame.GetPayload();
headerLength = 0;
@@ -833,6 +885,9 @@ otError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
if (mMessageNextOffset < aMessage.GetLength())
{
aFrame.SetFramePending(true);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
aMessage.SetTimeSync(false);
#endif
}
exit:
@@ -1110,6 +1165,10 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame)
linkInfo.mRss = aFrame.GetRssi();
linkInfo.mLqi = aFrame.GetLqi();
linkInfo.mLinkSecurity = aFrame.GetSecurityEnabled();
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
linkInfo.mNetworkTimeOffset = aFrame.GetNetworkTimeOffset();
linkInfo.mTimeSyncSeq = aFrame.GetTimeSyncSeq();
#endif
payload = aFrame.GetPayload();
payloadLength = aFrame.GetPayloadLength();
@@ -1204,6 +1263,10 @@ void MeshForwarder::HandleFragment(uint8_t * aFrame,
message->SetLinkSecurityEnabled(aLinkInfo.mLinkSecurity);
message->SetPanId(aLinkInfo.mPanId);
message->AddRss(aLinkInfo.mRss);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
message->SetTimeSyncSeq(aLinkInfo.mTimeSyncSeq);
message->SetNetworkTimeOffset(aLinkInfo.mNetworkTimeOffset);
#endif
headerLength = netif.GetLowpan().Decompress(*message, aMacSource, aMacDest, aFrame, aFrameLength,
fragmentHeader.GetDatagramSize());
VerifyOrExit(headerLength > 0, error = OT_ERROR_PARSE);
@@ -1372,6 +1435,10 @@ void MeshForwarder::HandleLowpanHC(uint8_t * aFrame,
message->SetLinkSecurityEnabled(aLinkInfo.mLinkSecurity);
message->SetPanId(aLinkInfo.mPanId);
message->AddRss(aLinkInfo.mRss);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
message->SetTimeSyncSeq(aLinkInfo.mTimeSyncSeq);
message->SetNetworkTimeOffset(aLinkInfo.mNetworkTimeOffset);
#endif
headerLength = netif.GetLowpan().Decompress(*message, aMacSource, aMacDest, aFrame, aFrameLength, 0);
VerifyOrExit(headerLength > 0, error = OT_ERROR_PARSE);
+75
View File
@@ -36,6 +36,7 @@
#include "mle.hpp"
#include <openthread/platform/radio.h>
#include <openthread/platform/time.h>
#include "common/code_utils.hpp"
#include "common/debug.hpp"
@@ -55,6 +56,7 @@
#include "thread/key_manager.hpp"
#include "thread/mle_router.hpp"
#include "thread/thread_netif.hpp"
#include "thread/time_sync_service.hpp"
using ot::Encoding::BigEndian::HostSwap16;
@@ -1349,6 +1351,38 @@ exit:
return error;
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
otError Mle::AppendTimeRequest(Message &aMessage)
{
TimeRequestTlv tlv;
tlv.Init();
return aMessage.Append(&tlv, sizeof(tlv));
}
otError Mle::AppendTimeParameter(Message &aMessage)
{
TimeParameterTlv tlv;
tlv.Init();
tlv.SetTimeSyncPeriod(GetNetif().GetTimeSync().GetTimeSyncPeriod());
tlv.SetXtalThreshold(GetNetif().GetTimeSync().GetXtalThreshold());
return aMessage.Append(&tlv, sizeof(tlv));
}
otError Mle::AppendXtalAccuracy(Message &aMessage)
{
XtalAccuracyTlv tlv;
tlv.Init();
tlv.SetXtalAccuracy(otPlatTimeGetXtalAccuracy());
return aMessage.Append(&tlv, sizeof(tlv));
}
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
otError Mle::AppendActiveTimestamp(Message &aMessage)
{
ThreadNetif & netif = GetNetif();
@@ -1845,6 +1879,9 @@ otError Mle::SendParentRequest(ParentRequestType aType)
SuccessOrExit(error = AppendChallenge(*message, mParentRequest.mChallenge, sizeof(mParentRequest.mChallenge)));
SuccessOrExit(error = AppendScanMask(*message, scanMask));
SuccessOrExit(error = AppendVersion(*message));
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
SuccessOrExit(error = AppendTimeRequest(*message));
#endif
memset(&destination, 0, sizeof(destination));
destination.mFields.m16[0] = HostSwap16(0xff02);
@@ -2604,6 +2641,12 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
case Header::kCommandAnnounce:
HandleAnnounce(aMessage, aMessageInfo);
break;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
case Header::kCommandTimeSync:
mle.HandleTimeSync(aMessage, aMessageInfo);
break;
#endif
}
exit:
@@ -2947,6 +2990,9 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf
MleFrameCounterTlv mleFrameCounter;
ChallengeTlv challenge;
Mac::ExtAddress extAddress;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
TimeParameterTlv timeParameter;
#endif
// Source Address
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kSourceAddress, sizeof(sourceAddress), sourceAddress));
@@ -3050,6 +3096,27 @@ otError Mle::HandleParentResponse(const Message &aMessage, const Ip6::MessageInf
mleFrameCounter.SetFrameCounter(linkFrameCounter.GetFrameCounter());
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
// Time Parameter
if (Tlv::GetTlv(aMessage, Tlv::kTimeParameter, sizeof(timeParameter), timeParameter) == OT_ERROR_NONE)
{
VerifyOrExit(timeParameter.IsValid());
GetNetif().GetTimeSync().SetTimeSyncPeriod(timeParameter.GetTimeSyncPeriod());
GetNetif().GetTimeSync().SetXtalThreshold(timeParameter.GetXtalThreshold());
}
#if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
else
{
// If the time sync feature is required, don't choose the parent which doesn't support it.
ExitNow();
}
#endif // OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
// Challenge
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kChallenge, sizeof(challenge), challenge));
VerifyOrExit(challenge.IsValid(), error = OT_ERROR_PARSE);
@@ -3158,6 +3225,14 @@ otError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::MessageIn
netif.GetPendingDataset().ClearNetwork();
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
// Sync to Thread network time
if (aMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ)
{
GetNetif().GetTimeSync().HandleTimeSyncMessage(aMessage);
}
#endif
// Parent Attach Success
mAttachTimer.Stop();
SetStateDetached();
+42
View File
@@ -301,6 +301,13 @@ public:
kCommandAnnounce = 15, ///< Announce
kCommandDiscoveryRequest = 16, ///< Discovery Request
kCommandDiscoveryResponse = 17, ///< Discovery Response
/**
* Applicable/Required only when time synchronization service
* (`OPENTHREAD_CONFIG_ENABLE_TIME_SYNC`) is enabled.
*
*/
kCommandTimeSync = 99, ///< Time Synchronization
};
/**
@@ -1248,6 +1255,41 @@ protected:
*/
otError AppendAddressRegistration(Message &aMessage);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
/**
* This method appends a Time Request TLV to a message.
*
* @param[in] aMessage A reference to the message.
*
* @retval OT_ERROR_NONE Successfully appended the Time Request TLV.
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to append the Time Request TLV.
*
*/
otError AppendTimeRequest(Message &aMessage);
/**
* This method appends a Time Parameter TLV to a message.
*
* @param[in] aMessage A reference to the message.
*
* @retval OT_ERROR_NONE Successfully appended the Time Parameter TLV.
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to append the Time Parameter TLV.
*
*/
otError AppendTimeParameter(Message &aMessage);
/**
* This method appends a XTAL Accuracy TLV to a message.
*
* @param[in] aMessage A reference to the message.
*
* @retval OT_ERROR_NONE Successfully appended the XTAL Accuracy TLV.
* @retval OT_ERROR_NO_BUFS Insufficient buffers available to append the XTAl Accuracy TLV.
*
*/
otError AppendXtalAccuracy(Message &aMessage);
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
/**
* This method appends a Active Timestamp TLV to a message.
*
+127 -1
View File
@@ -50,6 +50,7 @@
#include "thread/thread_netif.hpp"
#include "thread/thread_tlvs.hpp"
#include "thread/thread_uri_paths.hpp"
#include "thread/time_sync_service.hpp"
using ot::Encoding::BigEndian::HostSwap16;
@@ -506,6 +507,10 @@ otError MleRouter::SendLinkRequest(Neighbor *aNeighbor)
break;
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
SuccessOrExit(error = AppendTimeRequest(*message));
#endif
if (aNeighbor == NULL)
{
Random::FillBuffer(mChallenge, sizeof(mChallenge));
@@ -561,6 +566,9 @@ otError MleRouter::HandleLinkRequest(const Message &aMessage, const Ip6::Message
SourceAddressTlv sourceAddress;
TlvRequestTlv tlvRequest;
uint16_t rloc16;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
TimeRequestTlv timeRequest;
#endif
LogMleMessage("Receive Link Request", aMessageInfo.GetPeerAddr());
@@ -646,6 +654,17 @@ otError MleRouter::HandleLinkRequest(const Message &aMessage, const Ip6::Message
tlvRequest.SetLength(0);
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
if (Tlv::GetTlv(aMessage, Tlv::kTimeRequest, sizeof(timeRequest), timeRequest) == OT_ERROR_NONE)
{
neighbor->SetTimeSyncEnabled(true);
}
else
{
neighbor->SetTimeSyncEnabled(false);
}
#endif
SuccessOrExit(error = SendLinkAccept(aMessageInfo, neighbor, tlvRequest, challenge));
exit:
@@ -717,6 +736,13 @@ otError MleRouter::SendLinkAccept(const Ip6::MessageInfo &aMessageInfo,
aNeighbor->SetState(Neighbor::kStateLinkRequest);
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
if (aNeighbor->IsTimeSyncEnabled())
{
message->SetTimeSync(true);
}
#endif
if (aMessageInfo.GetSockAddr().IsMulticast())
{
SuccessOrExit(error = AddDelayedResponse(*message, aMessageInfo.GetPeerAddr(),
@@ -900,6 +926,9 @@ otError MleRouter::HandleLinkAccept(const Message & aMessage,
SendDataRequest(aMessageInfo.GetPeerAddr(), dataRequestTlvs, sizeof(dataRequestTlvs), 0);
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
GetNetif().GetTimeSync().HandleTimeSyncMessage(aMessage);
#endif
break;
case OT_DEVICE_ROLE_CHILD:
@@ -1167,7 +1196,12 @@ otError MleRouter::HandleAdvertisement(const Message &aMessage, const Ip6::Messa
ExitNow();
}
if (ComparePartitions(IsSingleton(route), leaderData, IsSingleton(), mLeaderData) > 0)
if (ComparePartitions(IsSingleton(route), leaderData, IsSingleton(), mLeaderData) > 0
#if OPENTHREAD_CONFIG_TIME_SYNC_REQUIRED
// if time sync is required, it will only migrate to a better network which also enables time sync.
&& aMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ
#endif
)
{
BecomeChild(kAttachBetter);
}
@@ -1189,6 +1223,10 @@ otError MleRouter::HandleAdvertisement(const Message &aMessage, const Ip6::Messa
VerifyOrExit(IsActiveRouter(sourceAddress.GetRloc16()) && route.IsValid());
routerId = GetRouterId(sourceAddress.GetRloc16());
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
GetNetif().GetTimeSync().HandleTimeSyncMessage(aMessage);
#endif
if (IsFullThreadDevice() &&
((mRouterTable.GetActiveRouterCount() == 0) ||
(static_cast<int8_t>(route.GetRouterIdSequence() - mRouterTable.GetRouterIdSequence()) > 0)))
@@ -1507,6 +1545,9 @@ otError MleRouter::HandleParentRequest(const Message &aMessage, const Ip6::Messa
ChallengeTlv challenge;
Router * leader;
Child * child;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
TimeRequestTlv timeRequest;
#endif
LogMleMessage("Receive Parent Request", aMessageInfo.GetPeerAddr());
@@ -1577,6 +1618,16 @@ otError MleRouter::HandleParentRequest(const Message &aMessage, const Ip6::Messa
child->ResetLinkFailures();
child->SetState(Neighbor::kStateParentRequest);
child->SetDataRequestPending(false);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
if (Tlv::GetTlv(aMessage, Tlv::kTimeRequest, sizeof(timeRequest), timeRequest) == OT_ERROR_NONE)
{
child->SetTimeSyncEnabled(true);
}
else
{
child->SetTimeSyncEnabled(false);
}
#endif
}
if (!child->IsStateValidOrRestoring())
@@ -1794,6 +1845,13 @@ void MleRouter::HandleStateUpdateTimer(void)
SynchronizeChildNetworkData();
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
if (mRole == OT_DEVICE_ROLE_LEADER || mRole == OT_DEVICE_ROLE_ROUTER)
{
GetNetif().GetTimeSync().ProcessTimeSync();
}
#endif
exit:
return;
}
@@ -1814,6 +1872,12 @@ otError MleRouter::SendParentResponse(Child *aChild, const ChallengeTlv &aChalle
SuccessOrExit(error = AppendLinkFrameCounter(*message));
SuccessOrExit(error = AppendMleFrameCounter(*message));
SuccessOrExit(error = AppendResponse(*message, aChallenge.GetChallenge(), aChallenge.GetLength()));
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
if (aChild->IsTimeSyncEnabled())
{
SuccessOrExit(error = AppendTimeParameter(*message));
}
#endif
aChild->GenerateChallenge();
@@ -2740,6 +2804,13 @@ otError MleRouter::SendChildIdResponse(Child &aChild)
netif.GetMeshForwarder().GetSourceMatchController().SetSrcMatchAsShort(aChild, false);
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
if (aChild.IsTimeSyncEnabled())
{
message->SetTimeSync(true);
}
#endif
memset(&destination, 0, sizeof(destination));
destination.mFields.m16[0] = HostSwap16(0xfe80);
destination.SetIid(aChild.GetExtAddress());
@@ -3695,6 +3766,10 @@ otError MleRouter::SendAddressSolicit(ThreadStatusTlv::Status aStatus)
statusTlv.SetStatus(aStatus);
SuccessOrExit(error = message->Append(&statusTlv, sizeof(statusTlv)));
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
SuccessOrExit(error = AppendXtalAccuracy(*message));
#endif
SuccessOrExit(error = GetLeaderAddress(messageInfo.GetPeerAddr()));
messageInfo.SetSockAddr(GetMeshLocal16());
messageInfo.SetPeerPort(kCoapUdpPort);
@@ -3889,6 +3964,9 @@ void MleRouter::HandleAddressSolicit(Coap::Header &aHeader, Message &aMessage, c
ThreadRloc16Tlv rlocTlv;
ThreadStatusTlv statusTlv;
Router * router = NULL;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
XtalAccuracyTlv xtalAccuracyTlv;
#endif
VerifyOrExit(aHeader.GetType() == OT_COAP_TYPE_CONFIRMABLE && aHeader.GetCode() == OT_COAP_CODE_POST,
error = OT_ERROR_PARSE);
@@ -3901,6 +3979,15 @@ void MleRouter::HandleAddressSolicit(Coap::Header &aHeader, Message &aMessage, c
SuccessOrExit(error = ThreadTlv::GetTlv(aMessage, ThreadTlv::kStatus, sizeof(statusTlv), statusTlv));
VerifyOrExit(statusTlv.IsValid(), error = OT_ERROR_PARSE);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
// In a time sync enabled network, all routers' xtal accuracy must be less than the threshold.
if (Tlv::GetTlv(aMessage, Tlv::kXtalAccuracy, sizeof(xtalAccuracyTlv), xtalAccuracyTlv) != OT_ERROR_NONE ||
xtalAccuracyTlv.GetXtalAccuracy() > GetNetif().GetTimeSync().GetXtalThreshold())
{
ExitNow(router = NULL);
}
#endif
// see if allocation already exists
router = mRouterTable.GetRouter(macAddr64Tlv.GetMacAddr());
@@ -4554,6 +4641,45 @@ bool MleRouter::IsSleepyChildSubscribed(const Ip6::Address &aAddress, Child &aCh
aChild.HasIp6Address(GetInstance(), aAddress);
}
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
otError MleRouter::HandleTimeSync(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
LogMleMessage("Receive Time Sync", aMessageInfo.GetPeerAddr());
GetNetif().GetTimeSync().HandleTimeSyncMessage(aMessage);
return OT_ERROR_NONE;
}
otError MleRouter::SendTimeSync(void)
{
otError error = OT_ERROR_NONE;
Ip6::Address destination;
Message * message = NULL;
VerifyOrExit((message = NewMleMessage()) != NULL, error = OT_ERROR_NO_BUFS);
SuccessOrExit(error = AppendHeader(*message, Header::kCommandTimeSync));
message->SetTimeSync(true);
memset(&destination, 0, sizeof(destination));
destination.mFields.m16[0] = HostSwap16(0xff02);
destination.mFields.m16[7] = HostSwap16(0x0001);
SuccessOrExit(error = SendMessage(*message, destination));
LogMleMessage("Send Time Sync", destination);
exit:
if (error != OT_ERROR_NONE && message != NULL)
{
message->Free();
}
return error;
}
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
} // namespace Mle
} // namespace ot
+14
View File
@@ -669,6 +669,17 @@ public:
*/
static uint8_t LinkQualityToCost(uint8_t aLinkQuality);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
/**
* This method generates an MLE Time Synchronization message.
*
* @retval OT_ERROR_NONE Successfully sent an MLE Time Synchronization message.
* @retval OT_ERROR_NO_BUFS Insufficient buffers to generate the MLE Time Synchronization message.
*
*/
otError SendTimeSync(void);
#endif
private:
enum
{
@@ -707,6 +718,9 @@ private:
otError HandleDataRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
otError HandleNetworkDataUpdateRouter(void);
otError HandleDiscoveryRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
otError HandleTimeSync(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
#endif
otError ProcessRouteTlv(const RouteTlv &aRoute);
void StopAdvertiseTimer(void);
+3
View File
@@ -147,6 +147,9 @@ private:
void HandlePartitionChange(void) {}
void StopAdvertiseTimer(void) {}
otError ProcessRouteTlv(const RouteTlv &) { return OT_ERROR_NONE; }
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
otError HandleTimeSync(const Message &, const Ip6::MessageInfo &) { return OT_ERROR_DROP; }
#endif
ChildTable mChildTable;
RouterTable mRouterTable;
+152 -1
View File
@@ -109,7 +109,17 @@ public:
kActiveDataset = 24, ///< Active Operational Dataset TLV
kPendingDataset = 25, ///< Pending Operational Dataset TLV
kDiscovery = 26, ///< Thread Discovery TLV
kInvalid = 255,
/**
* Applicable/Required only when time synchronization service
* (`OPENTHREAD_CONFIG_ENABLE_TIME_SYNC`) is enabled.
*
*/
kTimeRequest = 252, ///< Time Request TLV
kTimeParameter = 253, ///< Time Parameter TLV
kXtalAccuracy = 254, ///< XTAL Accuracy TLV
kInvalid = 255,
};
/**
@@ -1595,6 +1605,147 @@ private:
uint16_t mPanId;
} OT_TOOL_PACKED_END;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
/**
* This class implements Time Request TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class TimeRequestTlv : public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void)
{
SetType(kTimeRequest);
SetLength(sizeof(*this) - sizeof(Tlv));
}
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
} OT_TOOL_PACKED_END;
/**
* This class implements Time Parameter TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class TimeParameterTlv : public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void)
{
SetType(kTimeParameter);
SetLength(sizeof(*this) - sizeof(Tlv));
}
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
/**
* This method returns the time sync period.
*
* @returns The time sync period.
*
*/
uint16_t GetTimeSyncPeriod(void) const { return HostSwap16(mTimeSyncPeriod); }
/**
* This method sets the time sync period.
*
* @param[in] aTimeSyncPeriod The time sync period.
*
*/
void SetTimeSyncPeriod(uint16_t aTimeSyncPeriod) { mTimeSyncPeriod = HostSwap16(aTimeSyncPeriod); }
/**
* This method returns the XTAL accuracy threshold.
*
* @returns The XTAL accuracy threshold.
*
*/
uint16_t GetXtalThreshold(void) const { return HostSwap16(mXtalThreshold); }
/**
* This method sets the XTAL accuracy threshold.
*
* @param[in] aXTALThreshold The XTAL accuracy threshold.
*
*/
void SetXtalThreshold(uint16_t aXtalThreshold) { mXtalThreshold = HostSwap16(aXtalThreshold); }
private:
uint16_t mTimeSyncPeriod;
uint16_t mXtalThreshold;
} OT_TOOL_PACKED_END;
/**
* This class implements XTAL Accuracy TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class XtalAccuracyTlv : public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void)
{
SetType(kXtalAccuracy);
SetLength(sizeof(*this) - sizeof(Tlv));
}
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
/**
* This method returns the XTAL accuracy.
*
* @returns The XTAL accuracy.
*
*/
uint16_t GetXtalAccuracy(void) const { return HostSwap16(mXtalAccuracy); }
/**
* This method sets the XTAL accuracy.
*
* @param[in] aXTALAccuracy The XTAL accuracy.
*
*/
void SetXtalAccuracy(uint16_t aXtalAccuracy) { mXtalAccuracy = HostSwap16(aXtalAccuracy); }
private:
uint16_t mXtalAccuracy;
} OT_TOOL_PACKED_END;
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
/**
* This class implements Active Timestamp TLV generation and parsing.
*
+3 -1
View File
@@ -102,7 +102,9 @@ ThreadNetif::ThreadNetif(Instance &aInstance)
, mAnnounceBegin(aInstance)
, mPanIdQuery(aInstance)
, mEnergyScan(aInstance)
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
, mTimeSync(aInstance)
#endif
{
mCoap.SetInterceptor(&ThreadNetif::TmfFilter, this);
}
+14
View File
@@ -78,6 +78,7 @@
#include "thread/network_data_local.hpp"
#include "thread/network_diagnostic.hpp"
#include "thread/panid_query_server.hpp"
#include "thread/time_sync_service.hpp"
#include "utils/child_supervision.hpp"
#if OPENTHREAD_ENABLE_JAM_DETECTION
@@ -412,6 +413,16 @@ public:
*/
PanIdQueryServer &GetPanIdQueryServer(void) { return mPanIdQuery; }
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
/**
* This method returns a reference to the Time Synchronization Service object.
*
* @returns A reference to the Time Synchronization Service object.
*
*/
TimeSync &GetTimeSync(void) { return mTimeSync; }
#endif
/**
* This method returns whether Thread Management Framework Addressing Rules are met.
*
@@ -483,6 +494,9 @@ private:
AnnounceBeginServer mAnnounceBegin;
PanIdQueryServer mPanIdQuery;
EnergyScanServer mEnergyScan;
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
TimeSync mTimeSync;
#endif
};
/**
+154
View File
@@ -0,0 +1,154 @@
/*
* Copyright (c) 2018, 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 OpenThread Time Synchronization Service.
*/
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
#include "time_sync_service.hpp"
#include <openthread/platform/alarm-micro.h>
#include <openthread/platform/alarm-milli.h>
#include <openthread/platform/time.h>
#include "common/instance.hpp"
#include "common/logging.hpp"
namespace ot {
TimeSync::TimeSync(Instance &aInstance)
: InstanceLocator(aInstance)
, mTimeSyncRequired(false)
, mTimeSyncSeq(OT_TIME_SYNC_INVALID_SEQ)
, mTimeSyncPeriod(OPENTHREAD_CONFIG_TIME_SYNC_PERIOD)
, mXtalThreshold(OPENTHREAD_CONFIG_TIME_SYNC_XTAL_THRESHOLD)
, mLastTimeSyncSent(0)
, mLastTimeSyncReceived(0)
, mNetworkTimeOffset(0)
{
}
otNetworkTimeStatus TimeSync::GetTime(uint64_t &aNetworkTime) const
{
otNetworkTimeStatus networkTimeStatus = OT_NETWORK_TIME_SYNCHRONIZED;
otDeviceRole role = GetInstance().GetThreadNetif().GetMle().GetRole();
switch (role)
{
case OT_DEVICE_ROLE_DISABLED:
case OT_DEVICE_ROLE_DETACHED:
networkTimeStatus = OT_NETWORK_TIME_UNSYNCHRONIZED;
break;
case OT_DEVICE_ROLE_CHILD:
case OT_DEVICE_ROLE_ROUTER:
if ((TimerMilli::GetNow() - mLastTimeSyncReceived) > 2 * TimerMilli::SecToMsec(mTimeSyncPeriod))
{
// The device hasnt received time sync for more than two periods time.
networkTimeStatus = OT_NETWORK_TIME_RESYNC_NEEDED;
}
break;
case OT_DEVICE_ROLE_LEADER:
break;
}
aNetworkTime = otPlatTimeGet() + mNetworkTimeOffset;
return networkTimeStatus;
}
void TimeSync::HandleTimeSyncMessage(const Message &aMessage)
{
VerifyOrExit(aMessage.GetTimeSyncSeq() != OT_TIME_SYNC_INVALID_SEQ);
if (mTimeSyncSeq != OT_TIME_SYNC_INVALID_SEQ && (int8_t)(aMessage.GetTimeSyncSeq() - mTimeSyncSeq) < 0)
{
// receive older time sync sequence.
mTimeSyncRequired = true;
}
else if (GetInstance().GetThreadNetif().GetMle().GetRole() != OT_DEVICE_ROLE_LEADER)
{
// Update network time in following three cases:
// 1. during first attach;
// 2. already attached, receive newer time sync sequence;
// 3. during reattach or migration process.
if (mTimeSyncSeq == OT_TIME_SYNC_INVALID_SEQ || (int8_t)(aMessage.GetTimeSyncSeq() - mTimeSyncSeq) > 0 ||
GetInstance().GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_DETACHED)
{
// update network time and forward it.
mLastTimeSyncReceived = TimerMilli::GetNow();
mTimeSyncSeq = aMessage.GetTimeSyncSeq();
mNetworkTimeOffset = aMessage.GetNetworkTimeOffset();
mTimeSyncRequired = true;
}
}
exit:
return;
}
void TimeSync::IncrementTimeSyncSeq(void)
{
if (++mTimeSyncSeq == OT_TIME_SYNC_INVALID_SEQ)
{
++mTimeSyncSeq;
}
}
#if OPENTHREAD_FTD
void TimeSync::ProcessTimeSync(void)
{
if (GetInstance().GetThreadNetif().GetMle().GetRole() == OT_DEVICE_ROLE_LEADER &&
TimerMilli::GetNow() - mLastTimeSyncSent > TimerMilli::SecToMsec(mTimeSyncPeriod))
{
IncrementTimeSyncSeq();
mTimeSyncRequired = true;
}
if (mTimeSyncRequired)
{
VerifyOrExit(GetInstance().GetThreadNetif().GetMle().SendTimeSync() == OT_ERROR_NONE);
mLastTimeSyncSent = TimerMilli::GetNow();
mTimeSyncRequired = false;
}
exit:
return;
}
#endif // OPENTHREAD_FTD
} // namespace ot
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
+165
View File
@@ -0,0 +1,165 @@
/*
* Copyright (c) 2018, 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 network time synchronization service.
*/
#ifndef TIME_SYNC_HPP_
#define TIME_SYNC_HPP_
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
#include <openthread/network_time.h>
#include <openthread/types.h>
#include "common/locator.hpp"
#include "common/message.hpp"
#include "common/timer.hpp"
namespace ot {
/**
* This class implements OpenThread Time Synchronization Service.
*
*/
class TimeSync : public InstanceLocator
{
public:
/**
* This constructor initializes the object.
*
*/
TimeSync(Instance &aInstance);
/**
* Get the Thread network time.
*
* @param[inout] aNetworkTime The Thread network time in microseconds.
*
* @returns The time synchronization status.
*
*/
otNetworkTimeStatus GetTime(uint64_t &aNetworkTime) const;
/**
* Handle the message which includes time synchronization information.
*
* @param[in] aMessage The message which includes time synchronization information.
*
*/
void HandleTimeSyncMessage(const Message &aMessage);
#if OPENTHREAD_FTD
/**
* Send a time synchronization message when it is required.
*
* Note: A time synchronization message is required in following cases:
* 1. Leader send time sync message periodically;
* 2. Router(except Leader) received a time sync message with newer sequence;
* 3. Router received a time sync message with older sequence.
*
*/
void ProcessTimeSync(void);
#endif
/**
* This method gets the time synchronization sequence.
*
* @returns The time synchronization sequence.
*
*/
uint8_t GetTimeSyncSeq(void) const { return mTimeSyncSeq; };
/**
* This method gets the time offset to the Thread network time.
*
* @returns The time offset to the Thread network time, in microseconds.
*
*/
int64_t GetNetworkTimeOffset(void) const { return mNetworkTimeOffset; };
/**
* Set the time synchronization period.
*
* @param[in] aTimeSyncPeriod The time synchronization period, in seconds.
*
*/
void SetTimeSyncPeriod(uint16_t aTimeSyncPeriod) { mTimeSyncPeriod = aTimeSyncPeriod; }
/**
* Get the time synchronization period.
*
* @returns The time synchronization period, in seconds.
*
*/
uint16_t GetTimeSyncPeriod(void) const { return mTimeSyncPeriod; }
/**
* Set the time synchronization XTAL accuracy threshold for Router.
*
* @param[in] aXtalThreshold The XTAL accuracy threshold for Router, in PPM.
*
*/
void SetXtalThreshold(uint16_t aXtalThreshold) { mXtalThreshold = aXtalThreshold; }
/**
* Get the time synchronization XTAL accuracy threshold for Router.
*
* @returns The XTAL accuracy threshold for Router, in PPM.
*
*/
uint16_t GetXtalThreshold(void) const { return mXtalThreshold; }
private:
/**
* Increase the time synchronization sequence.
*
*/
void IncrementTimeSyncSeq(void);
bool mTimeSyncRequired; ///< Indicate whether or not a time synchronization message is required.
uint8_t mTimeSyncSeq; ///< The time synchronization sequence.
uint16_t mTimeSyncPeriod; ///< The time synchronization period.
uint16_t mXtalThreshold; ///< The XTAL accuracy threshold for a device to become a Router, in PPM.
uint32_t mLastTimeSyncSent; ///< The time when the last time synchronization message was sent.
uint32_t mLastTimeSyncReceived; ///< The time when the last time synchronization message was received.
int64_t mNetworkTimeOffset; ///< The time offset to the Thread Network time
};
/**
* @}
*/
} // namespace ot
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
#endif // TIME_SYNC_HPP_
+30 -7
View File
@@ -336,6 +336,24 @@ public:
*/
uint8_t GetChallengeSize(void) const { return sizeof(mValidPending.mPending.mChallenge); }
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
/**
* This method indicates whether or not time sync feature is enabled.
*
* @returns TRUE if time sync feature is enabled, FALSE otherwise.
*
*/
bool IsTimeSyncEnabled(void) const { return mTimeSyncEnabled; }
/**
* This method sets whether or not time sync feature is enabled.
*
* @param[in] aEnable TRUE if time sync feature is enabled, FALSE otherwise.
*
*/
void SetTimeSyncEnabled(bool aEnabled) { mTimeSyncEnabled = aEnabled; }
#endif
private:
Mac::ExtAddress mMacAddr; ///< The IEEE 802.15.4 Extended Address
uint32_t mLastHeard; ///< Time when last heard.
@@ -352,13 +370,18 @@ private:
} mPending;
} mValidPending;
uint32_t mKeySequence; ///< Current key sequence
uint16_t mRloc16; ///< The RLOC16
uint8_t mState : 3; ///< The link state
uint8_t mMode : 4; ///< The MLE device mode
bool mDataRequest : 1; ///< Indicates whether or not a Data Poll was received
uint8_t mLinkFailures; ///< Consecutive link failure count
LinkQualityInfo mLinkInfo; ///< Link quality info (contains average RSS, link margin and link quality)
uint32_t mKeySequence; ///< Current key sequence
uint16_t mRloc16; ///< The RLOC16
uint8_t mState : 3; ///< The link state
uint8_t mMode : 4; ///< The MLE device mode
bool mDataRequest : 1; ///< Indicates whether or not a Data Poll was received
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
uint8_t mLinkFailures : 7; ///< Consecutive link failure count
bool mTimeSyncEnabled : 1; ///< Indicates whether or not time sync feature is enabled.
#else
uint8_t mLinkFailures; ///< Consecutive link failure count
#endif
LinkQualityInfo mLinkInfo; ///< Link quality info (contains average RSS, link margin and link quality)
};
/**
+16
View File
@@ -217,6 +217,9 @@ const NcpBase::PropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = {
NCP_GET_PROP_HANDLER_ENTRY(CNTR_IP_RX_SUCCESS),
NCP_GET_PROP_HANDLER_ENTRY(CNTR_IP_TX_FAILURE),
NCP_GET_PROP_HANDLER_ENTRY(CNTR_IP_RX_FAILURE),
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
NCP_GET_PROP_HANDLER_ENTRY(THREAD_NETWORK_TIME),
#endif
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
#if OPENTHREAD_FTD
@@ -253,6 +256,11 @@ const NcpBase::PropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = {
NCP_GET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_AUTO_SELECT_ENABLED),
NCP_GET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_AUTO_SELECT_INTERVAL),
#endif
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
NCP_GET_PROP_HANDLER_ENTRY(TIME_SYNC_PERIOD),
NCP_GET_PROP_HANDLER_ENTRY(TIME_SYNC_XTAL_THRESHOLD),
#endif
#endif // OPENTHREAD_FTD
#if OPENTHREAD_RADIO || OPENTHREAD_ENABLE_RAW_LINK_API
@@ -361,6 +369,10 @@ const NcpBase::PropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = {
NCP_SET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_AUTO_SELECT_ENABLED),
NCP_SET_PROP_HANDLER_ENTRY(CHANNEL_MANAGER_AUTO_SELECT_INTERVAL),
#endif
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
NCP_SET_PROP_HANDLER_ENTRY(TIME_SYNC_PERIOD),
NCP_SET_PROP_HANDLER_ENTRY(TIME_SYNC_XTAL_THRESHOLD),
#endif
#endif // #if OPENTHREAD_FTD
};
@@ -2026,6 +2038,10 @@ otError NcpBase::GetPropertyHandler_CAPS(void)
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_CHANNEL_MANAGER));
#endif
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_TIME_SYNC));
#endif
#if OPENTHREAD_CONFIG_ENABLE_TX_ERROR_RATE_TRACKING
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_ERROR_RATE_TRACKING));
#endif
+10
View File
@@ -628,6 +628,10 @@ protected:
NCP_GET_PROP_HANDLER(NEST_LEGACY_LAST_NODE_JOINED);
#endif
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
NCP_GET_PROP_HANDLER(THREAD_NETWORK_TIME);
#endif
#endif // OPENTHREAD_MTD || OPENTHREAD_FTD
// --------------------------------------------------------------------------
@@ -695,6 +699,12 @@ protected:
NCP_GET_PROP_HANDLER(CHANNEL_MANAGER_AUTO_SELECT_INTERVAL);
NCP_SET_PROP_HANDLER(CHANNEL_MANAGER_AUTO_SELECT_INTERVAL);
#endif
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
NCP_GET_PROP_HANDLER(TIME_SYNC_PERIOD);
NCP_SET_PROP_HANDLER(TIME_SYNC_PERIOD);
NCP_GET_PROP_HANDLER(TIME_SYNC_XTAL_THRESHOLD);
NCP_SET_PROP_HANDLER(TIME_SYNC_XTAL_THRESHOLD);
#endif
#endif // OPENTHREAD_FTD
+38
View File
@@ -998,6 +998,44 @@ exit:
#endif // OPENTHREAD_ENABLE_CHANNEL_MANAGER
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
otError NcpBase::GetPropertyHandler_TIME_SYNC_PERIOD(void)
{
return mEncoder.WriteUint16(otNetworkTimeGetSyncPeriod(mInstance));
}
otError NcpBase::SetPropertyHandler_TIME_SYNC_PERIOD(void)
{
otError error = OT_ERROR_NONE;
uint16_t timeSyncPeriod;
SuccessOrExit(error = mDecoder.ReadUint16(timeSyncPeriod));
SuccessOrExit(error = otNetworkTimeSetSyncPeriod(mInstance, timeSyncPeriod));
exit:
return error;
}
otError NcpBase::GetPropertyHandler_TIME_SYNC_XTAL_THRESHOLD(void)
{
return mEncoder.WriteUint16(otNetworkTimeGetXtalThreshold(mInstance));
}
otError NcpBase::SetPropertyHandler_TIME_SYNC_XTAL_THRESHOLD(void)
{
otError error = OT_ERROR_NONE;
uint16_t xtalThreshold;
SuccessOrExit(error = mDecoder.ReadUint16(xtalThreshold));
SuccessOrExit(error = otNetworkTimeSetXtalThreshold(mInstance, xtalThreshold));
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
} // namespace Ncp
} // namespace ot
+20
View File
@@ -46,6 +46,9 @@
#include <openthread/jam_detection.h>
#endif
#include <openthread/ncp.h>
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
#include <openthread/network_time.h>
#endif
#include <openthread/openthread.h>
#include <openthread/platform/misc.h>
#include <openthread/platform/radio.h>
@@ -2521,6 +2524,23 @@ void NcpBase::StopLegacy(void)
#endif // OPENTHREAD_ENABLE_LEGACY
#if OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
otError NcpBase::GetPropertyHandler_THREAD_NETWORK_TIME(void)
{
otError error = OT_ERROR_NONE;
otNetworkTimeStatus networkTimeStatus;
uint64_t time;
networkTimeStatus = otNetworkTimeGet(mInstance, time);
SuccessOrExit(error = mEncoder.WriteUint64(time));
SuccessOrExit(error = mEncoder.WriteInt8((int8_t)networkTimeStatus));
exit:
return error;
}
#endif // OPENTHREAD_CONFIG_ENABLE_TIME_SYNC
otError NcpBase::EncodeChannelMask(uint32_t aChannelMask)
{
otError error = OT_ERROR_NONE;
+16
View File
@@ -1641,6 +1641,18 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key)
ret = "PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL";
break;
case SPINEL_PROP_THREAD_NETWORK_TIME:
ret = "PROP_THREAD_NETWORK_TIME";
break;
case SPINEL_PROP_TIME_SYNC_PERIOD:
ret = "PROP_TIME_SYNC_PERIOD";
break;
case SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD:
ret = "PROP_TIME_SYNC_XTAL_THRESHOLD";
break;
case SPINEL_PROP_UART_BITRATE:
ret = "PROP_UART_BITRATE";
break;
@@ -2226,6 +2238,10 @@ const char *spinel_capability_to_cstr(unsigned int capability)
ret = "CAP_OPENTHREAD_LOG_METADATA";
break;
case SPINEL_CAP_TIME_SYNC:
ret = "CAP_TIME_SYNC";
break;
case SPINEL_CAP_ERROR_RATE_TRACKING:
ret = "CAP_ERROR_RATE_TRACKING";
break;
+32
View File
@@ -452,6 +452,7 @@ enum
SPINEL_CAP_ERROR_RATE_TRACKING = (SPINEL_CAP_OPENTHREAD__BEGIN + 4),
SPINEL_CAP_CHANNEL_MANAGER = (SPINEL_CAP_OPENTHREAD__BEGIN + 5),
SPINEL_CAP_OPENTHREAD_LOG_METADATA = (SPINEL_CAP_OPENTHREAD__BEGIN + 6),
SPINEL_CAP_TIME_SYNC = (SPINEL_CAP_OPENTHREAD__BEGIN + 7),
SPINEL_CAP_OPENTHREAD__END = 640,
SPINEL_CAP_THREAD__BEGIN = 1024,
@@ -1567,6 +1568,37 @@ typedef enum {
*/
SPINEL_PROP_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL = SPINEL_PROP_OPENTHREAD__BEGIN + 6,
/// Thread network time.
/** Format: `Xc` - Read only
*
* Data per item is:
*
* `X`: The Thread network time, in microseconds.
* `c`: Time synchronization status.
*
*/
SPINEL_PROP_THREAD_NETWORK_TIME = SPINEL_PROP_OPENTHREAD__BEGIN + 7,
/// Thread time synchronization period
/** Format: `S` - Read-Write
*
* Data per item is:
*
* `S`: Time synchronization period, in seconds.
*
*/
SPINEL_PROP_TIME_SYNC_PERIOD = SPINEL_PROP_OPENTHREAD__BEGIN + 8,
/// Thread Time synchronization XTAL accuracy threshold for Router
/** Format: `S` - Read-Write
*
* Data per item is:
*
* `S`: The XTAL accuracy threshold for Router, in PPM.
*
*/
SPINEL_PROP_TIME_SYNC_XTAL_THRESHOLD = SPINEL_PROP_OPENTHREAD__BEGIN + 9,
SPINEL_PROP_OPENTHREAD__END = 0x2000,
/// UART Bitrate
+25 -17
View File
@@ -46,26 +46,34 @@ void TestMacHeader(void)
uint8_t secCtl;
uint8_t headerLength;
} tests[] = {
{Mac::Frame::kFcfDstAddrNone | Mac::Frame::kFcfSrcAddrNone, 0, 3},
{Mac::Frame::kFcfDstAddrNone | Mac::Frame::kFcfSrcAddrShort, 0, 7},
{Mac::Frame::kFcfDstAddrNone | Mac::Frame::kFcfSrcAddrExt, 0, 13},
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrNone, 0, 7},
{Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrNone, 0, 13},
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort, 0, 11},
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrExt, 0, 17},
{Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrShort, 0, 17},
{Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrExt, 0, 23},
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrNone | Mac::Frame::kFcfSrcAddrNone, 0, 3},
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrNone | Mac::Frame::kFcfSrcAddrShort, 0, 7},
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrNone | Mac::Frame::kFcfSrcAddrExt, 0, 13},
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrNone, 0, 7},
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrNone, 0, 13},
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort, 0, 11},
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrExt, 0, 17},
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrShort, 0, 17},
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrExt, 0, 23},
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort | Mac::Frame::kFcfPanidCompression, 0, 9},
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrExt | Mac::Frame::kFcfPanidCompression, 0, 15},
{Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrShort | Mac::Frame::kFcfPanidCompression, 0, 15},
{Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrExt | Mac::Frame::kFcfPanidCompression, 0, 21},
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort |
Mac::Frame::kFcfPanidCompression,
0, 9},
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrExt |
Mac::Frame::kFcfPanidCompression,
0, 15},
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrShort |
Mac::Frame::kFcfPanidCompression,
0, 15},
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrExt | Mac::Frame::kFcfSrcAddrExt |
Mac::Frame::kFcfPanidCompression,
0, 21},
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort | Mac::Frame::kFcfPanidCompression |
Mac::Frame::kFcfSecurityEnabled,
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort |
Mac::Frame::kFcfPanidCompression | Mac::Frame::kFcfSecurityEnabled,
Mac::Frame::kSecMic32 | Mac::Frame::kKeyIdMode1, 15},
{Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort | Mac::Frame::kFcfPanidCompression |
Mac::Frame::kFcfSecurityEnabled,
{Mac::Frame::kFcfFrameVersion2006 | Mac::Frame::kFcfDstAddrShort | Mac::Frame::kFcfSrcAddrShort |
Mac::Frame::kFcfPanidCompression | Mac::Frame::kFcfSecurityEnabled,
Mac::Frame::kSecMic32 | Mac::Frame::kKeyIdMode2, 19},
};