diff --git a/src/platform/ESP32/KeyValueStoreManagerImpl.cpp b/src/platform/ESP32/KeyValueStoreManagerImpl.cpp index 6617bb2cb11bf0..3c587167334de2 100644 --- a/src/platform/ESP32/KeyValueStoreManagerImpl.cpp +++ b/src/platform/ESP32/KeyValueStoreManagerImpl.cpp @@ -68,7 +68,7 @@ KeyValueStoreManagerImpl KeyValueStoreManagerImpl::sInstance; CHIP_ERROR KeyValueStoreManagerImpl::_Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size, size_t offset_bytes) { - VerifyOrReturnError(value, CHIP_ERROR_INVALID_ARGUMENT); + // value may be NULL when checking whether the key exists // Offset and partial reads are not supported in nvs, for now just return NOT_IMPLEMENTED. Support can be added in the // future if this is needed. diff --git a/src/platform/ESP32/NetworkCommissioningDriver.cpp b/src/platform/ESP32/NetworkCommissioningDriver.cpp index 2871c4c3f2031d..ee061fb746681e 100644 --- a/src/platform/ESP32/NetworkCommissioningDriver.cpp +++ b/src/platform/ESP32/NetworkCommissioningDriver.cpp @@ -95,39 +95,31 @@ CHIP_ERROR GetConfiguredNetwork(Network & network) CHIP_ERROR ESPWiFiDriver::Init(NetworkStatusChangeCallback * networkStatusChangeCallback) { - CHIP_ERROR err; - size_t ssidLen = 0; - size_t credentialsLen = 0; - - err = PersistedStorage::KeyValueStoreMgr().Get(kWiFiCredentialsKeyName, mSavedNetwork.credentials, - sizeof(mSavedNetwork.credentials), &credentialsLen); - if (err == CHIP_ERROR_NOT_FOUND) + wifi_config_t stationConfig; + if (esp_wifi_get_config(WIFI_IF_STA, &stationConfig) == ESP_OK && stationConfig.sta.ssid[0] != 0) { - return CHIP_NO_ERROR; - } + uint8_t ssidLen = static_cast( + strnlen(reinterpret_cast(stationConfig.sta.ssid), DeviceLayer::Internal::kMaxWiFiSSIDLength)); + memcpy(mStagingNetwork.ssid, stationConfig.sta.ssid, ssidLen); + mStagingNetwork.ssidLen = ssidLen; - err = PersistedStorage::KeyValueStoreMgr().Get(kWiFiSSIDKeyName, mSavedNetwork.ssid, sizeof(mSavedNetwork.ssid), &ssidLen); - if (err == CHIP_ERROR_NOT_FOUND) - { - return CHIP_NO_ERROR; - } - if (!CanCastTo(credentialsLen)) - { - return CHIP_ERROR_INCORRECT_STATE; - } - mSavedNetwork.credentialsLen = static_cast(credentialsLen); + uint8_t credentialsLen = static_cast( + strnlen(reinterpret_cast(stationConfig.sta.password), DeviceLayer::Internal::kMaxWiFiKeyLength)); - if (!CanCastTo(ssidLen)) - { - return CHIP_ERROR_INCORRECT_STATE; + memcpy(mStagingNetwork.credentials, stationConfig.sta.password, credentialsLen); + mStagingNetwork.credentialsLen = credentialsLen; } - mSavedNetwork.ssidLen = static_cast(ssidLen); - mStagingNetwork = mSavedNetwork; mpScanCallback = nullptr; mpConnectCallback = nullptr; mpStatusChangeCallback = networkStatusChangeCallback; - return err; + + // If the network configuration backup exists, it means that the device has been rebooted with + // the fail-safe armed. Since ESP-WiFi persists all wifi credentials changes, the backup must + // be restored on the boot. If there's no backup, the below function is a no-op. + RevertConfiguration(); + + return CHIP_NO_ERROR; } void ESPWiFiDriver::Shutdown() @@ -137,17 +129,51 @@ void ESPWiFiDriver::Shutdown() CHIP_ERROR ESPWiFiDriver::CommitConfiguration() { - ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Put(kWiFiSSIDKeyName, mStagingNetwork.ssid, mStagingNetwork.ssidLen)); - ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Put(kWiFiCredentialsKeyName, mStagingNetwork.credentials, - mStagingNetwork.credentialsLen)); - mSavedNetwork = mStagingNetwork; + PersistedStorage::KeyValueStoreMgr().Delete(kWiFiSSIDKeyName); + PersistedStorage::KeyValueStoreMgr().Delete(kWiFiCredentialsKeyName); + return CHIP_NO_ERROR; } CHIP_ERROR ESPWiFiDriver::RevertConfiguration() { - mStagingNetwork = mSavedNetwork; - return CHIP_NO_ERROR; + WiFiNetwork network; + Network configuredNetwork; + size_t ssidLen = 0; + size_t credentialsLen = 0; + + CHIP_ERROR error = PersistedStorage::KeyValueStoreMgr().Get(kWiFiSSIDKeyName, network.ssid, sizeof(network.ssid), &ssidLen); + ReturnErrorCodeIf(error == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND, CHIP_NO_ERROR); + VerifyOrExit(CanCastTo(ssidLen), error = CHIP_ERROR_INTERNAL); + VerifyOrExit(PersistedStorage::KeyValueStoreMgr().Get(kWiFiCredentialsKeyName, network.credentials, sizeof(network.credentials), + &credentialsLen) == CHIP_NO_ERROR, + error = CHIP_ERROR_INTERNAL); + VerifyOrExit(CanCastTo(credentialsLen), error = CHIP_ERROR_INTERNAL); + + network.ssidLen = static_cast(ssidLen); + network.credentialsLen = static_cast(credentialsLen); + mStagingNetwork = network; + + if (GetConfiguredNetwork(configuredNetwork) == CHIP_NO_ERROR) + { + VerifyOrExit(!NetworkMatch(mStagingNetwork, ByteSpan(configuredNetwork.networkID, configuredNetwork.networkIDLen)), + error = CHIP_NO_ERROR); + } + + if (error == CHIP_NO_ERROR) + { + // ConnectWiFiNetwork can work with empty mStagingNetwork (ssidLen = 0). + error = ConnectWiFiNetwork(reinterpret_cast(mStagingNetwork.ssid), mStagingNetwork.ssidLen, + reinterpret_cast(mStagingNetwork.credentials), mStagingNetwork.credentialsLen); + } + +exit: + + // Remove the backup. + PersistedStorage::KeyValueStoreMgr().Delete(kWiFiSSIDKeyName); + PersistedStorage::KeyValueStoreMgr().Delete(kWiFiCredentialsKeyName); + + return error; } bool ESPWiFiDriver::NetworkMatch(const WiFiNetwork & network, ByteSpan networkId) @@ -163,6 +189,7 @@ Status ESPWiFiDriver::AddOrUpdateNetwork(ByteSpan ssid, ByteSpan credentials, Mu VerifyOrReturnError(mStagingNetwork.ssidLen == 0 || NetworkMatch(mStagingNetwork, ssid), Status::kBoundsExceeded); VerifyOrReturnError(credentials.size() <= sizeof(mStagingNetwork.credentials), Status::kOutOfRange); VerifyOrReturnError(ssid.size() <= sizeof(mStagingNetwork.ssid), Status::kOutOfRange); + VerifyOrReturnError(BackupConfiguration() == CHIP_NO_ERROR, Status::kUnknownError); memcpy(mStagingNetwork.credentials, credentials.data(), credentials.size()); mStagingNetwork.credentialsLen = static_cast(credentials.size()); @@ -178,6 +205,7 @@ Status ESPWiFiDriver::RemoveNetwork(ByteSpan networkId, MutableCharSpan & outDeb outDebugText.reduce_size(0); outNetworkIndex = 0; VerifyOrReturnError(NetworkMatch(mStagingNetwork, networkId), Status::kNetworkIDNotFound); + VerifyOrReturnError(BackupConfiguration() == CHIP_NO_ERROR, Status::kUnknownError); // Use empty ssid for representing invalid network mStagingNetwork.ssidLen = 0; @@ -273,6 +301,7 @@ void ESPWiFiDriver::ConnectNetwork(ByteSpan networkId, ConnectCallback * callbac const uint32_t secToMiliSec = 1000; VerifyOrExit(NetworkMatch(mStagingNetwork, networkId), networkingStatus = Status::kNetworkIDNotFound); + VerifyOrExit(BackupConfiguration() == CHIP_NO_ERROR, networkingStatus = Status::kUnknownError); VerifyOrExit(mpConnectCallback == nullptr, networkingStatus = Status::kUnknownError); ChipLogProgress(NetworkProvisioning, "ESP NetworkCommissioningDelegate: SSID: %.*s", static_cast(networkId.size()), networkId.data()); @@ -484,6 +513,19 @@ bool ESPWiFiDriver::WiFiNetworkIterator::Next(Network & item) return true; } +CHIP_ERROR ESPWiFiDriver::BackupConfiguration() +{ + CHIP_ERROR err = PersistedStorage::KeyValueStoreMgr().Get(kWiFiSSIDKeyName, nullptr, 0); + if (err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL) + { + return CHIP_NO_ERROR; + } + ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Put(kWiFiCredentialsKeyName, mStagingNetwork.credentials, + mStagingNetwork.credentialsLen)); + ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Put(kWiFiSSIDKeyName, mStagingNetwork.ssid, mStagingNetwork.ssidLen)); + return CHIP_NO_ERROR; +} + } // namespace NetworkCommissioning } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/ESP32/NetworkCommissioningDriver.h b/src/platform/ESP32/NetworkCommissioningDriver.h index 447d6346dcbd1c..7c89e564292682 100644 --- a/src/platform/ESP32/NetworkCommissioningDriver.h +++ b/src/platform/ESP32/NetworkCommissioningDriver.h @@ -133,8 +133,8 @@ class ESPWiFiDriver final : public WiFiDriver private: bool NetworkMatch(const WiFiNetwork & network, ByteSpan networkId); CHIP_ERROR StartScanWiFiNetworks(ByteSpan ssid); + CHIP_ERROR BackupConfiguration(); - WiFiNetwork mSavedNetwork; WiFiNetwork mStagingNetwork; ScanCallback * mpScanCallback; ConnectCallback * mpConnectCallback;