| /* |
| * Copyright (c) 2016, Nest Labs, Inc. |
| * 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. |
| */ |
| |
| #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 <platform/random.h> |
| #include <thread/thread_netif.hpp> |
| |
| 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; |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| static otDEFINE_ALIGNED_VAR(sThreadNetifRaw, sizeof(ThreadNetif), uint64_t); |
| |
| static void HandleActiveScanResult(void *aContext, Mac::Frame *aFrame); |
| |
| void otInit(void) |
| { |
| otLogInfoApi("Init\n"); |
| Message::Init(); |
| sThreadNetif = new(&sThreadNetifRaw) ThreadNetif; |
| } |
| |
| void otProcessNextTasklet(void) |
| { |
| TaskletScheduler::RunNextTasklet(); |
| } |
| |
| bool otAreTaskletsPending(void) |
| { |
| return TaskletScheduler::AreTaskletsPending(); |
| } |
| |
| uint8_t otGetChannel(void) |
| { |
| return sThreadNetif->GetMac().GetChannel(); |
| } |
| |
| ThreadError otSetChannel(uint8_t aChannel) |
| { |
| return sThreadNetif->GetMac().SetChannel(aChannel); |
| } |
| |
| uint32_t otGetChildTimeout(void) |
| { |
| return sThreadNetif->GetMle().GetTimeout(); |
| } |
| |
| void otSetChildTimeout(uint32_t aTimeout) |
| { |
| sThreadNetif->GetMle().SetTimeout(aTimeout); |
| } |
| |
| const uint8_t *otGetExtendedAddress(void) |
| { |
| return reinterpret_cast<const uint8_t *>(sThreadNetif->GetMac().GetExtAddress()); |
| } |
| |
| const uint8_t *otGetExtendedPanId(void) |
| { |
| return sThreadNetif->GetMac().GetExtendedPanId(); |
| } |
| |
| void otSetExtendedPanId(const uint8_t *aExtendedPanId) |
| { |
| sThreadNetif->GetMac().SetExtendedPanId(aExtendedPanId); |
| sThreadNetif->GetMle().SetMeshLocalPrefix(aExtendedPanId); |
| } |
| |
| ThreadError otGetLeaderRloc(otIp6Address *aAddress) |
| { |
| ThreadError error; |
| |
| VerifyOrExit(aAddress != NULL, error = kThreadError_InvalidArgs); |
| |
| error = sThreadNetif->GetMle().GetLeaderAddress(*static_cast<Ip6::Address *>(aAddress)); |
| |
| exit: |
| return error; |
| } |
| |
| otLinkModeConfig otGetLinkMode(void) |
| { |
| otLinkModeConfig config = {}; |
| uint8_t mode = sThreadNetif->GetMle().GetDeviceMode(); |
| |
| 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(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(uint8_t *aKeyLength) |
| { |
| return sThreadNetif->GetKeyManager().GetMasterKey(aKeyLength); |
| } |
| |
| ThreadError otSetMasterKey(const uint8_t *aKey, uint8_t aKeyLength) |
| { |
| return sThreadNetif->GetKeyManager().SetMasterKey(aKey, aKeyLength); |
| } |
| |
| const otIp6Address *otGetMeshLocalEid(void) |
| { |
| return sThreadNetif->GetMle().GetMeshLocal64(); |
| } |
| |
| const uint8_t *otGetMeshLocalPrefix(void) |
| { |
| return sThreadNetif->GetMle().GetMeshLocalPrefix(); |
| } |
| |
| ThreadError otSetMeshLocalPrefix(const uint8_t *aMeshLocalPrefix) |
| { |
| return sThreadNetif->GetMle().SetMeshLocalPrefix(aMeshLocalPrefix); |
| } |
| |
| ThreadError otGetNetworkDataLeader(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(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(void) |
| { |
| return sThreadNetif->GetMac().GetNetworkName(); |
| } |
| |
| ThreadError otSetNetworkName(const char *aNetworkName) |
| { |
| return sThreadNetif->GetMac().SetNetworkName(aNetworkName); |
| } |
| |
| otPanId otGetPanId(void) |
| { |
| return sThreadNetif->GetMac().GetPanId(); |
| } |
| |
| ThreadError otSetPanId(otPanId aPanId) |
| { |
| return sThreadNetif->GetMac().SetPanId(aPanId); |
| } |
| |
| otShortAddress otGetShortAddress(void) |
| { |
| return sThreadNetif->GetMac().GetShortAddress(); |
| } |
| |
| uint8_t otGetLocalLeaderWeight(void) |
| { |
| return sThreadNetif->GetMle().GetLeaderWeight(); |
| } |
| |
| void otSetLocalLeaderWeight(uint8_t aWeight) |
| { |
| sThreadNetif->GetMle().SetLeaderWeight(aWeight); |
| } |
| |
| ThreadError otAddBorderRouter(const otBorderRouterConfig *aConfig) |
| { |
| uint8_t flags = 0; |
| |
| if (aConfig->mSlaacPreferred) |
| { |
| flags |= NetworkData::BorderRouterEntry::kPreferredFlag; |
| } |
| |
| if (aConfig->mSlaacValid) |
| { |
| flags |= NetworkData::BorderRouterEntry::kValidFlag; |
| } |
| |
| if (aConfig->mDhcp) |
| { |
| flags |= NetworkData::BorderRouterEntry::kDhcpFlag; |
| } |
| |
| if (aConfig->mConfigure) |
| { |
| flags |= NetworkData::BorderRouterEntry::kConfigureFlag; |
| } |
| |
| if (aConfig->mDefaultRoute) |
| { |
| flags |= NetworkData::BorderRouterEntry::kDefaultRouteFlag; |
| } |
| |
| return sThreadNetif->GetNetworkDataLocal().AddOnMeshPrefix(aConfig->mPrefix.mPrefix.m8, aConfig->mPrefix.mLength, |
| aConfig->mPreference, flags, aConfig->mStable); |
| } |
| |
| ThreadError otRemoveBorderRouter(const otIp6Prefix *aPrefix) |
| { |
| return sThreadNetif->GetNetworkDataLocal().RemoveOnMeshPrefix(aPrefix->mPrefix.m8, aPrefix->mLength); |
| } |
| |
| ThreadError otAddExternalRoute(const otExternalRouteConfig *aConfig) |
| { |
| return sThreadNetif->GetNetworkDataLocal().AddHasRoutePrefix(aConfig->mPrefix.mPrefix.m8, aConfig->mPrefix.mLength, |
| aConfig->mPreference, aConfig->mStable); |
| } |
| |
| ThreadError otRemoveExternalRoute(const otIp6Prefix *aPrefix) |
| { |
| return sThreadNetif->GetNetworkDataLocal().RemoveHasRoutePrefix(aPrefix->mPrefix.m8, aPrefix->mLength); |
| } |
| |
| ThreadError otSendServerData(void) |
| { |
| Ip6::Address destination; |
| sThreadNetif->GetMle().GetLeaderAddress(destination); |
| return sThreadNetif->GetNetworkDataLocal().Register(destination); |
| } |
| |
| uint32_t otGetContextIdReuseDelay(void) |
| { |
| return sThreadNetif->GetNetworkDataLeader().GetContextIdReuseDelay(); |
| } |
| |
| void otSetContextIdReuseDelay(uint32_t aDelay) |
| { |
| sThreadNetif->GetNetworkDataLeader().SetContextIdReuseDelay(aDelay); |
| } |
| |
| uint32_t otGetKeySequenceCounter(void) |
| { |
| return sThreadNetif->GetKeyManager().GetCurrentKeySequence(); |
| } |
| |
| void otSetKeySequenceCounter(uint32_t aKeySequenceCounter) |
| { |
| sThreadNetif->GetKeyManager().SetCurrentKeySequence(aKeySequenceCounter); |
| } |
| |
| uint32_t otGetNetworkIdTimeout(void) |
| { |
| return sThreadNetif->GetMle().GetNetworkIdTimeout(); |
| } |
| |
| void otSetNetworkIdTimeout(uint32_t aTimeout) |
| { |
| sThreadNetif->GetMle().SetNetworkIdTimeout(aTimeout); |
| } |
| |
| uint8_t otGetRouterUpgradeThreshold(void) |
| { |
| return sThreadNetif->GetMle().GetRouterUpgradeThreshold(); |
| } |
| |
| void otSetRouterUpgradeThreshold(uint8_t aThreshold) |
| { |
| sThreadNetif->GetMle().SetRouterUpgradeThreshold(aThreshold); |
| } |
| |
| ThreadError otReleaseRouterId(uint8_t aRouterId) |
| { |
| return sThreadNetif->GetMle().ReleaseRouterId(aRouterId); |
| } |
| |
| ThreadError otAddMacWhitelist(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(const uint8_t *aExtAddr, int8_t aRssi) |
| { |
| ThreadError error = kThreadError_None; |
| Thread::Mac::Whitelist::Entry *entry; |
| |
| entry = sThreadNetif->GetMac().GetWhitelist().Add(*reinterpret_cast<const Mac::ExtAddress *>(aExtAddr)); |
| VerifyOrExit(entry != NULL, error = kThreadError_NoBufs); |
| sThreadNetif->GetMac().GetWhitelist().SetConstantRssi(*entry, aRssi); |
| |
| exit: |
| return error; |
| } |
| |
| void otRemoveMacWhitelist(const uint8_t *aExtAddr) |
| { |
| sThreadNetif->GetMac().GetWhitelist().Remove(*reinterpret_cast<const Mac::ExtAddress *>(aExtAddr)); |
| } |
| |
| void otClearMacWhitelist(void) |
| { |
| sThreadNetif->GetMac().GetWhitelist().Clear(); |
| } |
| |
| void otDisableMacWhitelist(void) |
| { |
| sThreadNetif->GetMac().GetWhitelist().Disable(); |
| } |
| |
| void otEnableMacWhitelist(void) |
| { |
| sThreadNetif->GetMac().GetWhitelist().Enable(); |
| } |
| |
| ThreadError otBecomeDetached(void) |
| { |
| return sThreadNetif->GetMle().BecomeDetached(); |
| } |
| |
| ThreadError otBecomeChild(otMleAttachFilter aFilter) |
| { |
| return sThreadNetif->GetMle().BecomeChild(aFilter); |
| } |
| |
| ThreadError otBecomeRouter(void) |
| { |
| return sThreadNetif->GetMle().BecomeRouter(); |
| } |
| |
| ThreadError otBecomeLeader(void) |
| { |
| return sThreadNetif->GetMle().BecomeLeader(); |
| } |
| |
| otDeviceRole otGetDeviceRole(void) |
| { |
| 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; |
| } |
| |
| uint8_t otGetLeaderRouterId(void) |
| { |
| return sThreadNetif->GetMle().GetLeaderDataTlv().GetLeaderRouterId(); |
| } |
| |
| uint8_t otGetLeaderWeight(void) |
| { |
| return sThreadNetif->GetMle().GetLeaderDataTlv().GetWeighting(); |
| } |
| |
| uint8_t otGetNetworkDataVersion(void) |
| { |
| return sThreadNetif->GetMle().GetLeaderDataTlv().GetDataVersion(); |
| } |
| |
| uint32_t otGetPartitionId(void) |
| { |
| return sThreadNetif->GetMle().GetLeaderDataTlv().GetPartitionId(); |
| } |
| |
| uint16_t otGetRloc16(void) |
| { |
| return sThreadNetif->GetMle().GetRloc16(); |
| } |
| |
| uint8_t otGetRouterIdSequence(void) |
| { |
| return sThreadNetif->GetMle().GetRouterIdSequence(); |
| } |
| |
| uint8_t otGetStableNetworkDataVersion(void) |
| { |
| return sThreadNetif->GetMle().GetLeaderDataTlv().GetStableDataVersion(); |
| } |
| |
| 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(void) |
| { |
| return sThreadNetif->GetUnicastAddresses(); |
| } |
| |
| ThreadError otAddUnicastAddress(otNetifAddress *address) |
| { |
| return sThreadNetif->AddUnicastAddress(*static_cast<Ip6::NetifUnicastAddress *>(address)); |
| } |
| |
| ThreadError otRemoveUnicastAddress(otNetifAddress *address) |
| { |
| return sThreadNetif->RemoveUnicastAddress(*static_cast<Ip6::NetifUnicastAddress *>(address)); |
| } |
| |
| ThreadError otEnable(void) |
| { |
| return sThreadNetif->Up(); |
| } |
| |
| ThreadError otDisable(void) |
| { |
| return sThreadNetif->Down(); |
| } |
| |
| ThreadError otActiveScan(uint16_t aScanChannels, uint16_t aScanDuration, otHandleActiveScanResult aCallback) |
| { |
| return sThreadNetif->GetMac().ActiveScan(aScanChannels, aScanDuration, &HandleActiveScanResult, |
| reinterpret_cast<void *>(aCallback)); |
| } |
| |
| bool otActiveScanInProgress(void) |
| { |
| return sThreadNetif->GetMac().IsActiveScanInProgress(); |
| } |
| |
| void HandleActiveScanResult(void *aContext, Mac::Frame *aFrame) |
| { |
| otHandleActiveScanResult handler = reinterpret_cast<otHandleActiveScanResult>(aContext); |
| otActiveScanResult result = {}; |
| Mac::Address address; |
| Mac::Beacon *beacon; |
| uint8_t payloadLength; |
| |
| if (aFrame == NULL) |
| { |
| handler(NULL); |
| 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(); |
| result.mNetworkName = beacon->GetNetworkName(); |
| result.mExtPanId = beacon->GetExtendedPanId(); |
| } |
| |
| handler(&result); |
| |
| exit: |
| return; |
| } |
| |
| void otSetReceiveIp6DatagramCallback(otReceiveIp6DatagramCallback aCallback) |
| { |
| Ip6::Ip6::SetReceiveDatagramCallback(aCallback); |
| } |
| |
| ThreadError otSendIp6Datagram(otMessage aMessage) |
| { |
| return Ip6::Ip6::HandleDatagram(*static_cast<Message *>(aMessage), NULL, sThreadNetif->GetInterfaceId(), |
| NULL, true); |
| } |
| |
| otMessage otNewUdpMessage(void) |
| { |
| return Ip6::Udp::NewMessage(0); |
| } |
| |
| ThreadError otFreeMessage(otMessage aMessage) |
| { |
| return Message::Free(*static_cast<Message *>(aMessage)); |
| } |
| |
| 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); |
| } |
| |
| int 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(otUdpSocket *aSocket, otUdpReceive aCallback, void *aContext) |
| { |
| Ip6::UdpSocket *socket = reinterpret_cast<Ip6::UdpSocket *>(aSocket); |
| return socket->Open(aCallback, aContext); |
| } |
| |
| ThreadError otCloseUdpSocket(otUdpSocket *aSocket) |
| { |
| Ip6::UdpSocket *socket = reinterpret_cast<Ip6::UdpSocket *>(aSocket); |
| return socket->Close(); |
| } |
| |
| ThreadError otBindUdpSocket(otUdpSocket *aSocket, otSockAddr *aSockName) |
| { |
| Ip6::UdpSocket *socket = reinterpret_cast<Ip6::UdpSocket *>(aSocket); |
| return socket->Bind(*reinterpret_cast<const Ip6::SockAddr *>(aSockName)); |
| } |
| |
| ThreadError otSendUdpMessage(otUdpSocket *aSocket, otMessage aMessage, const otMessageInfo *aMessageInfo) |
| { |
| Ip6::UdpSocket *socket = reinterpret_cast<Ip6::UdpSocket *>(aSocket); |
| return socket->SendTo(*reinterpret_cast<Message *>(aMessage), |
| *reinterpret_cast<const Ip6::MessageInfo *>(aMessageInfo)); |
| } |
| |
| #ifdef __cplusplus |
| } // extern "C" |
| #endif |
| |
| } // namespace Thread |