blob: 666dfc8708c2fb8a2b97b5a1fbbd29a56ab9e846 [file] [log] [blame]
/*
* Copyright (c) 2016, 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 top-level interface to the OpenThread stack.
*/
#ifdef OPENTHREAD_CONFIG_FILE
#include OPENTHREAD_CONFIG_FILE
#else
#include <openthread-config.h>
#endif
#include <openthread.h>
#include <common/code_utils.hpp>
#include <common/debug.hpp>
#include <common/logging.hpp>
#include <common/message.hpp>
#include <common/new.hpp>
#include <common/tasklet.hpp>
#include <common/timer.hpp>
#include <crypto/mbedtls.hpp>
#include <net/icmp6.hpp>
#include <net/ip6.hpp>
#include <platform/random.h>
#include <platform/misc.h>
#include <thread/thread_netif.hpp>
#include <thread/thread_uris.hpp>
// Temporary definition
typedef struct otInstance
{
} otInstance;
namespace Thread {
// This needs to not be static until the NCP
// the OpenThread API is capable enough for
// of of the features in the NCP.
ThreadNetif *sThreadNetif;
#ifndef OPENTHREAD_MULTIPLE_INSTANCE
static otDEFINE_ALIGNED_VAR(sInstanceRaw, sizeof(otInstance), uint64_t);
otInstance *sInstance = NULL;
#endif
static Ip6::NetifCallback sNetifCallback;
static otDEFINE_ALIGNED_VAR(sMbedTlsRaw, sizeof(Crypto::MbedTls), uint64_t);
static otDEFINE_ALIGNED_VAR(sIp6Raw, sizeof(Ip6::Ip6), uint64_t);
Ip6::Ip6 *sIp6;
#ifdef __cplusplus
extern "C" {
#endif
static otDEFINE_ALIGNED_VAR(sThreadNetifRaw, sizeof(ThreadNetif), uint64_t);
static void HandleActiveScanResult(void *aContext, Mac::Frame *aFrame);
static void HandleEnergyScanResult(void *aContext, otEnergyScanResult *aResult);
static void HandleMleDiscover(otActiveScanResult *aResult, void *aContext);
static otHandleActiveScanResult sActiveScanCallback = NULL;
static void *sActiveScanCallbackContext = NULL;
static otHandleEnergyScanResult sEnergyScanCallback = NULL;
static void *sEnergyScanCallbackContext = NULL;
static otHandleActiveScanResult sDiscoverCallback = NULL;
static void *sDiscoverCallbackContext = NULL;
void otProcessNextTasklet(otInstance *)
{
sIp6->mTaskletScheduler.RunNextTasklet();
}
bool otAreTaskletsPending(otInstance *)
{
return sIp6->mTaskletScheduler.AreTaskletsPending();
}
uint8_t otGetChannel(otInstance *)
{
return sThreadNetif->GetMac().GetChannel();
}
ThreadError otSetChannel(otInstance *, uint8_t aChannel)
{
return sThreadNetif->GetMac().SetChannel(aChannel);
}
uint8_t otGetMaxAllowedChildren(otInstance *)
{
uint8_t aNumChildren;
(void)sThreadNetif->GetMle().GetChildren(&aNumChildren);
return aNumChildren;
}
ThreadError otSetMaxAllowedChildren(otInstance *, uint8_t aMaxChildren)
{
return sThreadNetif->GetMle().SetMaxAllowedChildren(aMaxChildren);
}
uint32_t otGetChildTimeout(otInstance *)
{
return sThreadNetif->GetMle().GetTimeout();
}
void otSetChildTimeout(otInstance *, uint32_t aTimeout)
{
sThreadNetif->GetMle().SetTimeout(aTimeout);
}
const uint8_t *otGetExtendedAddress(otInstance *)
{
return reinterpret_cast<const uint8_t *>(sThreadNetif->GetMac().GetExtAddress());
}
ThreadError otSetExtendedAddress(otInstance *, const otExtAddress *aExtAddress)
{
ThreadError error = kThreadError_None;
VerifyOrExit(aExtAddress != NULL, error = kThreadError_InvalidArgs);
SuccessOrExit(error = sThreadNetif->GetMac().SetExtAddress(*static_cast<const Mac::ExtAddress *>(aExtAddress)));
SuccessOrExit(error = sThreadNetif->GetMle().UpdateLinkLocalAddress());
exit:
return error;
}
const uint8_t *otGetExtendedPanId(otInstance *)
{
return sThreadNetif->GetMac().GetExtendedPanId();
}
void otSetExtendedPanId(otInstance *, const uint8_t *aExtendedPanId)
{
uint8_t mlPrefix[8];
sThreadNetif->GetMac().SetExtendedPanId(aExtendedPanId);
mlPrefix[0] = 0xfd;
memcpy(mlPrefix + 1, aExtendedPanId, 5);
mlPrefix[6] = 0x00;
mlPrefix[7] = 0x00;
sThreadNetif->GetMle().SetMeshLocalPrefix(mlPrefix);
}
void otGetFactoryAssignedIeeeEui64(otInstance *aInstance, otExtAddress *aEui64)
{
otPlatRadioGetIeeeEui64(aInstance, aEui64->m8);
}
void otGetHashMacAddress(otInstance *, otExtAddress *aHashMacAddress)
{
sThreadNetif->GetMac().GetHashMacAddress(static_cast<Mac::ExtAddress *>(aHashMacAddress));
}
ThreadError otGetLeaderRloc(otInstance *, otIp6Address *aAddress)
{
ThreadError error;
VerifyOrExit(aAddress != NULL, error = kThreadError_InvalidArgs);
error = sThreadNetif->GetMle().GetLeaderAddress(*static_cast<Ip6::Address *>(aAddress));
exit:
return error;
}
otLinkModeConfig otGetLinkMode(otInstance *)
{
otLinkModeConfig config;
uint8_t mode = sThreadNetif->GetMle().GetDeviceMode();
memset(&config, 0, sizeof(otLinkModeConfig));
if (mode & Mle::ModeTlv::kModeRxOnWhenIdle)
{
config.mRxOnWhenIdle = 1;
}
if (mode & Mle::ModeTlv::kModeSecureDataRequest)
{
config.mSecureDataRequests = 1;
}
if (mode & Mle::ModeTlv::kModeFFD)
{
config.mDeviceType = 1;
}
if (mode & Mle::ModeTlv::kModeFullNetworkData)
{
config.mNetworkData = 1;
}
return config;
}
ThreadError otSetLinkMode(otInstance *, otLinkModeConfig aConfig)
{
uint8_t mode = 0;
if (aConfig.mRxOnWhenIdle)
{
mode |= Mle::ModeTlv::kModeRxOnWhenIdle;
}
if (aConfig.mSecureDataRequests)
{
mode |= Mle::ModeTlv::kModeSecureDataRequest;
}
if (aConfig.mDeviceType)
{
mode |= Mle::ModeTlv::kModeFFD;
}
if (aConfig.mNetworkData)
{
mode |= Mle::ModeTlv::kModeFullNetworkData;
}
return sThreadNetif->GetMle().SetDeviceMode(mode);
}
const uint8_t *otGetMasterKey(otInstance *, uint8_t *aKeyLength)
{
return sThreadNetif->GetKeyManager().GetMasterKey(aKeyLength);
}
ThreadError otSetMasterKey(otInstance *, const uint8_t *aKey, uint8_t aKeyLength)
{
return sThreadNetif->GetKeyManager().SetMasterKey(aKey, aKeyLength);
}
int8_t otGetMaxTransmitPower(otInstance *)
{
return sThreadNetif->GetMac().GetMaxTransmitPower();
}
void otSetMaxTransmitPower(otInstance *, int8_t aPower)
{
sThreadNetif->GetMac().SetMaxTransmitPower(aPower);
}
const otIp6Address *otGetMeshLocalEid(otInstance *)
{
return sThreadNetif->GetMle().GetMeshLocal64();
}
const uint8_t *otGetMeshLocalPrefix(otInstance *)
{
return sThreadNetif->GetMle().GetMeshLocalPrefix();
}
ThreadError otSetMeshLocalPrefix(otInstance *, const uint8_t *aMeshLocalPrefix)
{
return sThreadNetif->GetMle().SetMeshLocalPrefix(aMeshLocalPrefix);
}
ThreadError otGetNetworkDataLeader(otInstance *, bool aStable, uint8_t *aData, uint8_t *aDataLength)
{
ThreadError error = kThreadError_None;
VerifyOrExit(aData != NULL && aDataLength != NULL, error = kThreadError_InvalidArgs);
sThreadNetif->GetNetworkDataLeader().GetNetworkData(aStable, aData, *aDataLength);
exit:
return error;
}
ThreadError otGetNetworkDataLocal(otInstance *, bool aStable, uint8_t *aData, uint8_t *aDataLength)
{
ThreadError error = kThreadError_None;
VerifyOrExit(aData != NULL && aDataLength != NULL, error = kThreadError_InvalidArgs);
sThreadNetif->GetNetworkDataLocal().GetNetworkData(aStable, aData, *aDataLength);
exit:
return error;
}
const char *otGetNetworkName(otInstance *)
{
return sThreadNetif->GetMac().GetNetworkName();
}
ThreadError otSetNetworkName(otInstance *, const char *aNetworkName)
{
return sThreadNetif->GetMac().SetNetworkName(aNetworkName);
}
otPanId otGetPanId(otInstance *)
{
return sThreadNetif->GetMac().GetPanId();
}
ThreadError otSetPanId(otInstance *, otPanId aPanId)
{
ThreadError error = kThreadError_None;
// do not allow setting PAN ID to broadcast if Thread is running
VerifyOrExit(aPanId != Mac::kPanIdBroadcast ||
sThreadNetif->GetMle().GetDeviceState() != Mle::kDeviceStateDisabled,
error = kThreadError_InvalidState);
error = sThreadNetif->GetMac().SetPanId(aPanId);
exit:
return error;
}
bool otIsRouterRoleEnabled(otInstance *)
{
return sThreadNetif->GetMle().IsRouterRoleEnabled();
}
void otSetRouterRoleEnabled(otInstance *, bool aEnabled)
{
sThreadNetif->GetMle().SetRouterRoleEnabled(aEnabled);
}
otShortAddress otGetShortAddress(otInstance *)
{
return sThreadNetif->GetMac().GetShortAddress();
}
uint8_t otGetLocalLeaderWeight(otInstance *)
{
return sThreadNetif->GetMle().GetLeaderWeight();
}
void otSetLocalLeaderWeight(otInstance *, uint8_t aWeight)
{
sThreadNetif->GetMle().SetLeaderWeight(aWeight);
}
uint32_t otGetLocalLeaderPartitionId(otInstance *)
{
return sThreadNetif->GetMle().GetLeaderPartitionId();
}
void otSetLocalLeaderPartitionId(otInstance *, uint32_t aPartitionId)
{
return sThreadNetif->GetMle().SetLeaderPartitionId(aPartitionId);
}
uint16_t otGetJoinerUdpPort(otInstance *)
{
return sThreadNetif->GetJoinerRouter().GetJoinerUdpPort();
}
ThreadError otSetJoinerUdpPort(otInstance *, uint16_t aJoinerUdpPort)
{
return sThreadNetif->GetJoinerRouter().SetJoinerUdpPort(aJoinerUdpPort);
}
ThreadError otAddBorderRouter(otInstance *, const otBorderRouterConfig *aConfig)
{
uint8_t flags = 0;
if (aConfig->mPreferred)
{
flags |= NetworkData::BorderRouterEntry::kPreferredFlag;
}
if (aConfig->mSlaac)
{
flags |= NetworkData::BorderRouterEntry::kSlaacFlag;
}
if (aConfig->mDhcp)
{
flags |= NetworkData::BorderRouterEntry::kDhcpFlag;
}
if (aConfig->mConfigure)
{
flags |= NetworkData::BorderRouterEntry::kConfigureFlag;
}
if (aConfig->mDefaultRoute)
{
flags |= NetworkData::BorderRouterEntry::kDefaultRouteFlag;
}
if (aConfig->mOnMesh)
{
flags |= NetworkData::BorderRouterEntry::kOnMeshFlag;
}
return sThreadNetif->GetNetworkDataLocal().AddOnMeshPrefix(aConfig->mPrefix.mPrefix.mFields.m8,
aConfig->mPrefix.mLength,
aConfig->mPreference, flags, aConfig->mStable);
}
ThreadError otRemoveBorderRouter(otInstance *, const otIp6Prefix *aPrefix)
{
return sThreadNetif->GetNetworkDataLocal().RemoveOnMeshPrefix(aPrefix->mPrefix.mFields.m8, aPrefix->mLength);
}
ThreadError otGetNextOnMeshPrefix(otInstance *, bool aLocal, otNetworkDataIterator *aIterator,
otBorderRouterConfig *aConfig)
{
ThreadError error = kThreadError_None;
VerifyOrExit(aIterator && aConfig, error = kThreadError_InvalidArgs);
if (aLocal)
{
error = sThreadNetif->GetNetworkDataLocal().GetNextOnMeshPrefix(aIterator, aConfig);
}
else
{
error = sThreadNetif->GetNetworkDataLeader().GetNextOnMeshPrefix(aIterator, aConfig);
}
exit:
return error;
}
ThreadError otAddExternalRoute(otInstance *, const otExternalRouteConfig *aConfig)
{
return sThreadNetif->GetNetworkDataLocal().AddHasRoutePrefix(aConfig->mPrefix.mPrefix.mFields.m8,
aConfig->mPrefix.mLength,
aConfig->mPreference, aConfig->mStable);
}
ThreadError otRemoveExternalRoute(otInstance *, const otIp6Prefix *aPrefix)
{
return sThreadNetif->GetNetworkDataLocal().RemoveHasRoutePrefix(aPrefix->mPrefix.mFields.m8, aPrefix->mLength);
}
ThreadError otSendServerData(otInstance *)
{
return sThreadNetif->GetNetworkDataLocal().SendServerDataNotification();
}
ThreadError otAddUnsecurePort(otInstance *, uint16_t aPort)
{
return sThreadNetif->GetIp6Filter().AddUnsecurePort(aPort);
}
ThreadError otRemoveUnsecurePort(otInstance *, uint16_t aPort)
{
return sThreadNetif->GetIp6Filter().RemoveUnsecurePort(aPort);
}
const uint16_t *otGetUnsecurePorts(otInstance *, uint8_t *aNumEntries)
{
return sThreadNetif->GetIp6Filter().GetUnsecurePorts(*aNumEntries);
}
uint32_t otGetContextIdReuseDelay(otInstance *)
{
return sThreadNetif->GetNetworkDataLeader().GetContextIdReuseDelay();
}
void otSetContextIdReuseDelay(otInstance *, uint32_t aDelay)
{
sThreadNetif->GetNetworkDataLeader().SetContextIdReuseDelay(aDelay);
}
uint32_t otGetKeySequenceCounter(otInstance *)
{
return sThreadNetif->GetKeyManager().GetCurrentKeySequence();
}
void otSetKeySequenceCounter(otInstance *, uint32_t aKeySequenceCounter)
{
sThreadNetif->GetKeyManager().SetCurrentKeySequence(aKeySequenceCounter);
}
uint8_t otGetNetworkIdTimeout(otInstance *)
{
return sThreadNetif->GetMle().GetNetworkIdTimeout();
}
void otSetNetworkIdTimeout(otInstance *, uint8_t aTimeout)
{
sThreadNetif->GetMle().SetNetworkIdTimeout(aTimeout);
}
uint8_t otGetRouterUpgradeThreshold(otInstance *)
{
return sThreadNetif->GetMle().GetRouterUpgradeThreshold();
}
void otSetRouterUpgradeThreshold(otInstance *, uint8_t aThreshold)
{
sThreadNetif->GetMle().SetRouterUpgradeThreshold(aThreshold);
}
ThreadError otReleaseRouterId(otInstance *, uint8_t aRouterId)
{
return sThreadNetif->GetMle().ReleaseRouterId(aRouterId);
}
ThreadError otAddMacWhitelist(otInstance *, const uint8_t *aExtAddr)
{
ThreadError error = kThreadError_None;
if (sThreadNetif->GetMac().GetWhitelist().Add(*reinterpret_cast<const Mac::ExtAddress *>(aExtAddr)) == NULL)
{
error = kThreadError_NoBufs;
}
return error;
}
ThreadError otAddMacWhitelistRssi(otInstance *, const uint8_t *aExtAddr, int8_t aRssi)
{
ThreadError error = kThreadError_None;
otMacWhitelistEntry *entry;
entry = sThreadNetif->GetMac().GetWhitelist().Add(*reinterpret_cast<const Mac::ExtAddress *>(aExtAddr));
VerifyOrExit(entry != NULL, error = kThreadError_NoBufs);
sThreadNetif->GetMac().GetWhitelist().SetFixedRssi(*entry, aRssi);
exit:
return error;
}
void otRemoveMacWhitelist(otInstance *, const uint8_t *aExtAddr)
{
sThreadNetif->GetMac().GetWhitelist().Remove(*reinterpret_cast<const Mac::ExtAddress *>(aExtAddr));
}
void otClearMacWhitelist(otInstance *)
{
sThreadNetif->GetMac().GetWhitelist().Clear();
}
ThreadError otGetMacWhitelistEntry(otInstance *, uint8_t aIndex, otMacWhitelistEntry *aEntry)
{
ThreadError error = kThreadError_None;
VerifyOrExit(aEntry != NULL, error = kThreadError_InvalidArgs);
error = sThreadNetif->GetMac().GetWhitelist().GetEntry(aIndex, *aEntry);
exit:
return error;
}
void otDisableMacWhitelist(otInstance *)
{
sThreadNetif->GetMac().GetWhitelist().Disable();
}
void otEnableMacWhitelist(otInstance *)
{
sThreadNetif->GetMac().GetWhitelist().Enable();
}
bool otIsMacWhitelistEnabled(otInstance *)
{
return sThreadNetif->GetMac().GetWhitelist().IsEnabled();
}
ThreadError otBecomeDetached(otInstance *)
{
return sThreadNetif->GetMle().BecomeDetached();
}
ThreadError otBecomeChild(otInstance *, otMleAttachFilter aFilter)
{
return sThreadNetif->GetMle().BecomeChild(aFilter);
}
ThreadError otBecomeRouter(otInstance *)
{
return sThreadNetif->GetMle().BecomeRouter(ThreadStatusTlv::kTooFewRouters);
}
ThreadError otBecomeLeader(otInstance *)
{
return sThreadNetif->GetMle().BecomeLeader();
}
ThreadError otAddMacBlacklist(otInstance *, const uint8_t *aExtAddr)
{
ThreadError error = kThreadError_None;
if (sThreadNetif->GetMac().GetBlacklist().Add(*reinterpret_cast<const Mac::ExtAddress *>(aExtAddr)) == NULL)
{
error = kThreadError_NoBufs;
}
return error;
}
void otRemoveMacBlacklist(otInstance *, const uint8_t *aExtAddr)
{
sThreadNetif->GetMac().GetBlacklist().Remove(*reinterpret_cast<const Mac::ExtAddress *>(aExtAddr));
}
void otClearMacBlacklist(otInstance *)
{
sThreadNetif->GetMac().GetBlacklist().Clear();
}
ThreadError otGetMacBlacklistEntry(otInstance *, uint8_t aIndex, otMacBlacklistEntry *aEntry)
{
ThreadError error = kThreadError_None;
VerifyOrExit(aEntry != NULL, error = kThreadError_InvalidArgs);
error = sThreadNetif->GetMac().GetBlacklist().GetEntry(aIndex, *aEntry);
exit:
return error;
}
void otDisableMacBlacklist(otInstance *)
{
sThreadNetif->GetMac().GetBlacklist().Disable();
}
void otEnableMacBlacklist(otInstance *)
{
sThreadNetif->GetMac().GetBlacklist().Enable();
}
bool otIsMacBlacklistEnabled(otInstance *)
{
return sThreadNetif->GetMac().GetBlacklist().IsEnabled();
}
ThreadError otGetAssignLinkQuality(otInstance *, const uint8_t *aExtAddr, uint8_t *aLinkQuality)
{
Mac::ExtAddress extAddress;
memset(&extAddress, 0, sizeof(extAddress));
memcpy(extAddress.m8, aExtAddr, OT_EXT_ADDRESS_SIZE);
return sThreadNetif->GetMle().GetAssignLinkQuality(extAddress, *aLinkQuality);
}
void otSetAssignLinkQuality(otInstance *, const uint8_t *aExtAddr, uint8_t aLinkQuality)
{
Mac::ExtAddress extAddress;
memset(&extAddress, 0, sizeof(extAddress));
memcpy(extAddress.m8, aExtAddr, OT_EXT_ADDRESS_SIZE);
sThreadNetif->GetMle().SetAssignLinkQuality(extAddress, aLinkQuality);
}
void otPlatformReset(otInstance *aInstance)
{
otPlatReset(aInstance);
}
uint8_t otGetRouterDowngradeThreshold(void)
{
return sThreadNetif->GetMle().GetRouterDowngradeThreshold();
}
void otSetRouterDowngradeThreshold(uint8_t aThreshold)
{
sThreadNetif->GetMle().SetRouterDowngradeThreshold(aThreshold);
}
ThreadError otGetChildInfoById(otInstance *, uint16_t aChildId, otChildInfo *aChildInfo)
{
ThreadError error = kThreadError_None;
VerifyOrExit(aChildInfo != NULL, error = kThreadError_InvalidArgs);
error = sThreadNetif->GetMle().GetChildInfoById(aChildId, *aChildInfo);
exit:
return error;
}
ThreadError otGetChildInfoByIndex(otInstance *, uint8_t aChildIndex, otChildInfo *aChildInfo)
{
ThreadError error = kThreadError_None;
VerifyOrExit(aChildInfo != NULL, error = kThreadError_InvalidArgs);
error = sThreadNetif->GetMle().GetChildInfoByIndex(aChildIndex, *aChildInfo);
exit:
return error;
}
otDeviceRole otGetDeviceRole(otInstance *)
{
otDeviceRole rval = kDeviceRoleDisabled;
switch (sThreadNetif->GetMle().GetDeviceState())
{
case Mle::kDeviceStateDisabled:
rval = kDeviceRoleDisabled;
break;
case Mle::kDeviceStateDetached:
rval = kDeviceRoleDetached;
break;
case Mle::kDeviceStateChild:
rval = kDeviceRoleChild;
break;
case Mle::kDeviceStateRouter:
rval = kDeviceRoleRouter;
break;
case Mle::kDeviceStateLeader:
rval = kDeviceRoleLeader;
break;
}
return rval;
}
ThreadError otGetEidCacheEntry(otInstance *, uint8_t aIndex, otEidCacheEntry *aEntry)
{
ThreadError error;
VerifyOrExit(aEntry != NULL, error = kThreadError_InvalidArgs);
error = sThreadNetif->GetAddressResolver().GetEntry(aIndex, *aEntry);
exit:
return error;
}
ThreadError otGetLeaderData(otInstance *, otLeaderData *aLeaderData)
{
ThreadError error;
VerifyOrExit(aLeaderData != NULL, error = kThreadError_InvalidArgs);
error = sThreadNetif->GetMle().GetLeaderData(*aLeaderData);
exit:
return error;
}
uint8_t otGetLeaderRouterId(otInstance *)
{
return sThreadNetif->GetMle().GetLeaderDataTlv().GetLeaderRouterId();
}
uint8_t otGetLeaderWeight(otInstance *)
{
return sThreadNetif->GetMle().GetLeaderDataTlv().GetWeighting();
}
uint8_t otGetNetworkDataVersion(otInstance *)
{
return sThreadNetif->GetMle().GetLeaderDataTlv().GetDataVersion();
}
uint32_t otGetPartitionId(otInstance *)
{
return sThreadNetif->GetMle().GetLeaderDataTlv().GetPartitionId();
}
uint16_t otGetRloc16(otInstance *)
{
return sThreadNetif->GetMle().GetRloc16();
}
uint8_t otGetRouterIdSequence(otInstance *)
{
return sThreadNetif->GetMle().GetRouterIdSequence();
}
ThreadError otGetRouterInfo(otInstance *, uint16_t aRouterId, otRouterInfo *aRouterInfo)
{
ThreadError error = kThreadError_None;
VerifyOrExit(aRouterInfo != NULL, error = kThreadError_InvalidArgs);
error = sThreadNetif->GetMle().GetRouterInfo(aRouterId, *aRouterInfo);
exit:
return error;
}
ThreadError otGetParentInfo(otInstance *, otRouterInfo *aParentInfo)
{
ThreadError error = kThreadError_None;
Router *parent;
VerifyOrExit(aParentInfo != NULL, error = kThreadError_InvalidArgs);
parent = sThreadNetif->GetMle().GetParent();
memcpy(aParentInfo->mExtAddress.m8, parent->mMacAddr.m8, OT_EXT_ADDRESS_SIZE);
aParentInfo->mRloc16 = parent->mValid.mRloc16;
exit:
return error;
}
uint8_t otGetStableNetworkDataVersion(otInstance *)
{
return sThreadNetif->GetMle().GetLeaderDataTlv().GetStableDataVersion();
}
void otSetLinkPcapCallback(otInstance *, otLinkPcapCallback aPcapCallback, void *aCallbackContext)
{
sThreadNetif->GetMac().SetPcapCallback(aPcapCallback, aCallbackContext);
}
bool otIsLinkPromiscuous(otInstance *)
{
return sThreadNetif->GetMac().IsPromiscuous();
}
ThreadError otSetLinkPromiscuous(otInstance *, bool aPromiscuous)
{
ThreadError error = kThreadError_None;
// cannot enable IEEE 802.15.4 promiscuous mode if the Thread interface is enabled
VerifyOrExit(sThreadNetif->IsUp() == false, error = kThreadError_Busy);
sThreadNetif->GetMac().SetPromiscuous(aPromiscuous);
exit:
return error;
}
const otMacCounters *otGetMacCounters(otInstance *)
{
return &sThreadNetif->GetMac().GetCounters();
}
bool otIsIp6AddressEqual(const otIp6Address *a, const otIp6Address *b)
{
return *static_cast<const Ip6::Address *>(a) == *static_cast<const Ip6::Address *>(b);
}
ThreadError otIp6AddressFromString(const char *str, otIp6Address *address)
{
return static_cast<Ip6::Address *>(address)->FromString(str);
}
const otNetifAddress *otGetUnicastAddresses(otInstance *)
{
return sThreadNetif->GetUnicastAddresses();
}
ThreadError otAddUnicastAddress(otInstance *, const otNetifAddress *address)
{
return sThreadNetif->AddExternalUnicastAddress(*static_cast<const Ip6::NetifUnicastAddress *>(address));
}
ThreadError otRemoveUnicastAddress(otInstance *, const otIp6Address *address)
{
return sThreadNetif->RemoveExternalUnicastAddress(*static_cast<const Ip6::Address *>(address));
}
void otSetStateChangedCallback(otInstance *, otStateChangedCallback aCallback, void *aCallbackContext)
{
sNetifCallback.Set(aCallback, aCallbackContext);
sThreadNetif->RegisterCallback(sNetifCallback);
}
const char *otGetVersionString(void)
{
static const char sVersion[] =
PACKAGE_NAME "/" PACKAGE_VERSION
#ifdef PLATFORM_INFO
"; " PLATFORM_INFO
#endif
#if defined(__DATE__)
"; " __DATE__ " " __TIME__;
#else
;
#endif
return sVersion;
}
uint32_t otGetPollPeriod(otInstance *)
{
return sThreadNetif->GetMeshForwarder().GetAssignPollPeriod();
}
void otSetPollPeriod(otInstance *, uint32_t aPollPeriod)
{
sThreadNetif->GetMeshForwarder().SetAssignPollPeriod(aPollPeriod);
}
#ifdef OPENTHREAD_MULTIPLE_INSTANCE
otInstance *otInstanceInit(void *aInstanceBuffer, uint64_t *aInstanceBufferSize)
{
otInstance *aInstance = NULL;
otLogInfoApi("otInstanceInit\n");
VerifyOrExit(aInstanceBufferSize != NULL, ;);
// Make sure the input buffer is big enough
VerifyOrExit(sizeof(otInstance) <= *aInstanceBufferSize, *aInstanceBufferSize = sizeof(otInstance));
VerifyOrExit(aInstanceBuffer != NULL, ;);
// Construct the context
aInstance = new(aInstanceBuffer)otInstance();
new(&sMbedTlsRaw) Crypto::MbedTls;
sIp6 = new(&sIp6Raw) Ip6::Ip6;
sThreadNetif = new(&sThreadNetifRaw) ThreadNetif(*sIp6);
exit:
return aInstance;
}
#else
otInstance *otInstanceInit()
{
otLogInfoApi("otInstanceInit\n");
VerifyOrExit(sInstance == NULL, ;);
// Construct the context
sInstance = new(&sInstanceRaw)otInstance();
new(&sMbedTlsRaw) Crypto::MbedTls;
sIp6 = new(&sIp6Raw) Ip6::Ip6;
sThreadNetif = new(&sThreadNetifRaw) ThreadNetif(*sIp6);
exit:
return sInstance;
}
#endif
ThreadError otSendDiagnosticGet(otInstance *aInstance, otIp6Address *aDestination, uint8_t aTlvTypes[], uint8_t aCount)
{
(void)aInstance;
return sThreadNetif->GetNetworkDiagnostic().SendDiagnosticGet(*static_cast<Ip6::Address *>(aDestination), aTlvTypes,
aCount);
}
ThreadError otSendDiagnosticReset(otInstance *aInstance, otIp6Address *aDestination, uint8_t aTlvTypes[],
uint8_t aCount)
{
(void)aInstance;
return sThreadNetif->GetNetworkDiagnostic().SendDiagnosticReset(*static_cast<Ip6::Address *>(aDestination), aTlvTypes,
aCount);
}
void otInstanceFinalize(otInstance *aInstance)
{
// Ensure we are disabled
(void)otThreadStop(aInstance);
(void)otInterfaceDown(aInstance);
// Nothing to actually free, since the caller supplied the buffer
sThreadNetif = NULL;
}
ThreadError otInterfaceUp(otInstance *)
{
ThreadError error = kThreadError_None;
error = sThreadNetif->Up();
return error;
}
ThreadError otInterfaceDown(otInstance *)
{
ThreadError error = kThreadError_None;
error = sThreadNetif->Down();
return error;
}
bool otIsInterfaceUp(otInstance *)
{
return sThreadNetif->IsUp();
}
ThreadError otThreadStart(otInstance *)
{
ThreadError error = kThreadError_None;
VerifyOrExit(sThreadNetif->GetMac().GetPanId() != Mac::kPanIdBroadcast, error = kThreadError_InvalidState);
error = sThreadNetif->GetMle().Start();
exit:
return error;
}
ThreadError otThreadStop(otInstance *)
{
ThreadError error = kThreadError_None;
error = sThreadNetif->GetMle().Stop();
return error;
}
bool otIsSingleton(otInstance *)
{
return sThreadNetif->GetMle().IsSingleton();
}
ThreadError otActiveScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration,
otHandleActiveScanResult aCallback, void *aCallbackContext)
{
sActiveScanCallback = aCallback;
sActiveScanCallbackContext = aCallbackContext;
return sThreadNetif->GetMac().ActiveScan(aScanChannels, aScanDuration, &HandleActiveScanResult, aInstance);
}
bool otIsActiveScanInProgress(otInstance *)
{
return sThreadNetif->GetMac().IsActiveScanInProgress();
}
void HandleActiveScanResult(void *aContext, Mac::Frame *aFrame)
{
otInstance *aInstance = static_cast<otInstance *>(aContext);
otActiveScanResult result;
Mac::Address address;
Mac::Beacon *beacon;
uint8_t payloadLength;
memset(&result, 0, sizeof(otActiveScanResult));
if (aFrame == NULL)
{
sActiveScanCallback(NULL, sActiveScanCallbackContext);
ExitNow();
}
SuccessOrExit(aFrame->GetSrcAddr(address));
VerifyOrExit(address.mLength == sizeof(address.mExtAddress), ;);
memcpy(&result.mExtAddress, &address.mExtAddress, sizeof(result.mExtAddress));
aFrame->GetSrcPanId(result.mPanId);
result.mChannel = aFrame->GetChannel();
result.mRssi = aFrame->GetPower();
result.mLqi = aFrame->GetLqi();
payloadLength = aFrame->GetPayloadLength();
beacon = reinterpret_cast<Mac::Beacon *>(aFrame->GetPayload());
if (payloadLength >= sizeof(*beacon) && beacon->IsValid())
{
result.mVersion = beacon->GetProtocolVersion();
result.mIsJoinable = beacon->IsJoiningPermitted();
result.mIsNative = beacon->IsNative();
memcpy(&result.mNetworkName, beacon->GetNetworkName(), sizeof(result.mNetworkName));
memcpy(&result.mExtendedPanId, beacon->GetExtendedPanId(), sizeof(result.mExtendedPanId));
}
sActiveScanCallback(&result, sActiveScanCallbackContext);
exit:
(void)aInstance;
return;
}
ThreadError otEnergyScan(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration,
otHandleEnergyScanResult aCallback, void *aCallbackContext)
{
sEnergyScanCallback = aCallback;
sEnergyScanCallbackContext = aCallbackContext;
return sThreadNetif->GetMac().EnergyScan(aScanChannels, aScanDuration, &HandleEnergyScanResult, aInstance);
}
void HandleEnergyScanResult(void *aContext, otEnergyScanResult *aResult)
{
otInstance *aInstance = static_cast<otInstance *>(aContext);
sEnergyScanCallback(aResult, sEnergyScanCallbackContext);
(void)aInstance;
}
bool otIsEnergyScanInProgress(otInstance *aInstance)
{
(void)aInstance;
return sThreadNetif->GetMac().IsEnergyScanInProgress();
}
ThreadError otDiscover(otInstance *aInstance, uint32_t aScanChannels, uint16_t aScanDuration, uint16_t aPanId,
otHandleActiveScanResult aCallback, void *aCallbackContext)
{
sDiscoverCallback = aCallback;
sDiscoverCallbackContext = aCallbackContext;
return sThreadNetif->GetMle().Discover(aScanChannels, aScanDuration, aPanId, &HandleMleDiscover, aInstance);
}
bool otIsDiscoverInProgress(otInstance *)
{
return sThreadNetif->GetMle().IsDiscoverInProgress();
}
void HandleMleDiscover(otActiveScanResult *aResult, void *aContext)
{
otInstance *aInstance = static_cast<otInstance *>(aContext);
(void)aInstance;
sDiscoverCallback(aResult, sDiscoverCallbackContext);
}
void otSetReceiveIp6DatagramCallback(otInstance *, otReceiveIp6DatagramCallback aCallback,
void *aCallbackContext)
{
sIp6->SetReceiveDatagramCallback(aCallback, aCallbackContext);
}
bool otIsReceiveIp6DatagramFilterEnabled(otInstance *)
{
return sIp6->IsReceiveIp6FilterEnabled();
}
void otSetReceiveIp6DatagramFilterEnabled(otInstance *, bool aEnabled)
{
sIp6->SetReceiveIp6FilterEnabled(aEnabled);
}
ThreadError otSendIp6Datagram(otInstance *, otMessage aMessage)
{
return sIp6->HandleDatagram(*static_cast<Message *>(aMessage), NULL, sThreadNetif->GetInterfaceId(), NULL, true);
}
otMessage otNewUdpMessage(otInstance *)
{
return sIp6->mUdp.NewMessage(0);
}
otMessage otNewIp6Message(otInstance *, bool aLinkSecurityEnabled)
{
Message *message = sIp6->mMessagePool.New(Message::kTypeIp6, 0);
if (message)
{
message->SetLinkSecurityEnabled(aLinkSecurityEnabled);
}
return message;
}
ThreadError otFreeMessage(otMessage aMessage)
{
return static_cast<Message *>(aMessage)->Free();
}
uint16_t otGetMessageLength(otMessage aMessage)
{
Message *message = static_cast<Message *>(aMessage);
return message->GetLength();
}
ThreadError otSetMessageLength(otMessage aMessage, uint16_t aLength)
{
Message *message = static_cast<Message *>(aMessage);
return message->SetLength(aLength);
}
uint16_t otGetMessageOffset(otMessage aMessage)
{
Message *message = static_cast<Message *>(aMessage);
return message->GetOffset();
}
ThreadError otSetMessageOffset(otMessage aMessage, uint16_t aOffset)
{
Message *message = static_cast<Message *>(aMessage);
return message->SetOffset(aOffset);
}
ThreadError otAppendMessage(otMessage aMessage, const void *aBuf, uint16_t aLength)
{
Message *message = static_cast<Message *>(aMessage);
return message->Append(aBuf, aLength);
}
int otReadMessage(otMessage aMessage, uint16_t aOffset, void *aBuf, uint16_t aLength)
{
Message *message = static_cast<Message *>(aMessage);
return message->Read(aOffset, aLength, aBuf);
}
int otWriteMessage(otMessage aMessage, uint16_t aOffset, const void *aBuf, uint16_t aLength)
{
Message *message = static_cast<Message *>(aMessage);
return message->Write(aOffset, aLength, aBuf);
}
ThreadError otOpenUdpSocket(otInstance *, otUdpSocket *aSocket, otUdpReceive aCallback, void *aCallbackContext)
{
ThreadError error = kThreadError_Busy;
Ip6::UdpSocket *socket = static_cast<Ip6::UdpSocket *>(aSocket);
if (socket->mTransport == NULL)
{
socket->mTransport = &sIp6->mUdp;
error = socket->Open(aCallback, aCallbackContext);
}
return error;
}
ThreadError otCloseUdpSocket(otUdpSocket *aSocket)
{
ThreadError error = kThreadError_InvalidState;
Ip6::UdpSocket *socket = static_cast<Ip6::UdpSocket *>(aSocket);
if (socket->mTransport != NULL)
{
error = socket->Close();
if (error == kThreadError_None)
{
socket->mTransport = NULL;
}
}
return error;
}
ThreadError otBindUdpSocket(otUdpSocket *aSocket, otSockAddr *aSockName)
{
Ip6::UdpSocket *socket = static_cast<Ip6::UdpSocket *>(aSocket);
return socket->Bind(*static_cast<const Ip6::SockAddr *>(aSockName));
}
ThreadError otSendUdp(otUdpSocket *aSocket, otMessage aMessage, const otMessageInfo *aMessageInfo)
{
Ip6::UdpSocket *socket = static_cast<Ip6::UdpSocket *>(aSocket);
return socket->SendTo(*static_cast<Message *>(aMessage),
*static_cast<const Ip6::MessageInfo *>(aMessageInfo));
}
bool otIsIcmpEchoEnabled(otInstance *)
{
return sIp6->mIcmp.IsEchoEnabled();
}
void otSetIcmpEchoEnabled(otInstance *, bool aEnabled)
{
sIp6->mIcmp.SetEchoEnabled(aEnabled);
}
uint8_t otIp6PrefixMatch(const otIp6Address *aFirst, const otIp6Address *aSecond)
{
uint8_t rval;
VerifyOrExit(aFirst != NULL && aSecond != NULL, rval = 0);
rval = static_cast<const Ip6::Address *>(aFirst)->PrefixMatch(*static_cast<const Ip6::Address *>(aSecond));
exit:
return rval;
}
ThreadError otGetActiveDataset(otInstance *, otOperationalDataset *aDataset)
{
ThreadError error = kThreadError_None;
VerifyOrExit(aDataset != NULL, error = kThreadError_InvalidArgs);
sThreadNetif->GetActiveDataset().Get(*aDataset);
exit:
return error;
}
ThreadError otSetActiveDataset(otInstance *, otOperationalDataset *aDataset)
{
ThreadError error;
VerifyOrExit(aDataset != NULL, error = kThreadError_InvalidArgs);
error = sThreadNetif->GetActiveDataset().Set(*aDataset);
exit:
return error;
}
ThreadError otGetPendingDataset(otInstance *, otOperationalDataset *aDataset)
{
ThreadError error = kThreadError_None;
VerifyOrExit(aDataset != NULL, error = kThreadError_InvalidArgs);
sThreadNetif->GetPendingDataset().Get(*aDataset);
exit:
return error;
}
ThreadError otSetPendingDataset(otInstance *, otOperationalDataset *aDataset)
{
ThreadError error;
VerifyOrExit(aDataset != NULL, error = kThreadError_InvalidArgs);
error = sThreadNetif->GetPendingDataset().Set(*aDataset);
exit:
return error;
}
ThreadError otSendActiveGet(otInstance *, const uint8_t *aTlvTypes, uint8_t aLength)
{
return sThreadNetif->GetActiveDataset().SendGetRequest(aTlvTypes, aLength);
}
ThreadError otSendActiveSet(otInstance *, const otOperationalDataset *aDataset, const uint8_t *aTlvs, uint8_t aLength)
{
return sThreadNetif->GetActiveDataset().SendSetRequest(*aDataset, aTlvs, aLength);
}
ThreadError otSendPendingGet(otInstance *, const uint8_t *aTlvTypes, uint8_t aLength)
{
return sThreadNetif->GetPendingDataset().SendGetRequest(aTlvTypes, aLength);
}
ThreadError otSendPendingSet(otInstance *, const otOperationalDataset *aDataset, const uint8_t *aTlvs, uint8_t aLength)
{
return sThreadNetif->GetPendingDataset().SendSetRequest(*aDataset, aTlvs, aLength);
}
#if OPENTHREAD_ENABLE_COMMISSIONER
#include <commissioning/commissioner.h>
ThreadError otCommissionerStart(otInstance *, const char *aPSKd, const char *aProvisioningUrl)
{
return sThreadNetif->GetCommissioner().Start(aPSKd, aProvisioningUrl);
}
ThreadError otCommissionerStop(otInstance *)
{
return sThreadNetif->GetCommissioner().Stop();
}
ThreadError otCommissionerEnergyScan(otInstance *, uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod,
uint16_t aScanDuration, const otIp6Address *aAddress,
otCommissionerEnergyReportCallback aCallback, void *aContext)
{
return sThreadNetif->GetCommissioner().mEnergyScan.SendQuery(aChannelMask, aCount, aPeriod, aScanDuration,
*static_cast<const Ip6::Address *>(aAddress),
aCallback, aContext);
}
ThreadError otCommissionerPanIdQuery(otInstance *, uint16_t aPanId, uint32_t aChannelMask,
const otIp6Address *aAddress,
otCommissionerPanIdConflictCallback aCallback, void *aContext)
{
return sThreadNetif->GetCommissioner().mPanIdQuery.SendQuery(aPanId, aChannelMask,
*static_cast<const Ip6::Address *>(aAddress),
aCallback, aContext);
}
ThreadError otSendMgmtCommissionerGet(otInstance *, const uint8_t *aTlvs, uint8_t aLength)
{
return sThreadNetif->GetCommissioner().SendMgmtCommissionerGetRequest(aTlvs, aLength);
}
ThreadError otSendMgmtCommissionerSet(otInstance *, const otCommissioningDataset *aDataset,
const uint8_t *aTlvs, uint8_t aLength)
{
return sThreadNetif->GetCommissioner().SendMgmtCommissionerSetRequest(*aDataset, aTlvs, aLength);
}
#endif // OPENTHREAD_ENABLE_COMMISSIONER
#if OPENTHREAD_ENABLE_JOINER
ThreadError otJoinerStart(otInstance *, const char *aPSKd, const char *aProvisioningUrl)
{
return sThreadNetif->GetJoiner().Start(aPSKd, aProvisioningUrl);
}
ThreadError otJoinerStop(otInstance *)
{
return sThreadNetif->GetJoiner().Stop();
}
#endif // OPENTHREAD_ENABLE_JOINER
#ifdef __cplusplus
} // extern "C"
#endif
} // namespace Thread