/* * 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 OpenThread Thread API (for both FTD and MTD). */ #include "openthread-core-config.h" #if OPENTHREAD_FTD || OPENTHREAD_MTD #include "instance/instance.hpp" using namespace ot; uint32_t otThreadGetChildTimeout(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetTimeout(); } void otThreadSetChildTimeout(otInstance *aInstance, uint32_t aTimeout) { AsCoreType(aInstance).Get().SetTimeout(aTimeout); } const otExtendedPanId *otThreadGetExtendedPanId(otInstance *aInstance) { return &AsCoreType(aInstance).Get().GetExtPanId(); } otError otThreadSetExtendedPanId(otInstance *aInstance, const otExtendedPanId *aExtendedPanId) { Error error = kErrorNone; Instance &instance = AsCoreType(aInstance); const MeshCoP::ExtendedPanId &extPanId = AsCoreType(aExtendedPanId); VerifyOrExit(instance.Get().IsDisabled(), error = kErrorInvalidState); instance.Get().SetExtPanId(extPanId); instance.Get().Clear(); instance.Get().Clear(); exit: return error; } otError otThreadGetLeaderRloc(otInstance *aInstance, otIp6Address *aLeaderRloc) { Error error = kErrorNone; VerifyOrExit(!AsCoreType(aInstance).Get().HasRloc16(Mle::kInvalidRloc16), error = kErrorDetached); AsCoreType(aInstance).Get().GetLeaderRloc(AsCoreType(aLeaderRloc)); exit: return error; } otLinkModeConfig otThreadGetLinkMode(otInstance *aInstance) { otLinkModeConfig config; AsCoreType(aInstance).Get().GetDeviceMode().Get(config); return config; } otError otThreadSetLinkMode(otInstance *aInstance, otLinkModeConfig aConfig) { return AsCoreType(aInstance).Get().SetDeviceMode(Mle::DeviceMode(aConfig)); } void otThreadGetNetworkKey(otInstance *aInstance, otNetworkKey *aNetworkKey) { AsCoreType(aInstance).Get().GetNetworkKey(AsCoreType(aNetworkKey)); } #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE otNetworkKeyRef otThreadGetNetworkKeyRef(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetNetworkKeyRef(); } #endif otError otThreadSetNetworkKey(otInstance *aInstance, const otNetworkKey *aKey) { Error error = kErrorNone; Instance &instance = AsCoreType(aInstance); VerifyOrExit(instance.Get().IsDisabled(), error = kErrorInvalidState); instance.Get().SetNetworkKey(AsCoreType(aKey)); instance.Get().Clear(); instance.Get().Clear(); exit: return error; } #if OPENTHREAD_CONFIG_PLATFORM_KEY_REFERENCES_ENABLE otError otThreadSetNetworkKeyRef(otInstance *aInstance, otNetworkKeyRef aKeyRef) { Error error = kErrorNone; Instance &instance = AsCoreType(aInstance); VerifyOrExit(aKeyRef != 0, error = kErrorInvalidArgs); VerifyOrExit(instance.Get().IsDisabled(), error = kErrorInvalidState); instance.Get().SetNetworkKeyRef((aKeyRef)); instance.Get().Clear(); instance.Get().Clear(); exit: return error; } #endif const otIp6Address *otThreadGetRloc(otInstance *aInstance) { return &AsCoreType(aInstance).Get().GetMeshLocalRloc(); } const otIp6Address *otThreadGetMeshLocalEid(otInstance *aInstance) { return &AsCoreType(aInstance).Get().GetMeshLocalEid(); } const otMeshLocalPrefix *otThreadGetMeshLocalPrefix(otInstance *aInstance) { return &AsCoreType(aInstance).Get().GetMeshLocalPrefix(); } otError otThreadSetMeshLocalPrefix(otInstance *aInstance, const otMeshLocalPrefix *aMeshLocalPrefix) { Error error = kErrorNone; VerifyOrExit(AsCoreType(aInstance).Get().IsDisabled(), error = kErrorInvalidState); AsCoreType(aInstance).Get().SetMeshLocalPrefix(AsCoreType(aMeshLocalPrefix)); AsCoreType(aInstance).Get().Clear(); AsCoreType(aInstance).Get().Clear(); exit: return error; } const otIp6Address *otThreadGetLinkLocalIp6Address(otInstance *aInstance) { return &AsCoreType(aInstance).Get().GetLinkLocalAddress(); } const otIp6Address *otThreadGetLinkLocalAllThreadNodesMulticastAddress(otInstance *aInstance) { return &AsCoreType(aInstance).Get().GetLinkLocalAllThreadNodesAddress(); } const otIp6Address *otThreadGetRealmLocalAllThreadNodesMulticastAddress(otInstance *aInstance) { return &AsCoreType(aInstance).Get().GetRealmLocalAllThreadNodesAddress(); } otError otThreadGetServiceAloc(otInstance *aInstance, uint8_t aServiceId, otIp6Address *aServiceAloc) { Error error = kErrorNone; VerifyOrExit(!AsCoreType(aInstance).Get().HasRloc16(Mle::kInvalidRloc16), error = kErrorDetached); AsCoreType(aInstance).Get().GetServiceAloc(aServiceId, AsCoreType(aServiceAloc)); exit: return error; } const char *otThreadGetNetworkName(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetNetworkName().GetAsCString(); } otError otThreadSetNetworkName(otInstance *aInstance, const char *aNetworkName) { Error error = kErrorNone; VerifyOrExit(AsCoreType(aInstance).Get().IsDisabled(), error = kErrorInvalidState); #if !OPENTHREAD_CONFIG_ALLOW_EMPTY_NETWORK_NAME // Thread interfaces support a zero length name internally for backwards compatibility, but new names // must be at least one valid character long. VerifyOrExit(nullptr != aNetworkName && aNetworkName[0] != '\0', error = kErrorInvalidArgs); #endif error = AsCoreType(aInstance).Get().SetNetworkName(aNetworkName); AsCoreType(aInstance).Get().Clear(); AsCoreType(aInstance).Get().Clear(); exit: return error; } #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) const char *otThreadGetDomainName(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetDomainName().GetAsCString(); } otError otThreadSetDomainName(otInstance *aInstance, const char *aDomainName) { Error error = kErrorNone; VerifyOrExit(AsCoreType(aInstance).Get().IsDisabled(), error = kErrorInvalidState); error = AsCoreType(aInstance).Get().SetDomainName(aDomainName); exit: return error; } #if OPENTHREAD_CONFIG_DUA_ENABLE otError otThreadSetFixedDuaInterfaceIdentifier(otInstance *aInstance, const otIp6InterfaceIdentifier *aIid) { Error error = kErrorNone; if (aIid) { error = AsCoreType(aInstance).Get().SetFixedDuaInterfaceIdentifier(AsCoreType(aIid)); } else { AsCoreType(aInstance).Get().ClearFixedDuaInterfaceIdentifier(); } return error; } const otIp6InterfaceIdentifier *otThreadGetFixedDuaInterfaceIdentifier(otInstance *aInstance) { Instance &instance = AsCoreType(aInstance); const otIp6InterfaceIdentifier *iid = nullptr; if (instance.Get().IsFixedDuaInterfaceIdentifierSet()) { iid = &instance.Get().GetFixedDuaInterfaceIdentifier(); } return iid; } #endif // OPENTHREAD_CONFIG_DUA_ENABLE #endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) uint32_t otThreadGetKeySequenceCounter(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetCurrentKeySequence(); } void otThreadSetKeySequenceCounter(otInstance *aInstance, uint32_t aKeySequenceCounter) { AsCoreType(aInstance).Get().SetCurrentKeySequence( aKeySequenceCounter, KeyManager::kForceUpdate | KeyManager::kGuardTimerUnchanged); } uint16_t otThreadGetKeySwitchGuardTime(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetKeySwitchGuardTime(); } void otThreadSetKeySwitchGuardTime(otInstance *aInstance, uint16_t aKeySwitchGuardTime) { AsCoreType(aInstance).Get().SetKeySwitchGuardTime(aKeySwitchGuardTime); } otError otThreadBecomeDetached(otInstance *aInstance) { return AsCoreType(aInstance).Get().BecomeDetached(); } otError otThreadBecomeChild(otInstance *aInstance) { return AsCoreType(aInstance).Get().BecomeChild(); } otError otThreadGetNextNeighborInfo(otInstance *aInstance, otNeighborInfoIterator *aIterator, otNeighborInfo *aInfo) { AssertPointerIsNotNull(aIterator); return AsCoreType(aInstance).Get().GetNextNeighborInfo(*aIterator, AsCoreType(aInfo)); } otDeviceRole otThreadGetDeviceRole(otInstance *aInstance) { return MapEnum(AsCoreType(aInstance).Get().GetRole()); } const char *otThreadDeviceRoleToString(otDeviceRole aRole) { return Mle::RoleToString(MapEnum(aRole)); } otError otThreadGetLeaderData(otInstance *aInstance, otLeaderData *aLeaderData) { Error error = kErrorNone; AssertPointerIsNotNull(aLeaderData); VerifyOrExit(AsCoreType(aInstance).Get().IsAttached(), error = kErrorDetached); *aLeaderData = AsCoreType(aInstance).Get().GetLeaderData(); exit: return error; } uint8_t otThreadGetLeaderRouterId(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetLeaderId(); } uint8_t otThreadGetLeaderWeight(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetLeaderData().GetWeighting(); } uint32_t otThreadGetPartitionId(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetLeaderData().GetPartitionId(); } uint16_t otThreadGetRloc16(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetRloc16(); } otError otThreadGetParentInfo(otInstance *aInstance, otRouterInfo *aParentInfo) { return AsCoreType(aInstance).Get().GetParentInfo(AsCoreType(aParentInfo)); } otError otThreadGetParentAverageRssi(otInstance *aInstance, int8_t *aParentRssi) { Error error = kErrorNone; AssertPointerIsNotNull(aParentRssi); *aParentRssi = AsCoreType(aInstance).Get().GetParent().GetLinkInfo().GetAverageRss(); VerifyOrExit(*aParentRssi != Radio::kInvalidRssi, error = kErrorFailed); exit: return error; } otError otThreadGetParentLastRssi(otInstance *aInstance, int8_t *aLastRssi) { Error error = kErrorNone; AssertPointerIsNotNull(aLastRssi); *aLastRssi = AsCoreType(aInstance).Get().GetParent().GetLinkInfo().GetLastRss(); VerifyOrExit(*aLastRssi != Radio::kInvalidRssi, error = kErrorFailed); exit: return error; } otError otThreadSearchForBetterParent(otInstance *aInstance) { return AsCoreType(aInstance).Get().SearchForBetterParent(); } otError otThreadSetEnabled(otInstance *aInstance, bool aEnabled) { Error error = kErrorNone; if (aEnabled) { error = AsCoreType(aInstance).Get().Start(); } else { AsCoreType(aInstance).Get().Stop(); } return error; } uint16_t otThreadGetVersion(void) { return kThreadVersion; } bool otThreadIsSingleton(otInstance *aInstance) { bool isSingleton = false; #if OPENTHREAD_FTD isSingleton = AsCoreType(aInstance).Get().IsSingleton(); #else OT_UNUSED_VARIABLE(aInstance); #endif return isSingleton; } otError otThreadDiscover(otInstance *aInstance, uint32_t aScanChannels, uint16_t aPanId, bool aJoiner, bool aEnableEui64Filtering, otHandleActiveScanResult aCallback, void *aCallbackContext) { return AsCoreType(aInstance).Get().Discover( Mac::ChannelMask(aScanChannels), aPanId, aJoiner, aEnableEui64Filtering, /* aFilterIndexes (use hash of factory EUI64) */ nullptr, aCallback, aCallbackContext); } otError otThreadSetJoinerAdvertisement(otInstance *aInstance, uint32_t aOui, const uint8_t *aAdvData, uint8_t aAdvDataLength) { return AsCoreType(aInstance).Get().SetJoinerAdvertisement(aOui, aAdvData, aAdvDataLength); } bool otThreadIsDiscoverInProgress(otInstance *aInstance) { return AsCoreType(aInstance).Get().IsInProgress(); } const otIpCounters *otThreadGetIp6Counters(otInstance *aInstance) { return &AsCoreType(aInstance).Get().GetCounters(); } void otThreadResetIp6Counters(otInstance *aInstance) { AsCoreType(aInstance).Get().ResetCounters(); } #if OPENTHREAD_CONFIG_TX_QUEUE_STATISTICS_ENABLE const uint32_t *otThreadGetTimeInQueueHistogram(otInstance *aInstance, uint16_t *aNumBins, uint32_t *aBinInterval) { AssertPointerIsNotNull(aNumBins); AssertPointerIsNotNull(aBinInterval); return AsCoreType(aInstance).Get().GetTimeInQueueHistogram(*aNumBins, *aBinInterval); } uint32_t otThreadGetMaxTimeInQueue(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetMaxTimeInQueue(); } void otThreadResetTimeInQueueStat(otInstance *aInstance) { return AsCoreType(aInstance).Get().ResetTimeInQueueStat(); } #endif const otMleCounters *otThreadGetMleCounters(otInstance *aInstance) { return &AsCoreType(aInstance).Get().GetCounters(); } void otThreadResetMleCounters(otInstance *aInstance) { AsCoreType(aInstance).Get().ResetCounters(); } #if OPENTHREAD_CONFIG_UPTIME_ENABLE uint32_t otThreadGetCurrentAttachDuration(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetCurrentAttachDuration(); } #endif #if OPENTHREAD_CONFIG_MLE_PARENT_RESPONSE_CALLBACK_API_ENABLE void otThreadRegisterParentResponseCallback(otInstance *aInstance, otThreadParentResponseCallback aCallback, void *aContext) { AsCoreType(aInstance).Get().RegisterParentResponseStatsCallback(aCallback, aContext); } #endif #if OPENTHREAD_CONFIG_TMF_ANYCAST_LOCATOR_ENABLE otError otThreadLocateAnycastDestination(otInstance *aInstance, const otIp6Address *aAnycastAddress, otThreadAnycastLocatorCallback aCallback, void *aContext) { return AsCoreType(aInstance).Get().Locate(AsCoreType(aAnycastAddress), aCallback, aContext); } bool otThreadIsAnycastLocateInProgress(otInstance *aInstance) { return AsCoreType(aInstance).Get().IsInProgress(); } #endif otError otThreadDetachGracefully(otInstance *aInstance, otDetachGracefullyCallback aCallback, void *aContext) { return AsCoreType(aInstance).Get().DetachGracefully(aCallback, aContext); } #if OPENTHREAD_CONFIG_DYNAMIC_STORE_FRAME_AHEAD_COUNTER_ENABLE void otThreadSetStoreFrameCounterAhead(otInstance *aInstance, uint32_t aStoreFrameCounterAhead) { return AsCoreType(aInstance).Get().SetStoreFrameCounterAhead(aStoreFrameCounterAhead); } uint32_t otThreadGetStoreFrameCounterAhead(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetStoreFrameCounterAhead(); } #endif #if OPENTHREAD_CONFIG_WAKEUP_COORDINATOR_ENABLE otError otThreadWakeup(otInstance *aInstance, const otExtAddress *aWedAddress, uint16_t aWakeupIntervalUs, uint16_t aWakeupDurationMs, otWakeupCallback aCallback, void *aCallbackContext) { return AsCoreType(aInstance).Get().Wakeup(AsCoreType(aWedAddress), aWakeupIntervalUs, aWakeupDurationMs, aCallback, aCallbackContext); } #endif #endif // OPENTHREAD_FTD || OPENTHREAD_MTD #if OPENTHREAD_CONFIG_UPTIME_ENABLE void otConvertDurationInSecondsToString(uint32_t aDuration, char *aBuffer, uint16_t aSize) { StringWriter writer(aBuffer, aSize); Uptime::UptimeToString(Uptime::SecToMsec(aDuration), writer, /* aIncludeMsec */ false); } #endif