mirror of
https://github.com/espressif/openthread.git
synced 2026-08-08 03:37:46 +00:00
[posix-host] add posix parameter to get dataset from NCP and save to file (#4446)
There are cases when NCP platform was used at first. Then need to change to use RCP platform later. The PAN active and pending dataset needs to be retrieved from NCP firmware to avoid repairing again. This change, 1. Add one parameter to posix host (--ncp-dataset). 2. Avoid some radio spinel command and check so that posix app can start otInstance and talk to NCP firmware. 3. Utilize spinel property SPINEL_PROP_THREAD_ACTIVE_DATASET and SPINEL_PROP_THREAD_PENDING_DATASET to retrieve dataset from NCP.
This commit is contained in:
@@ -65,6 +65,10 @@ jobs:
|
||||
os: linux
|
||||
compiler: gcc
|
||||
script: .travis/script.sh
|
||||
- env: BUILD_TARGET="posix-app-migrate" VERBOSE=1 COVERAGE=1
|
||||
os: linux
|
||||
compiler: clang
|
||||
script: .travis/script.sh
|
||||
- env: BUILD_TARGET="android-build" VERBOSE=1
|
||||
os: linux
|
||||
dist: trusty
|
||||
|
||||
@@ -104,6 +104,10 @@ cd /tmp || die
|
||||
) || die
|
||||
}
|
||||
|
||||
[ $BUILD_TARGET != posix-app-migrate ] || {
|
||||
sudo apt-get install expect || die
|
||||
}
|
||||
|
||||
[ $BUILD_TARGET != arm-gcc-4 ] || {
|
||||
sudo apt-get install lib32z1 || die
|
||||
wget https://launchpad.net/gcc-arm-embedded/4.9/4.9-2015-q3-update/+download/gcc-arm-none-eabi-4_9-2015q3-20150921-linux.tar.bz2 || die
|
||||
|
||||
Executable
+142
@@ -0,0 +1,142 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) 2020, 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.
|
||||
#
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
at_exit() {
|
||||
EXIT_CODE=$?
|
||||
|
||||
killall expect || true
|
||||
killall ot-cli-ftd || true
|
||||
killall ot-cli || true
|
||||
killall ot-rcp || true
|
||||
|
||||
exit $EXIT_CODE
|
||||
}
|
||||
|
||||
build() {
|
||||
make -f examples/Makefile-posix
|
||||
make -f src/posix/Makefile-posix
|
||||
}
|
||||
|
||||
check() {
|
||||
trap at_exit INT TERM EXIT
|
||||
|
||||
rm -rf tmp/
|
||||
|
||||
PANID="0xc001"
|
||||
EXT_PANID="0123456789abcdef"
|
||||
NETWORK_NAME="OT_NCP_TO_RCP"
|
||||
CHANNEL="20"
|
||||
MASTER_KEY="0123456789abcdef0123456789abcdef"
|
||||
|
||||
echo "Step 1. Start NCP platform and form a PAN..."
|
||||
RADIO_NCP_CMD="$(pwd)/$(ls output/*linux*/bin/ot-cli-ftd)"
|
||||
|
||||
expect <<EOF
|
||||
spawn ${RADIO_NCP_CMD} 1
|
||||
set timeout 2
|
||||
expect_after {
|
||||
timeout { exit 1 }
|
||||
}
|
||||
send "panid ${PANID}\r\n"
|
||||
expect "Done"
|
||||
send "extpanid ${EXT_PANID}\r\n"
|
||||
expect "Done"
|
||||
send "networkname ${NETWORK_NAME}\r\n"
|
||||
expect "Done"
|
||||
send "channel ${CHANNEL}\r\n"
|
||||
expect "Done"
|
||||
send "masterkey ${MASTER_KEY}\r\n"
|
||||
expect "Done"
|
||||
send "ifconfig up\r\n"
|
||||
expect "Done"
|
||||
send "thread start\r\n"
|
||||
expect "Done"
|
||||
sleep 5
|
||||
send "state\r\n"
|
||||
expect "leader"
|
||||
expect "Done"
|
||||
send "exit\r\n"
|
||||
expect eof
|
||||
EOF
|
||||
|
||||
echo "Step 2. Start retrieving dataset from Radio..."
|
||||
RADIO_NCP_PATH="$(pwd)/$(ls output/*linux*/bin/ot-ncp-ftd)"
|
||||
"$(pwd)/$(ls output/posix/*linux*/bin/ot-ncp)" -n --radio-version --ncp-dataset -- ${RADIO_NCP_PATH} 1
|
||||
|
||||
echo "Step 3. Start posix app and check whether PAN dataset is the same..."
|
||||
RADIO_RCP_PATH="$(pwd)/$(ls output/*linux*/bin/ot-rcp)"
|
||||
|
||||
OT_CLI_CMD="$(pwd)/$(ls output/posix/*linux*/bin/ot-cli) ${RADIO_RCP_PATH} 1"
|
||||
|
||||
expect <<EOF
|
||||
spawn ${OT_CLI_CMD}
|
||||
set timeout 2
|
||||
expect_after {
|
||||
timeout { exit 1 }
|
||||
}
|
||||
send "panid\r\n"
|
||||
expect ${PANID}
|
||||
expect "Done"
|
||||
send "extpanid\r\n"
|
||||
expect ${EXT_PANID}
|
||||
expect "Done"
|
||||
send "networkname\r\n"
|
||||
expect ${NETWORK_NAME}
|
||||
expect "Done"
|
||||
send "channel\r\n"
|
||||
expect ${CHANNEL}
|
||||
expect "Done"
|
||||
send "masterkey\r\n"
|
||||
expect ${MASTER_KEY}
|
||||
expect "Done"
|
||||
send "exit\r\n"
|
||||
expect eof
|
||||
EOF
|
||||
|
||||
echo "Step 4. Start posix app and check whether it can get radio firmware version..."
|
||||
RADIO_VERSION="$("$(pwd)/$(ls output/posix/*linux*/bin/ot-cli)" -n --radio-version --ncp-dataset -- ${RADIO_RCP_PATH} 1)" || true
|
||||
test -n "{RADIO_VERSION}"
|
||||
}
|
||||
|
||||
main() {
|
||||
case "$1" in
|
||||
check)
|
||||
check
|
||||
;;
|
||||
*)
|
||||
build
|
||||
check
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -601,6 +601,11 @@ build_samr21() {
|
||||
.travis/check-posix-app-pty || die
|
||||
}
|
||||
|
||||
[ $BUILD_TARGET != posix-app-migrate ] || {
|
||||
./bootstrap
|
||||
.travis/check-ncp-rcp-migrate || die
|
||||
}
|
||||
|
||||
[ $BUILD_TARGET != posix-mtd ] || {
|
||||
./bootstrap || die
|
||||
REFERENCE_DEVICE=1 COVERAGE=1 CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32 USE_MTD=1 make -f examples/Makefile-posix check || die
|
||||
|
||||
@@ -52,9 +52,10 @@ extern "C" {
|
||||
*
|
||||
*/
|
||||
|
||||
#define OT_IP6_PREFIX_SIZE 8 ///< Size of an IPv6 prefix (bytes)
|
||||
#define OT_IP6_IID_SIZE 8 ///< Size of an IPv6 Interface Identifier (bytes)
|
||||
#define OT_IP6_ADDRESS_SIZE 16 ///< Size of an IPv6 address (bytes)
|
||||
#define OT_IP6_PREFIX_SIZE 8 ///< Size of an IPv6 prefix (bytes)
|
||||
#define OT_IP6_PREFIX_BITSIZE (OT_IP6_PREFIX_SIZE * 8) ///< Size of an IPv6 prefix (bits)
|
||||
#define OT_IP6_IID_SIZE 8 ///< Size of an IPv6 Interface Identifier (bytes)
|
||||
#define OT_IP6_ADDRESS_SIZE 16 ///< Size of an IPv6 address (bytes)
|
||||
|
||||
/**
|
||||
* @struct otIp6Address
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
|
||||
#include "common/locator.hpp"
|
||||
#include "mac/mac_types.hpp"
|
||||
#include "thread/mle.hpp"
|
||||
#if OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE
|
||||
#include "utils/slaac_address.hpp"
|
||||
#endif
|
||||
@@ -136,7 +135,6 @@ public:
|
||||
uint8_t mMode; ///< The MLE device mode
|
||||
};
|
||||
|
||||
protected:
|
||||
/**
|
||||
* This enumeration defines the keys of settings.
|
||||
*
|
||||
@@ -152,6 +150,7 @@ protected:
|
||||
kKeySlaacIidSecretKey = 0x0007, ///< Secret key used by SLAAC module for generating semantically opaque IID
|
||||
};
|
||||
|
||||
protected:
|
||||
explicit SettingsBase(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
{
|
||||
|
||||
@@ -1034,8 +1034,8 @@ otError NcpBase::EncodeOperationalDataset(const otOperationalDataset &aDataset)
|
||||
|
||||
SuccessOrExit(mEncoder.OpenStruct());
|
||||
SuccessOrExit(mEncoder.WriteUintPacked(SPINEL_PROP_IPV6_ML_PREFIX));
|
||||
SuccessOrExit(error = mEncoder.WriteIp6Address(addr)); // Mesh local prefix
|
||||
SuccessOrExit(error = mEncoder.WriteUint8(64)); // Prefix length (in bits)
|
||||
SuccessOrExit(error = mEncoder.WriteIp6Address(addr)); // Mesh local prefix
|
||||
SuccessOrExit(error = mEncoder.WriteUint8(OT_IP6_PREFIX_BITSIZE)); // Prefix length (in bits)
|
||||
SuccessOrExit(mEncoder.CloseStruct());
|
||||
}
|
||||
|
||||
@@ -1223,7 +1223,7 @@ otError NcpBase::DecodeOperationalDataset(otOperationalDataset &aDataset,
|
||||
|
||||
SuccessOrExit(error = mDecoder.ReadIp6Address(addr));
|
||||
SuccessOrExit(error = mDecoder.ReadUint8(prefixLen));
|
||||
VerifyOrExit(prefixLen == 64, error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrExit(prefixLen == OT_IP6_PREFIX_BITSIZE, error = OT_ERROR_INVALID_ARGS);
|
||||
memcpy(aDataset.mMeshLocalPrefix.m8, addr, OT_MESH_LOCAL_PREFIX_SIZE);
|
||||
}
|
||||
|
||||
@@ -1557,8 +1557,8 @@ template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_IPV6_ML_PREFIX>(void)
|
||||
// Zero out the last 8 bytes.
|
||||
memset(addr.mFields.m8 + 8, 0, 8);
|
||||
|
||||
SuccessOrExit(error = mEncoder.WriteIp6Address(addr)); // Mesh local prefix
|
||||
SuccessOrExit(error = mEncoder.WriteUint8(64)); // Prefix length (in bits)
|
||||
SuccessOrExit(error = mEncoder.WriteIp6Address(addr)); // Mesh local prefix
|
||||
SuccessOrExit(error = mEncoder.WriteUint8(OT_IP6_PREFIX_BITSIZE)); // Prefix length (in bits)
|
||||
|
||||
exit:
|
||||
return error;
|
||||
@@ -1572,7 +1572,7 @@ template <> otError NcpBase::HandlePropertySet<SPINEL_PROP_IPV6_ML_PREFIX>(void)
|
||||
|
||||
SuccessOrExit(error = mDecoder.ReadIp6Address(meshLocalPrefix));
|
||||
SuccessOrExit(error = mDecoder.ReadUint8(prefixLength));
|
||||
VerifyOrExit(prefixLength == 64, error = OT_ERROR_INVALID_ARGS);
|
||||
VerifyOrExit(prefixLength == OT_IP6_PREFIX_BITSIZE, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
error = otThreadSetMeshLocalPrefix(mInstance, reinterpret_cast<const otMeshLocalPrefix *>(meshLocalPrefix));
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ static const struct option kOptions[] = {{"debug-level", required_argument, NULL
|
||||
{"radio-version", no_argument, NULL, 0},
|
||||
{"time-speed", required_argument, NULL, 's'},
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
{"ncp-dataset", no_argument, NULL, 0},
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
static void PrintUsage(const char *aProgramName, FILE *aStream, int aExitCode)
|
||||
@@ -111,6 +112,7 @@ static void PrintUsage(const char *aProgramName, FILE *aStream, int aExitCode)
|
||||
" -n --dry-run Just verify if arguments is valid and radio spinel is compatible.\n"
|
||||
" --no-reset Do not reset RCP on initialization\n"
|
||||
" --radio-version Print radio firmware version\n"
|
||||
" --ncp-dataset Retrieve and save NCP dataset to file\n"
|
||||
" -s --time-speed factor Time speed up factor.\n"
|
||||
" -v --verbose Also log to stderr.\n"
|
||||
" -h --help Display this usage information.\n",
|
||||
@@ -178,6 +180,10 @@ static void ParseArg(int aArgCount, char *aArgVector[], PosixConfig *aConfig)
|
||||
{
|
||||
aConfig->mPlatformConfig.mResetRadio = false;
|
||||
}
|
||||
else if (!strcmp(kOptions[index].name, "ncp-dataset"))
|
||||
{
|
||||
aConfig->mPlatformConfig.mRestoreDatasetFromNcp = true;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
PrintUsage(aArgVector[0], stderr, OT_EXIT_INVALID_ARGUMENTS);
|
||||
|
||||
@@ -68,4 +68,5 @@ target_include_directories(openthread-posix PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/src
|
||||
${PROJECT_SOURCE_DIR}/src/core
|
||||
${PROJECT_SOURCE_DIR}/src/posix/platform
|
||||
${PROJECT_SOURCE_DIR}/third_party/mbedtls/repo/include
|
||||
)
|
||||
|
||||
@@ -90,12 +90,13 @@ enum
|
||||
*/
|
||||
typedef struct otPlatformConfig
|
||||
{
|
||||
uint64_t mNodeId; ///< Unique node ID.
|
||||
uint32_t mSpeedUpFactor; ///< Speed up factor.
|
||||
const char *mInterfaceName; ///< Thread network interface name.
|
||||
const char *mRadioFile; ///< Radio file path.
|
||||
const char *mRadioConfig; ///< Radio configurations.
|
||||
bool mResetRadio; ///< Whether to reset RCP when initializing.
|
||||
uint64_t mNodeId; ///< Unique node ID.
|
||||
uint32_t mSpeedUpFactor; ///< Speed up factor.
|
||||
const char *mInterfaceName; ///< Thread network interface name.
|
||||
const char *mRadioFile; ///< Radio file path.
|
||||
const char *mRadioConfig; ///< Radio configurations.
|
||||
bool mResetRadio; ///< Whether to reset RCP when initializing.
|
||||
bool mRestoreDatasetFromNcp; ///< Whether to retrieve dataset from NCP and save to file.
|
||||
} otPlatformConfig;
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
#include "platform-posix.h"
|
||||
#include "ncp/spinel_decoder.hpp"
|
||||
|
||||
#include "radio_spinel.hpp"
|
||||
|
||||
@@ -52,9 +53,14 @@
|
||||
#include <common/encoding.hpp>
|
||||
#include <common/logging.hpp>
|
||||
#include <common/new.hpp>
|
||||
#include <common/settings.hpp>
|
||||
#include <meshcop/dataset.hpp>
|
||||
#include <meshcop/meshcop_tlvs.hpp>
|
||||
#include <openthread/dataset.h>
|
||||
#include <openthread/platform/alarm-milli.h>
|
||||
#include <openthread/platform/diag.h>
|
||||
#include <openthread/platform/radio.h>
|
||||
#include <openthread/platform/settings.h>
|
||||
|
||||
#ifndef TX_WAIT_US
|
||||
#define TX_WAIT_US (5 * US_PER_S)
|
||||
@@ -184,6 +190,7 @@ RadioSpinel::RadioSpinel(void)
|
||||
void RadioSpinel::Init(const otPlatformConfig &aPlatformConfig)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
bool isRcp;
|
||||
|
||||
SuccessOrExit(error = mHdlcInterface.Init(aPlatformConfig));
|
||||
|
||||
@@ -196,14 +203,19 @@ void RadioSpinel::Init(const otPlatformConfig &aPlatformConfig)
|
||||
VerifyOrExit(mIsReady, error = OT_ERROR_FAILED);
|
||||
|
||||
SuccessOrExit(error = CheckSpinelVersion());
|
||||
SuccessOrExit(error = CheckCapabilities());
|
||||
SuccessOrExit(error = CheckRadioCapabilities());
|
||||
|
||||
SuccessOrExit(error = CheckCapabilities(isRcp));
|
||||
SuccessOrExit(error = Get(SPINEL_PROP_NCP_VERSION, SPINEL_DATATYPE_UTF8_S, mVersion, sizeof(mVersion)));
|
||||
SuccessOrExit(error = Get(SPINEL_PROP_HWADDR, SPINEL_DATATYPE_UINT64_S, &gNodeId));
|
||||
|
||||
gNodeId = ot::Encoding::BigEndian::HostSwap64(gNodeId);
|
||||
|
||||
if (aPlatformConfig.mRestoreDatasetFromNcp && !isRcp)
|
||||
{
|
||||
DieNow((RestoreDatasetFromNcp() == OT_ERROR_NONE) ? OT_EXIT_SUCCESS : OT_EXIT_FAILURE);
|
||||
}
|
||||
|
||||
SuccessOrExit(error = CheckRadioCapabilities());
|
||||
|
||||
mRxRadioFrame.mPsdu = mRxPsdu;
|
||||
mTxRadioFrame.mPsdu = mTxPsdu;
|
||||
mAckRadioFrame.mPsdu = mAckPsdu;
|
||||
@@ -234,7 +246,7 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError RadioSpinel::CheckCapabilities(void)
|
||||
otError RadioSpinel::CheckCapabilities(bool &aIsRcp)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
uint8_t capsBuffer[kCapsBufferSize];
|
||||
@@ -244,6 +256,8 @@ otError RadioSpinel::CheckCapabilities(void)
|
||||
|
||||
SuccessOrExit(error = Get(SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, capsBuffer, &capsLength));
|
||||
|
||||
aIsRcp = false;
|
||||
|
||||
while (capsLength > 0)
|
||||
{
|
||||
unsigned int capability;
|
||||
@@ -262,11 +276,16 @@ otError RadioSpinel::CheckCapabilities(void)
|
||||
supportsRawRadio = true;
|
||||
}
|
||||
|
||||
if (capability == SPINEL_CAP_CONFIG_RADIO)
|
||||
{
|
||||
aIsRcp = true;
|
||||
}
|
||||
|
||||
capsData += unpacked;
|
||||
capsLength -= static_cast<spinel_size_t>(unpacked);
|
||||
}
|
||||
|
||||
if (!supportsRawRadio)
|
||||
if (!supportsRawRadio && aIsRcp)
|
||||
{
|
||||
otLogCritPlat("RCP capability list does not include support for radio/raw mode");
|
||||
DieNow(OT_EXIT_RADIO_SPINEL_INCOMPATIBLE);
|
||||
@@ -301,6 +320,23 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError RadioSpinel::RestoreDatasetFromNcp(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
otPlatSettingsInit(mInstance);
|
||||
|
||||
otLogInfoPlat("Trying to get saved dataset from NCP");
|
||||
SuccessOrExit(
|
||||
error = Get(SPINEL_PROP_THREAD_ACTIVE_DATASET, SPINEL_DATATYPE_VOID_S, &RadioSpinel::ThreadDatasetHandler));
|
||||
SuccessOrExit(
|
||||
error = Get(SPINEL_PROP_THREAD_PENDING_DATASET, SPINEL_DATATYPE_VOID_S, &RadioSpinel::ThreadDatasetHandler));
|
||||
|
||||
exit:
|
||||
otPlatSettingsDeinit(mInstance);
|
||||
return error;
|
||||
}
|
||||
|
||||
void RadioSpinel::Deinit(void)
|
||||
{
|
||||
mHdlcInterface.Deinit();
|
||||
@@ -452,6 +488,159 @@ exit:
|
||||
LogIfFail("Error processing response", error);
|
||||
}
|
||||
|
||||
otError RadioSpinel::ThreadDatasetHandler(const uint8_t *aBuffer, uint16_t aLength)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
otOperationalDataset opDataset;
|
||||
bool isActive = ((mWaitingKey == SPINEL_PROP_THREAD_ACTIVE_DATASET) ? true : false);
|
||||
Ncp::SpinelDecoder decoder;
|
||||
MeshCoP::Dataset dataset(isActive ? MeshCoP::Tlv::kActiveTimestamp : MeshCoP::Tlv::kPendingTimestamp);
|
||||
|
||||
memset(&opDataset, 0, sizeof(otOperationalDataset));
|
||||
decoder.Init(aBuffer, aLength);
|
||||
|
||||
while (!decoder.IsAllReadInStruct())
|
||||
{
|
||||
unsigned int propKey;
|
||||
|
||||
SuccessOrExit(error = decoder.OpenStruct());
|
||||
SuccessOrExit(error = decoder.ReadUintPacked(propKey));
|
||||
|
||||
switch (static_cast<spinel_prop_key_t>(propKey))
|
||||
{
|
||||
case SPINEL_PROP_NET_MASTER_KEY:
|
||||
{
|
||||
const uint8_t *key;
|
||||
uint16_t len;
|
||||
|
||||
SuccessOrExit(error = decoder.ReadData(key, len));
|
||||
VerifyOrExit(len == OT_MASTER_KEY_SIZE, error = OT_ERROR_INVALID_ARGS);
|
||||
memcpy(opDataset.mMasterKey.m8, key, len);
|
||||
opDataset.mComponents.mIsMasterKeyPresent = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPINEL_PROP_NET_NETWORK_NAME:
|
||||
{
|
||||
const char *name;
|
||||
size_t len;
|
||||
|
||||
SuccessOrExit(error = decoder.ReadUtf8(name));
|
||||
len = strnlen(name, OT_NETWORK_NAME_MAX_SIZE);
|
||||
memcpy(opDataset.mNetworkName.m8, name, len);
|
||||
opDataset.mNetworkName.m8[len] = '\0';
|
||||
opDataset.mComponents.mIsNetworkNamePresent = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPINEL_PROP_NET_XPANID:
|
||||
{
|
||||
const uint8_t *xpanid;
|
||||
uint16_t len;
|
||||
|
||||
SuccessOrExit(error = decoder.ReadData(xpanid, len));
|
||||
VerifyOrExit(len == OT_EXT_PAN_ID_SIZE, error = OT_ERROR_INVALID_ARGS);
|
||||
memcpy(opDataset.mExtendedPanId.m8, xpanid, len);
|
||||
opDataset.mComponents.mIsExtendedPanIdPresent = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPINEL_PROP_IPV6_ML_PREFIX:
|
||||
{
|
||||
const otIp6Address *addr;
|
||||
uint8_t prefixLen;
|
||||
|
||||
SuccessOrExit(error = decoder.ReadIp6Address(addr));
|
||||
SuccessOrExit(error = decoder.ReadUint8(prefixLen));
|
||||
VerifyOrExit(prefixLen == OT_IP6_PREFIX_BITSIZE, error = OT_ERROR_INVALID_ARGS);
|
||||
memcpy(opDataset.mMeshLocalPrefix.m8, addr, OT_MESH_LOCAL_PREFIX_SIZE);
|
||||
opDataset.mComponents.mIsMeshLocalPrefixPresent = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPINEL_PROP_DATASET_DELAY_TIMER:
|
||||
{
|
||||
SuccessOrExit(error = decoder.ReadUint32(opDataset.mDelay));
|
||||
opDataset.mComponents.mIsDelayPresent = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPINEL_PROP_MAC_15_4_PANID:
|
||||
{
|
||||
SuccessOrExit(error = decoder.ReadUint16(opDataset.mPanId));
|
||||
opDataset.mComponents.mIsPanIdPresent = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPINEL_PROP_PHY_CHAN:
|
||||
{
|
||||
uint8_t channel;
|
||||
|
||||
SuccessOrExit(error = decoder.ReadUint8(channel));
|
||||
opDataset.mChannel = channel;
|
||||
opDataset.mComponents.mIsChannelPresent = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPINEL_PROP_NET_PSKC:
|
||||
{
|
||||
const uint8_t *psk;
|
||||
uint16_t len;
|
||||
|
||||
SuccessOrExit(error = decoder.ReadData(psk, len));
|
||||
VerifyOrExit(len == OT_PSKC_MAX_SIZE, error = OT_ERROR_INVALID_ARGS);
|
||||
memcpy(opDataset.mPskc.m8, psk, OT_PSKC_MAX_SIZE);
|
||||
opDataset.mComponents.mIsPskcPresent = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPINEL_PROP_DATASET_SECURITY_POLICY:
|
||||
{
|
||||
SuccessOrExit(error = decoder.ReadUint16(opDataset.mSecurityPolicy.mRotationTime));
|
||||
SuccessOrExit(error = decoder.ReadUint8(opDataset.mSecurityPolicy.mFlags));
|
||||
opDataset.mComponents.mIsSecurityPolicyPresent = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SPINEL_PROP_PHY_CHAN_SUPPORTED:
|
||||
{
|
||||
uint8_t channel;
|
||||
|
||||
opDataset.mChannelMask = 0;
|
||||
|
||||
while (!decoder.IsAllReadInStruct())
|
||||
{
|
||||
SuccessOrExit(error = decoder.ReadUint8(channel));
|
||||
VerifyOrExit(channel <= 31, error = OT_ERROR_INVALID_ARGS);
|
||||
opDataset.mChannelMask |= (1UL << channel);
|
||||
}
|
||||
opDataset.mComponents.mIsChannelMaskPresent = true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
SuccessOrExit(error = decoder.CloseStruct());
|
||||
}
|
||||
|
||||
/*
|
||||
* Initially set Active Timestamp to 0. This is to allow the node to join the network
|
||||
* yet retrieve the full Active Dataset from a neighboring device if one exists.
|
||||
*/
|
||||
opDataset.mActiveTimestamp = 0;
|
||||
opDataset.mComponents.mIsActiveTimestampPresent = true;
|
||||
|
||||
SuccessOrExit(error = dataset.Set(opDataset));
|
||||
SuccessOrExit(error = otPlatSettingsSet(
|
||||
mInstance, isActive ? SettingsBase::kKeyActiveDataset : SettingsBase::kKeyPendingDataset,
|
||||
dataset.GetBytes(), dataset.GetSize()));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void RadioSpinel::HandleWaitingResponse(uint32_t aCommand,
|
||||
spinel_prop_key_t aKey,
|
||||
const uint8_t * aBuffer,
|
||||
@@ -480,11 +669,22 @@ void RadioSpinel::HandleWaitingResponse(uint32_t aCommand,
|
||||
{
|
||||
if (mPropertyFormat)
|
||||
{
|
||||
spinel_ssize_t unpacked =
|
||||
spinel_datatype_vunpack_in_place(aBuffer, aLength, mPropertyFormat, mPropertyArgs);
|
||||
if (static_cast<spinel_datatype_t>(mPropertyFormat[0]) == SPINEL_DATATYPE_VOID_C)
|
||||
{
|
||||
// reserved SPINEL_DATATYPE_VOID_C indicate caller want to parse the spinel response itself
|
||||
ResponseHandler handler = va_arg(mPropertyArgs, ResponseHandler);
|
||||
|
||||
VerifyOrExit(unpacked > 0, mError = OT_ERROR_PARSE);
|
||||
mError = OT_ERROR_NONE;
|
||||
assert(handler != NULL);
|
||||
mError = (this->*handler)(aBuffer, aLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
spinel_ssize_t unpacked =
|
||||
spinel_datatype_vunpack_in_place(aBuffer, aLength, mPropertyFormat, mPropertyArgs);
|
||||
|
||||
VerifyOrExit(unpacked > 0, mError = OT_ERROR_PARSE);
|
||||
mError = OT_ERROR_NONE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -538,8 +538,10 @@ private:
|
||||
kStateTransmitDone, ///< Radio indicated frame transmission is done.
|
||||
};
|
||||
|
||||
typedef otError (RadioSpinel::*ResponseHandler)(const uint8_t *aBuffer, uint16_t aLength);
|
||||
|
||||
otError CheckSpinelVersion(void);
|
||||
otError CheckCapabilities(void);
|
||||
otError CheckCapabilities(bool &aIsRcp);
|
||||
otError CheckRadioCapabilities(void);
|
||||
void ProcessFrameQueue(void);
|
||||
|
||||
@@ -612,6 +614,7 @@ private:
|
||||
const char * pack_format,
|
||||
va_list args);
|
||||
otError ParseRadioFrame(otRadioFrame &aFrame, const uint8_t *aBuffer, uint16_t aLength);
|
||||
otError ThreadDatasetHandler(const uint8_t *aBuffer, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* This method returns if the property changed event is safe to be handled now.
|
||||
@@ -641,6 +644,17 @@ private:
|
||||
|
||||
void TransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError);
|
||||
|
||||
/**
|
||||
* This method gets dataset from NCP radio and saves it.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully restore dataset.
|
||||
* @retval OT_ERROR_BUSY Failed due to another operation is on going.
|
||||
* @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver.
|
||||
* @retval OT_ERROR_NOT_FOUND Failed due to spinel property not supported in radio.
|
||||
* @retval OT_ERROR_FAILED Failed due to other reasons.
|
||||
*/
|
||||
otError RestoreDatasetFromNcp(void);
|
||||
|
||||
otInstance *mInstance;
|
||||
|
||||
HdlcInterface mHdlcInterface;
|
||||
|
||||
Reference in New Issue
Block a user