From c3d4dec3c066aede9245d629459dc1ae2f3103cc Mon Sep 17 00:00:00 2001
From: Adrian Gielniewski <adrian.gielniewski@nordicsemi.no>
Date: Fri, 14 Mar 2025 13:44:21 +0100
Subject: [PATCH] OpenThread: Clear SRP host and services during
 RevertConfiguration

* Postpone `RevertConfiguration` until Server is initialized.
* Clear SRP host and services before reverting dataset.
* Abort revert if creating new backup.

Signed-off-by: Adrian Gielniewski <adrian.gielniewski@nordicsemi.no>
---
 ...enericNetworkCommissioningThreadDriver.cpp | 55 ++++++++++++++++---
 .../GenericNetworkCommissioningThreadDriver.h |  2 +
 2 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp
index fe5bd40a0afb42..14828e90f50823 100644
--- a/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp
+++ b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp
@@ -51,8 +51,13 @@ CHIP_ERROR GenericThreadDriver::Init(Internal::BaseDriver::NetworkStatusChangeCa
 
     // If the network configuration backup exists, it means that the device has been rebooted with
     // the fail-safe armed. Since OpenThread persists all operational dataset changes, the backup
-    // must be restored on the boot. If there's no backup, the below function is a no-op.
-    RevertConfiguration();
+    // must be restored.
+    if (BackupExists())
+    {
+        // Set flag and postpone revert until OpenThread is initialized,
+        // as we need to clear SRP host and services before restoring the backup.
+        mRevertOnServerReady = true;
+    }
 
     CheckInterfaceEnabled();
 
@@ -61,11 +66,28 @@ CHIP_ERROR GenericThreadDriver::Init(Internal::BaseDriver::NetworkStatusChangeCa
 
 void GenericThreadDriver::OnThreadStateChangeHandler(const ChipDeviceEvent * event, intptr_t arg)
 {
-    if ((event->Type == DeviceEventType::kThreadStateChange) &&
-        (event->ThreadStateChange.OpenThread.Flags & OT_CHANGED_THREAD_PANID))
+    auto & driver = *reinterpret_cast<GenericThreadDriver *>(arg);
+
+    switch (event->Type)
     {
-        // Update the mStagingNetwork when thread panid changed
-        ThreadStackMgrImpl().GetThreadProvision(reinterpret_cast<GenericThreadDriver *>(arg)->mStagingNetwork);
+    case DeviceEventType::kThreadStateChange:
+        if (event->ThreadStateChange.OpenThread.Flags & OT_CHANGED_THREAD_PANID)
+        {
+            // Update the mStagingNetwork when thread panid changed
+            ThreadStackMgrImpl().GetThreadProvision(driver.mStagingNetwork);
+        }
+        break;
+
+    case DeviceEventType::kServerReady:
+        if (driver.mRevertOnServerReady)
+        {
+            driver.mRevertOnServerReady = false;
+            driver.RevertConfiguration();
+        }
+        break;
+
+    default:
+        break;
     }
 }
 
@@ -97,6 +119,8 @@ CHIP_ERROR GenericThreadDriver::RevertConfiguration()
     // since the fail-safe was armed, so return with no error.
     VerifyOrReturnError(error != CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND, CHIP_NO_ERROR);
 
+    ThreadStackMgrImpl().ClearAllSrpHostAndServices();
+
     if (!GetEnabled())
     {
         // When reverting configuration, set InterfaceEnabled to default value (true).
@@ -272,10 +296,11 @@ Status GenericThreadDriver::MatchesNetworkId(const Thread::OperationalDataset &
 
 CHIP_ERROR GenericThreadDriver::BackupConfiguration()
 {
-    // If configuration is already backed up, return with no error
-    CHIP_ERROR err = KeyValueStoreMgr().Get(DefaultStorageKeyAllocator::FailSafeNetworkConfig().KeyName(), nullptr, 0);
+    // Abort pending revert
+    mRevertOnServerReady = false;
 
-    if (err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL)
+    // If configuration is already backed up, return with no error
+    if (BackupExists())
     {
         return CHIP_NO_ERROR;
     }
@@ -285,6 +310,18 @@ CHIP_ERROR GenericThreadDriver::BackupConfiguration()
     return KeyValueStoreMgr().Put(DefaultStorageKeyAllocator::FailSafeNetworkConfig().KeyName(), dataset.data(), dataset.size());
 }
 
+bool GenericThreadDriver::BackupExists()
+{
+    CHIP_ERROR err = KeyValueStoreMgr().Get(DefaultStorageKeyAllocator::FailSafeNetworkConfig().KeyName(), nullptr, 0);
+
+    if (err == CHIP_NO_ERROR || err == CHIP_ERROR_BUFFER_TOO_SMALL)
+    {
+        return true;
+    }
+
+    return false;
+}
+
 void GenericThreadDriver::CheckInterfaceEnabled()
 {
 #if !CHIP_DEVICE_CONFIG_ENABLE_THREAD_AUTOSTART
diff --git a/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.h b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.h
index 3cdb8cff668034..cc9f4a335506ef 100644
--- a/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.h
+++ b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.h
@@ -127,10 +127,12 @@ class GenericThreadDriver final : public ThreadDriver
     static void OnThreadStateChangeHandler(const ChipDeviceEvent * event, intptr_t arg);
     Status MatchesNetworkId(const Thread::OperationalDataset & dataset, const ByteSpan & networkId) const;
     CHIP_ERROR BackupConfiguration();
+    bool BackupExists();
     void CheckInterfaceEnabled();
 
     ThreadNetworkIterator mThreadIterator      = ThreadNetworkIterator(this);
     Thread::OperationalDataset mStagingNetwork = {};
+    bool mRevertOnServerReady                  = false;
 };
 
 } // namespace NetworkCommissioning