diff --git a/examples/light-switch-app/efr32/build_for_wifi_gnfile.gn b/examples/light-switch-app/efr32/build_for_wifi_gnfile.gn index 9752ee73e7c91d..d391814190d09f 100644 --- a/examples/light-switch-app/efr32/build_for_wifi_gnfile.gn +++ b/examples/light-switch-app/efr32/build_for_wifi_gnfile.gn @@ -23,6 +23,6 @@ check_system_includes = true default_args = { target_cpu = "arm" target_os = "freertos" - use_thread = false + chip_enable_wifi = true import("//build_for_wifi_args.gni") } diff --git a/examples/lighting-app/telink/CMakeLists.txt b/examples/lighting-app/telink/CMakeLists.txt index cad8cc224805ae..1783b09f5e8527 100644 --- a/examples/lighting-app/telink/CMakeLists.txt +++ b/examples/lighting-app/telink/CMakeLists.txt @@ -93,6 +93,7 @@ target_sources(app PRIVATE ${CHIP_ROOT}/src/app/clusters/level-control/level-control.cpp ${CHIP_ROOT}/src/app/clusters/color-control-server/color-control-server.cpp ${CHIP_ROOT}/src/app/clusters/occupancy-sensor-server/occupancy-sensor-server.cpp + ${CHIP_ROOT}/src/app/clusters/network-commissioning/network-commissioning.cpp ${CHIP_ROOT}/src/app/clusters/network-commissioning-old/network-commissioning-ember.cpp ${CHIP_ROOT}/src/app/clusters/network-commissioning-old/network-commissioning-old.cpp ${CHIP_ROOT}/src/app/clusters/ota-requestor/ota-requestor-server.cpp diff --git a/examples/lock-app/efr32/build_for_wifi_gnfile.gn b/examples/lock-app/efr32/build_for_wifi_gnfile.gn index 9752ee73e7c91d..d391814190d09f 100644 --- a/examples/lock-app/efr32/build_for_wifi_gnfile.gn +++ b/examples/lock-app/efr32/build_for_wifi_gnfile.gn @@ -23,6 +23,6 @@ check_system_includes = true default_args = { target_cpu = "arm" target_os = "freertos" - use_thread = false + chip_enable_wifi = true import("//build_for_wifi_args.gni") } diff --git a/examples/persistent-storage/qpg/args.gni b/examples/persistent-storage/qpg/args.gni index b0d121b1029802..4918e5af9de27b 100644 --- a/examples/persistent-storage/qpg/args.gni +++ b/examples/persistent-storage/qpg/args.gni @@ -16,3 +16,4 @@ import("//build_overrides/chip.gni") import("${chip_root}/examples/platform/qpg/args.gni") qpg_sdk_target = get_label_info(":sdk", "label_no_toolchain") +chip_enable_openthread = false diff --git a/examples/shell/efr32/BUILD.gn b/examples/shell/efr32/BUILD.gn index 64e73d4cfbb981..ea683bed9362cf 100644 --- a/examples/shell/efr32/BUILD.gn +++ b/examples/shell/efr32/BUILD.gn @@ -49,7 +49,6 @@ efr32_sdk("sdk") { defines = [ "BOARD_ID=${efr32_board}", "OPENTHREAD_CONFIG_CLI_TRANSPORT=OT_CLI_TRANSPORT_CONSOLE", - "ENABLE_CHIP_SHELL", ] } diff --git a/examples/shell/efr32/args.gni b/examples/shell/efr32/args.gni index 1b73ad66dcea58..9d49561c413334 100644 --- a/examples/shell/efr32/args.gni +++ b/examples/shell/efr32/args.gni @@ -22,3 +22,4 @@ pw_log_BACKEND = "${chip_root}/src/lib/support/pw_log_chip" pw_assert_BACKEND = "$dir_pw_assert_log" chip_enable_openthread = true chip_openthread_ftd = true +chip_build_libshell = true diff --git a/examples/shell/efr32/include/CHIPProjectConfig.h b/examples/shell/efr32/include/CHIPProjectConfig.h index e5be53a055f434..b47c348e6df34c 100644 --- a/examples/shell/efr32/include/CHIPProjectConfig.h +++ b/examples/shell/efr32/include/CHIPProjectConfig.h @@ -113,3 +113,5 @@ * A size, in bytes, of the individual debug event logging buffer. */ #define CHIP_DEVICE_CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE (512) + +#define _NO_NETWORK_COMMISSIONING_DRIVER_ diff --git a/examples/shell/mbed/CMakeLists.txt b/examples/shell/mbed/CMakeLists.txt index 18397ba9b8d689..fbd5b2576ecf9b 100644 --- a/examples/shell/mbed/CMakeLists.txt +++ b/examples/shell/mbed/CMakeLists.txt @@ -21,6 +21,7 @@ include(${MBED_PATH}/tools/cmake/app.cmake) project(${APP_TARGET}) + add_subdirectory(${MBED_PATH} ./mbed_build) add_subdirectory(${MBED_OS_POSIX_SOCKET_PATH} ./mbed_os_posix_socket_build) diff --git a/examples/shell/mbed/main/include/CHIPProjectConfig.h b/examples/shell/mbed/main/include/CHIPProjectConfig.h index ab3dbbecc38342..44bf03fc40b208 100644 --- a/examples/shell/mbed/main/include/CHIPProjectConfig.h +++ b/examples/shell/mbed/main/include/CHIPProjectConfig.h @@ -33,3 +33,7 @@ // Use a default pairing code if one hasn't been provisioned in flash. #define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 #define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 + +// shell app uses openthread but does not have the NETWORK_COMMISSIONING cluster or zap config +// Do not instantiate the NETWORK_COMMISSIONING thread driver +#define _NO_NETWORK_COMMISSIONING_DRIVER_ diff --git a/examples/shell/nrfconnect/CHIPProjectConfig.h b/examples/shell/nrfconnect/CHIPProjectConfig.h index cc90aa590dfd57..4b35fcd6a8cf58 100644 --- a/examples/shell/nrfconnect/CHIPProjectConfig.h +++ b/examples/shell/nrfconnect/CHIPProjectConfig.h @@ -42,3 +42,7 @@ * 0x4E53: nrfconnect shell */ #define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x4E53 + +// shell app uses openthread but does not have the NETWORK_COMMISSIONING cluster or zap config +// Do not instantiate the NETWORK_COMMISSIONING thread driver +#define _NO_NETWORK_COMMISSIONING_DRIVER_ diff --git a/examples/shell/nxp/k32w/k32w0/BUILD.gn b/examples/shell/nxp/k32w/k32w0/BUILD.gn index dbb85ebe56be38..505373a42bf860 100644 --- a/examples/shell/nxp/k32w/k32w0/BUILD.gn +++ b/examples/shell/nxp/k32w/k32w0/BUILD.gn @@ -44,7 +44,11 @@ k32w0_sdk("sdk") { "${k32w0_platform_dir}/util/include", ] - defines = [] + defines = [ + # shell app uses openthread but does not have the NETWORK_COMMISSIONING cluster or zap config. + "_NO_NETWORK_COMMISSIONING_DRIVER_", + ] + if (is_debug) { defines += [ "BUILD_RELEASE=0" ] } else { diff --git a/examples/window-app/efr32/build_for_wifi_gnfile.gn b/examples/window-app/efr32/build_for_wifi_gnfile.gn index 9752ee73e7c91d..d391814190d09f 100644 --- a/examples/window-app/efr32/build_for_wifi_gnfile.gn +++ b/examples/window-app/efr32/build_for_wifi_gnfile.gn @@ -23,6 +23,6 @@ check_system_includes = true default_args = { target_cpu = "arm" target_os = "freertos" - use_thread = false + chip_enable_wifi = true import("//build_for_wifi_args.gni") } diff --git a/src/include/platform/ThreadStackManager.h b/src/include/platform/ThreadStackManager.h index f9db5e3df3c6e7..e4c0e4696ab3c0 100644 --- a/src/include/platform/ThreadStackManager.h +++ b/src/include/platform/ThreadStackManager.h @@ -27,6 +27,7 @@ #include #include #include +#include namespace chip { @@ -88,6 +89,9 @@ class ThreadStackManager bool TryLockThreadStack(); void UnlockThreadStack(); bool HaveRouteToAddress(const chip::Inet::IPAddress & destAddr); + bool IsThreadEnabled(); + bool IsThreadProvisioned(); + bool IsThreadAttached(); CHIP_ERROR GetThreadProvision(ByteSpan & netInfo); CHIP_ERROR GetAndLogThreadStatsCounters(); CHIP_ERROR GetAndLogThreadTopologyMinimal(); @@ -99,6 +103,9 @@ class ThreadStackManager CHIP_ERROR JoinerStart(); CHIP_ERROR SetThreadProvision(ByteSpan aDataset); CHIP_ERROR SetThreadEnabled(bool val); + CHIP_ERROR AttachToThreadNetwork(ByteSpan netInfo, NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * callback); + CHIP_ERROR StartThreadScan(NetworkCommissioning::ThreadDriver::ScanCallback * callback); + void OnThreadAttachFinished(void); #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT CHIP_ERROR AddSrpService(const char * aInstanceName, const char * aName, uint16_t aPort, @@ -145,9 +152,6 @@ class ThreadStackManager friend class Internal::GenericThreadStackManagerImpl_FreeRTOS; void OnPlatformEvent(const ChipDeviceEvent * event); - bool IsThreadEnabled(); - bool IsThreadProvisioned(); - bool IsThreadAttached(); void ErasePersistentInfo(); ConnectivityManager::ThreadDeviceType GetThreadDeviceType(); CHIP_ERROR SetThreadDeviceType(ConnectivityManager::ThreadDeviceType threadRole); @@ -347,6 +351,23 @@ inline CHIP_ERROR ThreadStackManager::SetThreadProvision(ByteSpan netInfo) return static_cast(this)->_SetThreadProvision(netInfo); } +inline CHIP_ERROR +ThreadStackManager::AttachToThreadNetwork(ByteSpan netInfo, + NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * callback) +{ + return static_cast(this)->_AttachToThreadNetwork(netInfo, callback); +} + +inline void ThreadStackManager::OnThreadAttachFinished(void) +{ + static_cast(this)->_OnThreadAttachFinished(); +} + +inline CHIP_ERROR ThreadStackManager::StartThreadScan(NetworkCommissioning::ThreadDriver::ScanCallback * callback) +{ + return static_cast(this)->_StartThreadScan(callback); +} + inline void ThreadStackManager::ErasePersistentInfo() { static_cast(this)->_ErasePersistentInfo(); diff --git a/src/include/platform/internal/GenericConnectivityManagerImpl_Thread.cpp b/src/include/platform/internal/GenericConnectivityManagerImpl_Thread.cpp index b02aed72f903a3..1eb0f3f89242bb 100644 --- a/src/include/platform/internal/GenericConnectivityManagerImpl_Thread.cpp +++ b/src/include/platform/internal/GenericConnectivityManagerImpl_Thread.cpp @@ -44,6 +44,11 @@ void GenericConnectivityManagerImpl_Thread::_OnPlatformEvent(const Ch (event->Type == DeviceEventType::kThreadStateChange && event->ThreadStateChange.NetDataChanged); const bool fabricMembershipChanged = (event->Type == DeviceEventType::kFabricMembershipChange); + if (threadConnChanged && event->ThreadConnectivityChange.Result == kConnectivity_Established) + { + ThreadStackMgrImpl().OnThreadAttachFinished(); + } + // If any of the above events has occurred, assess whether there's been a change in // service connectivity via Thread. if (threadConnChanged || threadAddrChanged || threadNetDataChanged || fabricMembershipChanged) diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn index 5709d0544f4b78..730c5df69932ff 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -301,6 +301,14 @@ if (chip_device_platform != "none") { "PlatformEventSupport.cpp", ] + # Linux has its own NetworkCommissioningThreadDriver + if (chip_enable_openthread && chip_device_platform != "linux") { + sources += [ + "OpenThread/GenericNetworkCommissioningThreadDriver.cpp", + "OpenThread/GenericNetworkCommissioningThreadDriver.h", + ] + } + if (chip_enable_ota_requestor) { sources += [ "GenericOTARequestorDriver.cpp", diff --git a/src/platform/EFR32/BUILD.gn b/src/platform/EFR32/BUILD.gn index 00469606e03597..172b94bdb82dce 100644 --- a/src/platform/EFR32/BUILD.gn +++ b/src/platform/EFR32/BUILD.gn @@ -95,7 +95,9 @@ static_library("EFR32") { sources += [ "../OpenThread/DnssdImpl.cpp" ] deps += [ "${chip_root}/src/lib/dnssd:platform_header" ] } - } else { + } + + if (chip_enable_wifi) { sources += [ "ConnectivityManagerImpl_WIFI.cpp", "ServiceProvisioning.cpp", diff --git a/src/platform/EFR32/CHIPDevicePlatformConfig.h b/src/platform/EFR32/CHIPDevicePlatformConfig.h index 74521d1da33f60..f6e5b9619ab079 100644 --- a/src/platform/EFR32/CHIPDevicePlatformConfig.h +++ b/src/platform/EFR32/CHIPDevicePlatformConfig.h @@ -29,12 +29,13 @@ #define CHIP_DEVICE_CONFIG_EFR32_NVM3_ERROR_MIN 0xB00000 #define CHIP_DEVICE_CONFIG_EFR32_BLE_ERROR_MIN 0xC00000 +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION 0 +#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP 0 + #if defined(SL_WIFI) #define CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION 1 #elif CHIP_ENABLE_OPENTHREAD -#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION 0 -#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP 0 #define CHIP_DEVICE_CONFIG_ENABLE_THREAD 1 #define CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT 1 #define CHIP_DEVICE_CONFIG_ENABLE_THREAD_DNS_CLIENT 1 diff --git a/src/platform/EFR32/ThreadStackManagerImpl.cpp b/src/platform/EFR32/ThreadStackManagerImpl.cpp index da08ecfa0f930b..fbd89807260177 100644 --- a/src/platform/EFR32/ThreadStackManagerImpl.cpp +++ b/src/platform/EFR32/ThreadStackManagerImpl.cpp @@ -28,7 +28,6 @@ #include #include - #include #include diff --git a/src/platform/Linux/ThreadStackManagerImpl.cpp b/src/platform/Linux/ThreadStackManagerImpl.cpp index d50aed7be164c4..29114d00c7051a 100644 --- a/src/platform/Linux/ThreadStackManagerImpl.cpp +++ b/src/platform/Linux/ThreadStackManagerImpl.cpp @@ -289,7 +289,7 @@ CHIP_ERROR ThreadStackManagerImpl::_SetThreadEnabled(bool val) VerifyOrReturnError(mProxy, CHIP_ERROR_INCORRECT_STATE); if (val) { - openthread_io_openthread_border_router_call_attach(mProxy.get(), nullptr, _OnThreadAttachFinished, this); + openthread_io_openthread_border_router_call_attach(mProxy.get(), nullptr, _OnThreadBrAttachFinished, this); } else { @@ -311,7 +311,7 @@ CHIP_ERROR ThreadStackManagerImpl::_SetThreadEnabled(bool val) return CHIP_NO_ERROR; } -void ThreadStackManagerImpl::_OnThreadAttachFinished(GObject * source_object, GAsyncResult * res, gpointer user_data) +void ThreadStackManagerImpl::_OnThreadBrAttachFinished(GObject * source_object, GAsyncResult * res, gpointer user_data) { ThreadStackManagerImpl * this_ = reinterpret_cast(user_data); std::unique_ptr attachRes; @@ -507,7 +507,7 @@ CHIP_ERROR ThreadStackManagerImpl::_JoinerStart() return CHIP_ERROR_NOT_IMPLEMENTED; } -CHIP_ERROR ThreadStackManagerImpl::StartThreadScan(ThreadDriver::ScanCallback * callback) +CHIP_ERROR ThreadStackManagerImpl::_StartThreadScan(ThreadDriver::ScanCallback * callback) { // There is another ongoing scan request, reject the new one. VerifyOrReturnError(mpScanCallback == nullptr, CHIP_ERROR_INCORRECT_STATE); @@ -637,8 +637,8 @@ CHIP_ERROR ThreadStackManagerImpl::_WriteThreadNetworkDiagnosticAttributeToTlv(A } CHIP_ERROR -ThreadStackManagerImpl::AttachToThreadNetwork(ByteSpan netInfo, - NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * callback) +ThreadStackManagerImpl::_AttachToThreadNetwork(ByteSpan netInfo, + NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * callback) { // There is another ongoing connect request, reject the new one. VerifyOrReturnError(mpConnectCallback == nullptr, CHIP_ERROR_INCORRECT_STATE); diff --git a/src/platform/Linux/ThreadStackManagerImpl.h b/src/platform/Linux/ThreadStackManagerImpl.h index caac53708b9922..e725bb5d72f64d 100644 --- a/src/platform/Linux/ThreadStackManagerImpl.h +++ b/src/platform/Linux/ThreadStackManagerImpl.h @@ -65,10 +65,13 @@ class ThreadStackManagerImpl : public ThreadStackManager bool _IsThreadAttached(); - CHIP_ERROR AttachToThreadNetwork(ByteSpan netInfo, NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * callback); + CHIP_ERROR _AttachToThreadNetwork(ByteSpan netInfo, NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * callback); CHIP_ERROR _SetThreadEnabled(bool val); - static void _OnThreadAttachFinished(GObject * source_object, GAsyncResult * res, gpointer user_data); + + void _OnThreadAttachFinished(void); + + static void _OnThreadBrAttachFinished(GObject * source_object, GAsyncResult * res, gpointer user_data); ConnectivityManager::ThreadDeviceType _GetThreadDeviceType(); @@ -100,7 +103,7 @@ class ThreadStackManagerImpl : public ThreadStackManager CHIP_ERROR _WriteThreadNetworkDiagnosticAttributeToTlv(AttributeId attributeId, app::AttributeValueEncoder & encoder); - CHIP_ERROR StartThreadScan(NetworkCommissioning::ThreadDriver::ScanCallback * callback); + CHIP_ERROR _StartThreadScan(NetworkCommissioning::ThreadDriver::ScanCallback * callback); ~ThreadStackManagerImpl() = default; @@ -145,5 +148,10 @@ class ThreadStackManagerImpl : public ThreadStackManager bool mAttached; }; +inline void ThreadStackManagerImpl::_OnThreadAttachFinished(void) +{ + // stub for ThreadStackManager.h +} + } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp new file mode 100644 index 00000000000000..ccb3a408e7ecc3 --- /dev/null +++ b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp @@ -0,0 +1,194 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace chip; +using namespace chip::Thread; + +namespace chip { +namespace DeviceLayer { +namespace NetworkCommissioning { +// NOTE: For ThreadDriver, we use two network configs, one is mSavedNetwork, and another is mStagingNetwork, during init, it will +// load the network config from thread persistent info, and loads it into both mSavedNetwork and mStagingNetwork. When updating the +// networks, all changes are made on the staging network. When validated we can commit it and save it to the persistent info + +CHIP_ERROR GenericThreadDriver::Init() +{ + ByteSpan currentProvision; + VerifyOrReturnError(ThreadStackMgrImpl().IsThreadAttached(), CHIP_NO_ERROR); + VerifyOrReturnError(ThreadStackMgrImpl().GetThreadProvision(currentProvision) == CHIP_NO_ERROR, CHIP_NO_ERROR); + + mSavedNetwork.Init(currentProvision); + mStagingNetwork.Init(currentProvision); + + return CHIP_NO_ERROR; +} + +CHIP_ERROR GenericThreadDriver::CommitConfiguration() +{ + // Note: on AttachToThreadNetwork OpenThread will persist the networks on its own, + // we don't have much to do for saving the networks (see Init() above, + // we just load the saved dataset from ot instance.) + mSavedNetwork = mStagingNetwork; + return CHIP_NO_ERROR; +} + +CHIP_ERROR GenericThreadDriver::RevertConfiguration() +{ + mStagingNetwork = mSavedNetwork; + return CHIP_NO_ERROR; +} + +Status GenericThreadDriver::AddOrUpdateNetwork(ByteSpan operationalDataset) +{ + uint8_t extpanid[kSizeExtendedPanId]; + uint8_t newExtpanid[kSizeExtendedPanId]; + Thread::OperationalDataset newDataset; + + newDataset.Init(operationalDataset); + VerifyOrReturnError(newDataset.IsCommissioned(), Status::kOutOfRange); + + newDataset.GetExtendedPanId(newExtpanid); + mStagingNetwork.GetExtendedPanId(extpanid); + + // We only support one active operational dataset. Add/Update based on either: + // Staging network not commissioned yet (active) or we are updating the dataset with same Extended Pan ID. + VerifyOrReturnError(!mStagingNetwork.IsCommissioned() || memcmp(extpanid, newExtpanid, kSizeExtendedPanId) == 0, + Status::kBoundsExceeded); + + mStagingNetwork = newDataset; + return Status::kSuccess; +} + +Status GenericThreadDriver::RemoveNetwork(ByteSpan networkId) +{ + uint8_t extpanid[kSizeExtendedPanId]; + if (!mStagingNetwork.IsCommissioned()) + { + return Status::kNetworkNotFound; + } + else if (mStagingNetwork.GetExtendedPanId(extpanid) != CHIP_NO_ERROR) + { + return Status::kUnknownError; + } + + VerifyOrReturnError(networkId.size() == kSizeExtendedPanId && memcmp(networkId.data(), extpanid, kSizeExtendedPanId) == 0, + Status::kNetworkNotFound); + mStagingNetwork.Clear(); + return Status::kSuccess; +} + +Status GenericThreadDriver::ReorderNetwork(ByteSpan networkId, uint8_t index) +{ + uint8_t extpanid[kSizeExtendedPanId]; + if (!mStagingNetwork.IsCommissioned()) + { + return Status::kNetworkNotFound; + } + else if (mStagingNetwork.GetExtendedPanId(extpanid) != CHIP_NO_ERROR) + { + return Status::kUnknownError; + } + + VerifyOrReturnError(networkId.size() == kSizeExtendedPanId && memcmp(networkId.data(), extpanid, kSizeExtendedPanId) == 0, + Status::kNetworkNotFound); + + return Status::kSuccess; +} + +void GenericThreadDriver::ConnectNetwork(ByteSpan networkId, ConnectCallback * callback) +{ + NetworkCommissioning::Status status = Status::kSuccess; + uint8_t extpanid[kSizeExtendedPanId]; + if (!mStagingNetwork.IsCommissioned()) + { + ExitNow(status = Status::kNetworkNotFound); + } + else if (mStagingNetwork.GetExtendedPanId(extpanid) != CHIP_NO_ERROR) + { + ExitNow(status = Status::kUnknownError); + } + + VerifyOrExit((networkId.size() == kSizeExtendedPanId && memcmp(networkId.data(), extpanid, kSizeExtendedPanId) == 0), + status = Status::kNetworkNotFound); + + VerifyOrExit(DeviceLayer::ThreadStackMgrImpl().AttachToThreadNetwork(mStagingNetwork.AsByteSpan(), callback) == CHIP_NO_ERROR, + status = Status::kUnknownError); + +exit: + if (status != Status::kSuccess) + { + callback->OnResult(status, CharSpan(), 0); + } +} + +void GenericThreadDriver::ScanNetworks(ThreadDriver::ScanCallback * callback) +{ + CHIP_ERROR err = DeviceLayer::ThreadStackMgrImpl().StartThreadScan(callback); + if (err != CHIP_NO_ERROR) + { + callback->OnFinished(Status::kUnknownError, CharSpan(), nullptr); + } +} + +size_t GenericThreadDriver::ThreadNetworkIterator::Count() +{ + return driver->mStagingNetwork.IsCommissioned() ? 1 : 0; +} + +bool GenericThreadDriver::ThreadNetworkIterator::Next(Network & item) +{ + if (exhausted || !driver->mStagingNetwork.IsCommissioned()) + { + return false; + } + uint8_t extpanid[kSizeExtendedPanId]; + VerifyOrReturnError(driver->mStagingNetwork.GetExtendedPanId(extpanid) == CHIP_NO_ERROR, false); + memcpy(item.networkID, extpanid, kSizeExtendedPanId); + item.networkIDLen = kSizeExtendedPanId; + item.connected = false; + exhausted = true; + + ByteSpan currentProvision; + Thread::OperationalDataset currentDataset; + uint8_t enabledExtPanId[Thread::kSizeExtendedPanId]; + + // The Thread network is not actually enabled. + VerifyOrReturnError(ConnectivityMgrImpl().IsThreadAttached(), true); + VerifyOrReturnError(ThreadStackMgrImpl().GetThreadProvision(currentProvision) == CHIP_NO_ERROR, true); + VerifyOrReturnError(currentDataset.Init(currentProvision) == CHIP_NO_ERROR, true); + // The Thread network is not enabled, but has a different extended pan id. + VerifyOrReturnError(currentDataset.GetExtendedPanId(enabledExtPanId) == CHIP_NO_ERROR, true); + VerifyOrReturnError(memcmp(extpanid, enabledExtPanId, kSizeExtendedPanId) == 0, true); + // The Thread network is enabled and has the same extended pan id as the one in our record. + item.connected = true; + + return true; +} + +} // namespace NetworkCommissioning +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.h b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.h new file mode 100644 index 00000000000000..de70a3055af6f8 --- /dev/null +++ b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.h @@ -0,0 +1,72 @@ +/* + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace chip { +namespace DeviceLayer { +namespace NetworkCommissioning { + +class GenericThreadDriver final : public ThreadDriver +{ +public: + class ThreadNetworkIterator final : public NetworkIterator + { + public: + ThreadNetworkIterator(GenericThreadDriver * aDriver) : driver(aDriver) {} + size_t Count() override; + bool Next(Network & item) override; + void Release() override { delete this; } + ~ThreadNetworkIterator() = default; + + private: + GenericThreadDriver * driver; + bool exhausted = false; + }; + + // BaseDriver + NetworkIterator * GetNetworks() override { return new ThreadNetworkIterator(this); } + CHIP_ERROR Init() override; + CHIP_ERROR Shutdown() override { return CHIP_NO_ERROR; } // Nothing to do on EFR32 for shutdown. + + // WirelessDriver + uint8_t GetMaxNetworks() override { return 1; } + uint8_t GetScanNetworkTimeoutSeconds() override { return 10; } + uint8_t GetConnectNetworkTimeoutSeconds() override { return 20; } + + CHIP_ERROR CommitConfiguration() override; + CHIP_ERROR RevertConfiguration() override; + + Status RemoveNetwork(ByteSpan networkId) override; + Status ReorderNetwork(ByteSpan networkId, uint8_t index) override; + void ConnectNetwork(ByteSpan networkId, ConnectCallback * callback) override; + + // ThreadDriver + Status AddOrUpdateNetwork(ByteSpan operationalDataset) override; + void ScanNetworks(ScanCallback * callback) override; + +private: + ThreadNetworkIterator mThreadIterator = ThreadNetworkIterator(this); + Thread::OperationalDataset mSavedNetwork; + Thread::OperationalDataset mStagingNetwork; +}; + +} // namespace NetworkCommissioning +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.cpp b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.cpp index b47e471f882473..7db260edea72bc 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.cpp +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.cpp @@ -46,12 +46,14 @@ #endif #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -73,6 +75,7 @@ extern "C" void otAppCliInit(otInstance * aInstance); using namespace chip::app; using namespace chip::app::Clusters; using namespace chip::app::DataModel; +using namespace chip::DeviceLayer::NetworkCommissioning; using chip::Inet::IPPrefix; @@ -80,6 +83,21 @@ namespace chip { namespace DeviceLayer { namespace Internal { +// Network commissioning +namespace { +#ifndef _NO_NETWORK_COMMISSIONING_DRIVER_ +NetworkCommissioning::GenericThreadDriver sGenericThreadDriver; +Clusters::NetworkCommissioning::Instance sThreadNetworkCommissioningInstance(0 /* Endpoint Id */, &sGenericThreadDriver); +#endif + +void initNetworkCommissioningThreadDriver(void) +{ +#ifndef _NO_NETWORK_COMMISSIONING_DRIVER_ + sThreadNetworkCommissioningInstance.Init(); +#endif +} + +} // namespace // Fully instantiate the generic implementation class in whatever compilation unit includes this file. template class GenericThreadStackManagerImpl_OpenThread; @@ -281,6 +299,26 @@ bool GenericThreadStackManagerImpl_OpenThread::_IsThreadProvisioned(v return provisioned; } +template +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_GetThreadProvision(ByteSpan & netInfo) +{ + VerifyOrReturnError(Impl()->IsThreadProvisioned(), CHIP_ERROR_INCORRECT_STATE); + otOperationalDatasetTlvs datasetTlv; + + Impl()->LockThreadStack(); + otError otErr = otDatasetGetActiveTlvs(mOTInst, &datasetTlv); + Impl()->UnlockThreadStack(); + if (otErr != OT_ERROR_NONE) + { + return MapOpenThreadError(otErr); + } + + ReturnErrorOnFailure(mActiveDataset.Init(ByteSpan(datasetTlv.mTlvs, datasetTlv.mLength))); + netInfo = mActiveDataset.AsByteSpan(); + + return CHIP_NO_ERROR; +} + template bool GenericThreadStackManagerImpl_OpenThread::_IsThreadAttached(void) { @@ -293,6 +331,41 @@ bool GenericThreadStackManagerImpl_OpenThread::_IsThreadAttached(void return (curRole != OT_DEVICE_ROLE_DISABLED && curRole != OT_DEVICE_ROLE_DETACHED); } +template +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_AttachToThreadNetwork( + ByteSpan netInfo, NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * callback) +{ + // There is another ongoing connect request, reject the new one. + VerifyOrReturnError(mpConnectCallback == nullptr, CHIP_ERROR_INCORRECT_STATE); + ReturnErrorOnFailure(Impl()->SetThreadEnabled(false)); + ReturnErrorOnFailure(Impl()->SetThreadProvision(netInfo)); + ReturnErrorOnFailure(Impl()->SetThreadEnabled(true)); + mpConnectCallback = callback; + return CHIP_NO_ERROR; +} + +template +void GenericThreadStackManagerImpl_OpenThread::_OnThreadAttachFinished() +{ + if (mpConnectCallback != nullptr) + { + DeviceLayer::SystemLayer().ScheduleLambda([this]() { + mpConnectCallback->OnResult(NetworkCommissioning::Status::kSuccess, CharSpan(), 0); + mpConnectCallback = nullptr; + }); + } +} + +template +CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::_StartThreadScan(ThreadDriver::ScanCallback * callback) +{ + // TODO END scan feature + _OnNetworkScanFinished callback for response + // There is another ongoing scan request, reject the new one. + VerifyOrReturnError(mpScanCallback == nullptr, CHIP_ERROR_INCORRECT_STATE); + mpScanCallback = callback; + return CHIP_NO_ERROR; +} + template ConnectivityManager::ThreadDeviceType GenericThreadStackManagerImpl_OpenThread::_GetThreadDeviceType(void) { @@ -1509,6 +1582,8 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::DoInit(otInstanc ChipLogProgress(DeviceLayer, "OpenThread ifconfig up and thread start"); } + initNetworkCommissioningThreadDriver(); + exit: ChipLogProgress(DeviceLayer, "OpenThread started: %s", otThreadErrorToString(otErr)); return err; diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h index ca10b5d31cd3fe..d7c51fb8dbb6c9 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.h @@ -39,6 +39,7 @@ #include #include #include +#include namespace chip { namespace DeviceLayer { @@ -82,9 +83,12 @@ class GenericThreadStackManagerImpl_OpenThread bool _IsThreadAttached(void); CHIP_ERROR _GetThreadProvision(ByteSpan & netInfo); CHIP_ERROR _SetThreadProvision(ByteSpan netInfo); + CHIP_ERROR _AttachToThreadNetwork(ByteSpan netInfo, NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * callback); + void _OnThreadAttachFinished(void); void _ErasePersistentInfo(void); ConnectivityManager::ThreadDeviceType _GetThreadDeviceType(void); CHIP_ERROR _SetThreadDeviceType(ConnectivityManager::ThreadDeviceType deviceType); + CHIP_ERROR _StartThreadScan(NetworkCommissioning::ThreadDriver::ScanCallback * callback); #if CHIP_DEVICE_CONFIG_ENABLE_SED CHIP_ERROR _GetSEDPollingConfig(ConnectivityManager::SEDPollingConfig & pollingConfig); @@ -136,7 +140,11 @@ class GenericThreadStackManagerImpl_OpenThread // ===== Private members for use by this class only. otInstance * mOTInst; - uint64_t mOverrunCount = 0; + uint64_t mOverrunCount = 0; + Thread::OperationalDataset mActiveDataset = {}; + + NetworkCommissioning::ThreadDriver::ScanCallback * mpScanCallback; + NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * mpConnectCallback; #if CHIP_DEVICE_CONFIG_ENABLE_SED ConnectivityManager::SEDPollingConfig mPollingConfig; diff --git a/src/test_driver/efr32/BUILD.gn b/src/test_driver/efr32/BUILD.gn index ec5848855dcecd..67bbf521466712 100644 --- a/src/test_driver/efr32/BUILD.gn +++ b/src/test_driver/efr32/BUILD.gn @@ -57,6 +57,9 @@ efr32_sdk("sdk") { "BOARD_ID=${efr32_board}", "EFR32_LOG_ENABLED=1", "PW_RPC_ENABLED", + + # Thread is built but test driver do not have the NETWORK_COMMISSIONING cluster or zap config. + "_NO_NETWORK_COMMISSIONING_DRIVER_", ] }