From 8c39011d9cd5a55be61c4e863c0904671a4d07f1 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Mon, 25 Jul 2016 17:52:47 -0700 Subject: [PATCH] Separate out interface up/down from Thread start/stop. (#278) * Redefine otEnable/otDisable to just initialize/uninitialize the OpenThread stack. * Remove otInit API since it is replaced by otEnable. * Add otInterfaceUp/otInterfaceDown APIs to bring up/down IPv6 interface. * Add otThreadStart/otThreadStop APIs to start/stop Thread protocol operation. * Updated NCP implementation to utilize new APIs. --- examples/apps/cli/README.md | 22 +++++++-- examples/apps/cli/main.c | 2 +- examples/apps/ncp/main.c | 2 +- include/openthread.h | 72 ++++++++++++++++++++++++---- src/cli/README.md | 34 +++++++++---- src/cli/cli.cpp | 57 ++++++++++++++++------ src/cli/cli.hpp | 4 +- src/core/openthread.cpp | 80 ++++++++++++++++++++++++++----- src/core/thread/mle.cpp | 13 +++-- src/core/thread/thread_netif.cpp | 9 +++- src/ncp/ncp_base.cpp | 59 ++++++++++++----------- tests/scripts/thread-cert/node.py | 8 +++- 12 files changed, 271 insertions(+), 91 deletions(-) diff --git a/examples/apps/cli/README.md b/examples/apps/cli/README.md index 269a66fd5..86af4037f 100644 --- a/examples/apps/cli/README.md +++ b/examples/apps/cli/README.md @@ -23,10 +23,17 @@ $ cd /output//bin $ ./ot-cli 1 ``` -Start OpenThread: +Bring up the IPv6 interface: ```bash -> start +> ifconfig up +Done +``` + +Start Thread protocol operation: + +```bash +> thread start Done ``` @@ -58,10 +65,17 @@ $ cd /output//bin $ ./ot-cli 2 ``` -Start OpenThread: +Bring up the IPv6 interface: ```bash -> start +> ifconfig up +Done +``` + +Start Thread protocol operation: + +```bash +> thread start Done ``` diff --git a/examples/apps/cli/main.c b/examples/apps/cli/main.c index b02aec7e3..63647287b 100644 --- a/examples/apps/cli/main.c +++ b/examples/apps/cli/main.c @@ -37,7 +37,7 @@ void otSignalTaskletPending(void) int main(int argc, char *argv[]) { PlatformInit(argc, argv); - otInit(); + otEnable(); otCliUartInit(); while (1) diff --git a/examples/apps/ncp/main.c b/examples/apps/ncp/main.c index e8e03c1fb..cc7b1d884 100644 --- a/examples/apps/ncp/main.c +++ b/examples/apps/ncp/main.c @@ -37,7 +37,7 @@ void otSignalTaskletPending(void) int main(int argc, char *argv[]) { PlatformInit(argc, argv); - otInit(); + otEnable(); otNcpInit(); while (1) diff --git a/include/openthread.h b/include/openthread.h index 89c116e14..5fd68d1f2 100644 --- a/include/openthread.h +++ b/include/openthread.h @@ -111,11 +111,6 @@ extern "C" { * */ -/** - * Initialize the OpenThread library. - */ -void otInit(void); - /** * Run the next queued tasklet in OpenThread. */ @@ -151,19 +146,78 @@ extern void otSignalTaskletPending(void); */ /** - * Enable the Thread interface. + * This function initializes the OpenThread library. + * + * This function initializes OpenThread and prepares it for subsequent OpenThread API calls. This function must be + * called before any other calls to OpenThread. + * + * @retval kThreadError_None Successfully enabled the Thread interface. * - * @retval kThreadErrorNone Successfully enabled the Thread interface. */ ThreadError otEnable(void); /** - * Disable the Thread interface. + * This function disables the OpenThread library. + * + * Call this function when OpenThread is no longer in use. The client must call otEnable() to use OpenThread + * again. + * + * @retval kThreadError_None Successfully disabled the Thread interface. * - * @retval kThreadErrorNone Successfully disabled the Thread interface. */ ThreadError otDisable(void); +/** + * This function brings up the IPv6 interface. + * + * Call this function to bring up the IPv6 interface and enables IPv6 communication. + * + * @retval kThreadError_None Successfully enabled the IPv6 interface. + * @retval kThreadError_InvalidState OpenThread is not enabled or the IPv6 interface is already up. + * + */ +ThreadError otInterfaceUp(void); + +/** + * This function brings down the IPv6 interface. + * + * Call this function to bring down the IPv6 interface and disable all IPv6 communication. + * + * @retval kThreadError_None Successfully brought the interface down. + * @retval kThreadError_InvalidState The interface was not up. + * + */ +ThreadError otInterfaceDown(void); + +/** + * This function indicates whether or not the IPv6 interface is up. + * + * @retval TRUE The IPv6 interface is up. + * @retval FALSE The IPv6 interface is down. + * + */ +bool otIsInterfaceUp(void); + +/** + * This function starts Thread protocol operation. + * + * The interface must be up when calling this function. + * + * @retval kThreadError_None Successfully started Thread protocol operation. + * @retval kThreadError_InvalidState Thread protocol operation is already started or the interface is not up. + * + */ +ThreadError otThreadStart(void); + +/** + * This function stops Thread protocol operation. + * + * @retval kThreadError_None Successfully stopped Thread protocol operation. + * @retval kThreadError_InvalidState The Thread protocol operation was not started. + * + */ +ThreadError otThreadStop(void); + /** * This function pointer is called during an IEEE 802.15.4 Active Scan when an IEEE 802.15.4 Beacon is received or * the scan completes. diff --git a/src/cli/README.md b/src/cli/README.md index 03e71ce8d..205e5030b 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -15,6 +15,7 @@ OpenThread test scripts use the CLI to execute test cases. * [eidcache](#eidcache) * [extaddr](#extaddr) * [extpanid](#extpanid) +* [ifconfig](#ifconfig) * [ipaddr](#ipaddr) * [keysequence](#keysequence) * [leaderweight](#leaderweight) @@ -32,9 +33,8 @@ OpenThread test scripts use the CLI to execute test cases. * [router](#router) * [routerupgradethreshold](#routerupgradethreshold) * [scan](#scan) -* [start](#start) * [state](#state) -* [stop](#stop) +* [thread](#thread) * [version](#version) * [whitelist](#whitelist) @@ -208,6 +208,24 @@ Set the Thread Extended PAN ID value. Done ``` +### ifconfig up + +Bring up the IPv6 interface. + +```bash +> ifconfig up +Done +``` + +### ifconfig down + +Bring down the IPv6 interface. + +```bash +> ifconfig down +Done +``` + ### ipaddr List all IPv6 addresses assigned to the Thread interface. @@ -541,21 +559,21 @@ Perform an IEEE 802.15.4 Active Scan. Done ``` -### start +### thread start -Enable OpenThread. +Enable Thread protocol operation and attach to a Thread network. ```bash -> start +> thread start Done ``` -### stop +### thread stop -Disable OpenThread. +Disable Thread protocol operation and detach from a Thread network. ```bash -> stop +> thread stop Done ``` diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index dcfad09dd..18ce443ea 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -59,6 +59,7 @@ const struct Command Interpreter::sCommands[] = { "eidcache", &ProcessEidCache }, { "extaddr", &ProcessExtAddress }, { "extpanid", &ProcessExtPanId }, + { "ifconfig", &ProcessIfconfig }, { "ipaddr", &ProcessIpAddr }, { "keysequence", &ProcessKeySequence }, { "leaderdata", &ProcessLeaderData }, @@ -77,9 +78,8 @@ const struct Command Interpreter::sCommands[] = { "router", &ProcessRouter }, { "routerupgradethreshold", &ProcessRouterUpgradeThreshold }, { "scan", &ProcessScan }, - { "start", &ProcessStart }, { "state", &ProcessState }, - { "stop", &ProcessStop }, + { "thread", &ProcessThread }, { "version", &ProcessVersion }, { "whitelist", &ProcessWhitelist }, }; @@ -408,6 +408,34 @@ exit: AppendResult(error); } +void Interpreter::ProcessIfconfig(int argc, char *argv[]) +{ + ThreadError error = kThreadError_Parse; + + if (argc == 0) + { + if (otIsInterfaceUp()) + { + sServer->OutputFormat("up\r\n"); + } + else + { + sServer->OutputFormat("down\r\n"); + } + } + else if (strcmp(argv[0], "up") == 0) + { + SuccessOrExit(error = otInterfaceUp()); + } + else if (strcmp(argv[0], "down") == 0) + { + SuccessOrExit(error = otInterfaceDown()); + } + +exit: + AppendResult(error); +} + ThreadError Interpreter::ProcessIpAddrAdd(int argc, char *argv[]) { ThreadError error; @@ -1192,16 +1220,6 @@ exit: return; } -void Interpreter::ProcessStart(int argc, char *argv[]) -{ - ThreadError error = kThreadError_None; - - SuccessOrExit(error = otEnable()); - -exit: - AppendResult(error); -} - void Interpreter::ProcessState(int argc, char *argv[]) { ThreadError error = kThreadError_None; @@ -1259,11 +1277,20 @@ exit: AppendResult(error); } -void Interpreter::ProcessStop(int argc, char *argv[]) +void Interpreter::ProcessThread(int argc, char *argv[]) { - ThreadError error = kThreadError_None; + ThreadError error = kThreadError_Parse; - SuccessOrExit(error = otDisable()); + VerifyOrExit(argc > 0, error = kThreadError_Parse); + + if (strcmp(argv[0], "start") == 0) + { + SuccessOrExit(error = otThreadStart()); + } + else if (strcmp(argv[0], "stop") == 0) + { + SuccessOrExit(error = otThreadStop()); + } exit: AppendResult(error); diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index 62894d3cd..fd84af514 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -96,6 +96,7 @@ private: static void ProcessEidCache(int argc, char *argv[]); static void ProcessExtAddress(int argc, char *argv[]); static void ProcessExtPanId(int argc, char *argv[]); + static void ProcessIfconfig(int argc, char *argv[]); static void ProcessIpAddr(int argc, char *argv[]); static ThreadError ProcessIpAddrAdd(int argc, char *argv[]); static ThreadError ProcessIpAddrDel(int argc, char *argv[]); @@ -120,9 +121,8 @@ private: static void ProcessRouterUpgradeThreshold(int argc, char *argv[]); static void ProcessRloc16(int argc, char *argv[]); static void ProcessScan(int argc, char *argv[]); - static void ProcessStart(int argc, char *argv[]); static void ProcessState(int argc, char *argv[]); - static void ProcessStop(int argc, char *argv[]); + static void ProcessThread(int argc, char *argv[]); static void ProcessVersion(int argc, char *argv[]); static void ProcessWhitelist(int argc, char *argv[]); diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index ec7b6ea3c..569fad5bb 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -51,6 +51,7 @@ namespace Thread { ThreadNetif *sThreadNetif; static Ip6::NetifCallback sNetifCallback; +static bool mEnabled = false; #ifdef __cplusplus extern "C" { @@ -60,13 +61,6 @@ 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(); @@ -657,10 +651,12 @@ ThreadError otEnable(void) { ThreadError error = kThreadError_None; - // cannot enable the Thread stack if IEEE 802.15.4 promiscuous mode is enabled - VerifyOrExit(otPlatRadioGetPromiscuous() == false, error = kThreadError_Busy); + VerifyOrExit(!mEnabled, error = kThreadError_InvalidState); - SuccessOrExit(error = sThreadNetif->Up()); + otLogInfoApi("otEnable\n"); + Message::Init(); + sThreadNetif = new(&sThreadNetifRaw) ThreadNetif; + mEnabled = true; exit: return error; @@ -668,7 +664,69 @@ exit: ThreadError otDisable(void) { - return sThreadNetif->Down(); + ThreadError error = kThreadError_None; + + VerifyOrExit(mEnabled, error = kThreadError_InvalidState); + + otThreadStop(); + otInterfaceDown(); + mEnabled = false; + +exit: + return error; +} + +ThreadError otInterfaceUp(void) +{ + ThreadError error = kThreadError_None; + + VerifyOrExit(mEnabled, error = kThreadError_InvalidState); + + error = sThreadNetif->Up(); + +exit: + return error; +} + +ThreadError otInterfaceDown(void) +{ + ThreadError error = kThreadError_None; + + VerifyOrExit(mEnabled, error = kThreadError_InvalidState); + + error = sThreadNetif->Down(); + +exit: + return error; +} + +bool otIsInterfaceUp(void) +{ + return mEnabled && sThreadNetif->IsUp(); +} + +ThreadError otThreadStart(void) +{ + ThreadError error = kThreadError_None; + + VerifyOrExit(mEnabled, error = kThreadError_InvalidState); + + error = sThreadNetif->GetMle().Start(); + +exit: + return error; +} + +ThreadError otThreadStop(void) +{ + ThreadError error = kThreadError_None; + + VerifyOrExit(mEnabled, error = kThreadError_InvalidState); + + error = sThreadNetif->GetMle().Stop(); + +exit: + return error; } ThreadError otActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, otHandleActiveScanResult aCallback) diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 1d98e8de9..35691beec 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -144,6 +145,10 @@ ThreadError Mle::Start(void) ThreadError error = kThreadError_None; Ip6::SockAddr sockaddr; + // cannot bring up the interface if IEEE 802.15.4 promiscuous mode is enabled + VerifyOrExit(otPlatRadioGetPromiscuous() == false, error = kThreadError_Busy); + VerifyOrExit(mNetif.IsUp(), error = kThreadError_InvalidState); + // memcpy(&sockaddr.mAddr, &mLinkLocal64.GetAddress(), sizeof(sockaddr.mAddr)); sockaddr.mPort = kUdpPort; SuccessOrExit(error = mSocket.Open(&HandleUdpReceive, this)); @@ -173,18 +178,12 @@ exit: ThreadError Mle::Stop(void) { - ThreadError error = kThreadError_None; - - VerifyOrExit(mDeviceState != kDeviceStateDisabled, error = kThreadError_Busy); - SetStateDetached(); mSocket.Close(); mNetif.RemoveUnicastAddress(mLinkLocal16); mNetif.RemoveUnicastAddress(mMeshLocal16); mDeviceState = kDeviceStateDisabled; - -exit: - return error; + return kThreadError_None; } ThreadError Mle::BecomeDetached(void) diff --git a/src/core/thread/thread_netif.cpp b/src/core/thread/thread_netif.cpp index 5c9bad8f2..65731659e 100644 --- a/src/core/thread/thread_netif.cpp +++ b/src/core/thread/thread_netif.cpp @@ -74,12 +74,17 @@ const char *ThreadNetif::GetName(void) const ThreadError ThreadNetif::Up(void) { + ThreadError error = kThreadError_None; + + VerifyOrExit(!mIsUp, error = kThreadError_InvalidState); + Netif::AddNetif(); mMeshForwarder.Start(); - mMleRouter.Start(); mCoapServer.Start(); mIsUp = true; - return kThreadError_None; + +exit: + return error; } ThreadError ThreadNetif::Down(void) diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 2ad275c5a..272013c93 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -869,7 +869,8 @@ void NcpBase::CommandHandler_NOOP(uint8_t header, unsigned int command, const ui void NcpBase::CommandHandler_RESET(uint8_t header, unsigned int command, const uint8_t *arg_ptr, uint16_t arg_len) { // TODO: Figure out how to actually perform a reset. - otInit(); + otDisable(); + otEnable(); SendLastStatus(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_STATUS_RESET_SOFTWARE); } @@ -1268,7 +1269,7 @@ void NcpBase::GetPropertyHandler_NET_ENABLED(uint8_t header, spinel_prop_key_t k SPINEL_CMD_PROP_VALUE_IS, key, SPINEL_DATATYPE_BOOL_S, - (otGetDeviceRole() != kDeviceRoleDisabled) + otIsInterfaceUp() ); } @@ -1276,21 +1277,25 @@ void NcpBase::GetPropertyHandler_NET_STATE(uint8_t header, spinel_prop_key_t key { spinel_net_state_t state(SPINEL_NET_STATE_OFFLINE); - switch (otGetDeviceRole()) + if (!otInterfaceUp()) { - case kDeviceRoleDisabled: state = SPINEL_NET_STATE_OFFLINE; - break; + } + else + { + switch (otGetDeviceRole()) + { + case kDeviceRoleDisabled: + case kDeviceRoleDetached: + state = SPINEL_NET_STATE_DETACHED; + break; - case kDeviceRoleDetached: - state = SPINEL_NET_STATE_DETACHED; - break; - - case kDeviceRoleChild: - case kDeviceRoleRouter: - case kDeviceRoleLeader: - state = SPINEL_NET_STATE_ATTACHED; - break; + case kDeviceRoleChild: + case kDeviceRoleRouter: + case kDeviceRoleLeader: + state = SPINEL_NET_STATE_ATTACHED; + break; + } } SendPropteryUpdate( @@ -2170,40 +2175,36 @@ void NcpBase::SetPropertyHandler_NET_STATE(uint8_t header, spinel_prop_key_t key switch (i) { case SPINEL_NET_STATE_OFFLINE: - if (otGetDeviceRole() != kDeviceRoleDisabled) + if (otIsInterfaceUp()) { - errorCode = otDisable(); + errorCode = otInterfaceDown(); } break; case SPINEL_NET_STATE_DETACHED: - if (otGetDeviceRole() == kDeviceRoleDisabled) + if (!otIsInterfaceUp()) { - errorCode = otEnable(); - - if (errorCode == kThreadError_None) - { - errorCode = otBecomeDetached(); - } + errorCode = otInterfaceUp(); } - else if (otGetDeviceRole() != kDeviceRoleDetached) + + if ((errorCode == kThreadError_None) && (otGetDeviceRole() != kDeviceRoleDisabled)) { - errorCode = otBecomeDetached(); + errorCode = otThreadStop(); } break; case SPINEL_NET_STATE_ATTACHING: case SPINEL_NET_STATE_ATTACHED: - if (otGetDeviceRole() == kDeviceRoleDisabled) + if (!otIsInterfaceUp()) { - errorCode = otEnable(); + errorCode = otInterfaceUp(); } - if (otGetDeviceRole() == kDeviceRoleDetached) + if ((errorCode == kThreadError_None) && (otGetDeviceRole() == kDeviceRoleDetached)) { - errorCode = otBecomeRouter(); + errorCode = otThreadStart(); if (errorCode == kThreadError_None) { diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index 83282140d..9026229ed 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -94,11 +94,15 @@ class Node: self.pexpect.expect('Done') def start(self): - self.send_command('start') + self.send_command('ifconfig up') + self.pexpect.expect('Done') + self.send_command('thread start') self.pexpect.expect('Done') def stop(self): - self.send_command('stop') + self.send_command('thread stop') + self.pexpect.expect('Done') + self.send_command('ifconfig down') self.pexpect.expect('Done') def clear_whitelist(self):