[zephyr] Added Bluetooth LE Extended Advertisement option (#33005)

This commit implements platform solution for a Bluetooth LE
extended advertising.

Additionally, for the CommissioningWindowManager types were
changed from Seconds16 to Seconds32, because the current
implementation overflows for 48h duration.

Co-authored-by: Patryk Lipinski <patryk.lipinski@nordicsemi.no>
diff --git a/config/zephyr/Kconfig b/config/zephyr/Kconfig
index ad36a66..bdfa709 100644
--- a/config/zephyr/Kconfig
+++ b/config/zephyr/Kconfig
@@ -533,4 +533,22 @@
 
 endif
 
+config CHIP_BLE_EXT_ADVERTISING
+	bool "Bluetooth LE extended advertising"
+	help
+	  Enable Bluetooth LE extended advertising, which allows the device to advertise
+	  Matter service over Bluetooth LE for a period of time longer than 15 minutes.
+	  If this config is true, 
+	  CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS define can be set up to 172800 seconds (48h).
+
+config CHIP_BLE_ADVERTISING_DURATION
+	int "Bluetooth LE advertising duration in minutes"
+	range 15 2880 if CHIP_BLE_EXT_ADVERTISING
+	range 0 15
+	default 15
+	help
+	  Specify how long the device will advertise Matter service over Bluetooth LE in minutes.
+	  If CHIP_BLE_EXT_ADVERTISING is set to false, the maximum duration time is 15 minutes, 
+	  else the maximum duration time can be extended to 2880 minutes (48h).
+
 endif
diff --git a/src/app/server/CommissioningWindowManager.cpp b/src/app/server/CommissioningWindowManager.cpp
index a205d09..f11261a 100644
--- a/src/app/server/CommissioningWindowManager.cpp
+++ b/src/app/server/CommissioningWindowManager.cpp
@@ -228,7 +228,7 @@
     }
 }
 
-CHIP_ERROR CommissioningWindowManager::OpenCommissioningWindow(Seconds16 commissioningTimeout)
+CHIP_ERROR CommissioningWindowManager::OpenCommissioningWindow(Seconds32 commissioningTimeout)
 {
     VerifyOrReturnError(commissioningTimeout <= MaxCommissioningTimeout() && commissioningTimeout >= MinCommissioningTimeout(),
                         CHIP_ERROR_INVALID_ARGUMENT);
@@ -288,7 +288,7 @@
     return CHIP_NO_ERROR;
 }
 
-CHIP_ERROR CommissioningWindowManager::OpenBasicCommissioningWindow(Seconds16 commissioningTimeout,
+CHIP_ERROR CommissioningWindowManager::OpenBasicCommissioningWindow(Seconds32 commissioningTimeout,
                                                                     CommissioningWindowAdvertisement advertisementMode)
 {
     RestoreDiscriminator();
@@ -316,7 +316,7 @@
 
 CHIP_ERROR
 CommissioningWindowManager::OpenBasicCommissioningWindowForAdministratorCommissioningCluster(
-    System::Clock::Seconds16 commissioningTimeout, FabricIndex fabricIndex, VendorId vendorId)
+    System::Clock::Seconds32 commissioningTimeout, FabricIndex fabricIndex, VendorId vendorId)
 {
     ReturnErrorOnFailure(OpenBasicCommissioningWindow(commissioningTimeout, CommissioningWindowAdvertisement::kDnssdOnly));
 
@@ -326,7 +326,7 @@
     return CHIP_NO_ERROR;
 }
 
-CHIP_ERROR CommissioningWindowManager::OpenEnhancedCommissioningWindow(Seconds16 commissioningTimeout, uint16_t discriminator,
+CHIP_ERROR CommissioningWindowManager::OpenEnhancedCommissioningWindow(Seconds32 commissioningTimeout, uint16_t discriminator,
                                                                        Spake2pVerifier & verifier, uint32_t iterations,
                                                                        ByteSpan salt, FabricIndex fabricIndex, VendorId vendorId)
 {
diff --git a/src/app/server/CommissioningWindowManager.h b/src/app/server/CommissioningWindowManager.h
index 6b4e1ef..51efb44 100644
--- a/src/app/server/CommissioningWindowManager.h
+++ b/src/app/server/CommissioningWindowManager.h
@@ -58,21 +58,21 @@
         return CHIP_NO_ERROR;
     }
 
-    static constexpr System::Clock::Seconds16 MaxCommissioningTimeout()
+    static constexpr System::Clock::Seconds32 MaxCommissioningTimeout()
     {
 #if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
         // Specification section 2.3.1 - Extended Announcement Duration up to 48h
-        return System::Clock::Seconds16(60 * 60 * 48);
+        return System::Clock::Seconds32(60 * 60 * 48);
 #else
         // Specification section 5.4.2.3. Announcement Duration says 15 minutes.
-        return System::Clock::Seconds16(15 * 60);
+        return System::Clock::Seconds32(15 * 60);
 #endif
     }
 
-    System::Clock::Seconds16 MinCommissioningTimeout() const
+    System::Clock::Seconds32 MinCommissioningTimeout() const
     {
         // Specification section 5.4.2.3. Announcement Duration says 3 minutes.
-        return mMinCommissioningTimeoutOverride.ValueOr(System::Clock::Seconds16(3 * 60));
+        return mMinCommissioningTimeoutOverride.ValueOr(System::Clock::Seconds32(3 * 60));
     }
 
     void SetAppDelegate(AppDelegate * delegate) { mAppDelegate = delegate; }
@@ -82,7 +82,7 @@
      */
     CHIP_ERROR
     OpenBasicCommissioningWindow(
-        System::Clock::Seconds16 commissioningTimeout      = System::Clock::Seconds16(CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS),
+        System::Clock::Seconds32 commissioningTimeout      = System::Clock::Seconds32(CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS),
         CommissioningWindowAdvertisement advertisementMode = chip::CommissioningWindowAdvertisement::kAllSupported);
 
     /**
@@ -90,10 +90,10 @@
      * the Administrator Commmissioning cluster implementation.
      */
     CHIP_ERROR
-    OpenBasicCommissioningWindowForAdministratorCommissioningCluster(System::Clock::Seconds16 commissioningTimeout,
+    OpenBasicCommissioningWindowForAdministratorCommissioningCluster(System::Clock::Seconds32 commissioningTimeout,
                                                                      FabricIndex fabricIndex, VendorId vendorId);
 
-    CHIP_ERROR OpenEnhancedCommissioningWindow(System::Clock::Seconds16 commissioningTimeout, uint16_t discriminator,
+    CHIP_ERROR OpenEnhancedCommissioningWindow(System::Clock::Seconds32 commissioningTimeout, uint16_t discriminator,
                                                Crypto::Spake2pVerifier & verifier, uint32_t iterations, chip::ByteSpan salt,
                                                FabricIndex fabricIndex, VendorId vendorId);
 
@@ -128,7 +128,7 @@
 
     // For tests only, allow overriding the spec-defined minimum value of the
     // commissioning window timeout.
-    void OverrideMinCommissioningTimeout(System::Clock::Seconds16 timeout) { mMinCommissioningTimeoutOverride.SetValue(timeout); }
+    void OverrideMinCommissioningTimeout(System::Clock::Seconds32 timeout) { mMinCommissioningTimeoutOverride.SetValue(timeout); }
 
 private:
     //////////// SessionDelegate Implementation ///////////////
@@ -146,7 +146,7 @@
 
     // Start a timer that will call HandleCommissioningWindowTimeout, and then
     // start advertising and listen for PASE.
-    CHIP_ERROR OpenCommissioningWindow(System::Clock::Seconds16 commissioningTimeout);
+    CHIP_ERROR OpenCommissioningWindow(System::Clock::Seconds32 commissioningTimeout);
 
     // Start advertising and listening for PASE connections.  Should only be
     // called when a commissioning window timeout timer is running.
@@ -219,7 +219,7 @@
 
     // For tests only, so that we can test the commissioning window timeout
     // without having to wait 3 minutes.
-    Optional<System::Clock::Seconds16> mMinCommissioningTimeoutOverride;
+    Optional<System::Clock::Seconds32> mMinCommissioningTimeoutOverride;
 
     // The PASE session we are using, so we can handle CloseSession properly.
     SessionHolderWithDelegate mPASESession;
diff --git a/src/app/tests/TestCommissionManager.cpp b/src/app/tests/TestCommissionManager.cpp
index c314421..0076fd6 100644
--- a/src/app/tests/TestCommissionManager.cpp
+++ b/src/app/tests/TestCommissionManager.cpp
@@ -239,7 +239,7 @@
     NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
 
     CommissioningWindowManager & commissionMgr = Server::GetInstance().GetCommissioningWindowManager();
-    constexpr auto kTimeoutSeconds             = chip::System::Clock::Seconds16(1);
+    constexpr auto kTimeoutSeconds             = chip::System::Clock::Seconds32(1);
     constexpr uint16_t kTimeoutMs              = 1000;
     constexpr unsigned kSleepPadding           = 100;
     commissionMgr.OverrideMinCommissioningTimeout(kTimeoutSeconds);
diff --git a/src/include/platform/ConnectivityManager.h b/src/include/platform/ConnectivityManager.h
index 90bab2a..5699caf 100644
--- a/src/include/platform/ConnectivityManager.h
+++ b/src/include/platform/ConnectivityManager.h
@@ -138,8 +138,9 @@
 
     enum BLEAdvertisingMode
     {
-        kFastAdvertising = 0,
-        kSlowAdvertising = 1,
+        kFastAdvertising     = 0,
+        kSlowAdvertising     = 1,
+        kExtendedAdvertising = 2,
     };
 
     enum class SEDIntervalMode
diff --git a/src/platform/Zephyr/BLEManagerImpl.cpp b/src/platform/Zephyr/BLEManagerImpl.cpp
index 54cf69d..d4e8333 100644
--- a/src/platform/Zephyr/BLEManagerImpl.cpp
+++ b/src/platform/Zephyr/BLEManagerImpl.cpp
@@ -252,18 +252,39 @@
     Encoding::LittleEndian::Put16(serviceData.uuid, UUID16_CHIPoBLEService.val);
     ReturnErrorOnFailure(ConfigurationMgr().GetBLEDeviceIdentificationInfo(serviceData.deviceIdInfo));
 
+#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
+    if (mFlags.Has(Flags::kExtendedAdvertisingEnabled))
+    {
+        serviceData.deviceIdInfo.SetVendorId(DEVICE_HANDLE_NULL);
+        serviceData.deviceIdInfo.SetProductId(DEVICE_HANDLE_NULL);
+        serviceData.deviceIdInfo.SetExtendedAnnouncementFlag(true);
+    }
+#endif
+
     advertisingData[0]  = BT_DATA(BT_DATA_FLAGS, &kAdvertisingFlags, sizeof(kAdvertisingFlags));
     advertisingData[1]  = BT_DATA(BT_DATA_SVC_DATA16, &serviceData, sizeof(serviceData));
     scanResponseData[0] = BT_DATA(BT_DATA_NAME_COMPLETE, name, nameSize);
 
-    mAdvertisingRequest.priority         = CHIP_DEVICE_BLE_ADVERTISING_PRIORITY;
-    mAdvertisingRequest.options          = kAdvertisingOptions;
-    mAdvertisingRequest.minInterval      = mFlags.Has(Flags::kFastAdvertisingEnabled)
-             ? CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN
-             : CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN;
-    mAdvertisingRequest.maxInterval      = mFlags.Has(Flags::kFastAdvertisingEnabled)
-             ? CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX
-             : CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX;
+    mAdvertisingRequest.priority = CHIP_DEVICE_BLE_ADVERTISING_PRIORITY;
+    mAdvertisingRequest.options  = kAdvertisingOptions;
+
+    if (mFlags.Has(Flags::kFastAdvertisingEnabled))
+    {
+        mAdvertisingRequest.minInterval = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MIN;
+        mAdvertisingRequest.maxInterval = CHIP_DEVICE_CONFIG_BLE_FAST_ADVERTISING_INTERVAL_MAX;
+    }
+#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
+    else if (mFlags.Has(Flags::kExtendedAdvertisingEnabled))
+    {
+        mAdvertisingRequest.minInterval = CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MIN;
+        mAdvertisingRequest.maxInterval = CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_MAX;
+    }
+#endif
+    else
+    {
+        mAdvertisingRequest.minInterval = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MIN;
+        mAdvertisingRequest.maxInterval = CHIP_DEVICE_CONFIG_BLE_SLOW_ADVERTISING_INTERVAL_MAX;
+    }
     mAdvertisingRequest.advertisingData  = Span<bt_data>(advertisingData);
     mAdvertisingRequest.scanResponseData = nameSize ? Span<bt_data>(scanResponseData) : Span<bt_data>{};
 
@@ -322,10 +343,17 @@
 
         if (mFlags.Has(Flags::kFastAdvertisingEnabled))
         {
-            // Start timer to change advertising interval.
+            // Start timer to change advertising interval from fast to slow.
             DeviceLayer::SystemLayer().StartTimer(
                 System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_BLE_ADVERTISING_INTERVAL_CHANGE_TIME),
-                HandleBLEAdvertisementIntervalChange, this);
+                HandleSlowBLEAdvertisementInterval, this);
+
+#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
+            // Start timer to schedule start of the extended advertising
+            DeviceLayer::SystemLayer().StartTimer(
+                System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING_INTERVAL_CHANGE_TIME_MS),
+                HandleExtendedBLEAdvertisementInterval, this);
+#endif
         }
     }
 
@@ -342,6 +370,10 @@
         mFlags.Clear(Flags::kAdvertising);
         mFlags.Set(Flags::kFastAdvertisingEnabled, true);
 
+#if CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING
+        mFlags.Clear(Flags::kExtendedAdvertisingEnabled);
+#endif
+
         ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped");
 
         // Post a CHIPoBLEAdvertisingChange(Stopped) event.
@@ -353,7 +385,8 @@
         }
 
         // Cancel timer event changing CHIPoBLE advertisement interval
-        DeviceLayer::SystemLayer().CancelTimer(HandleBLEAdvertisementIntervalChange, this);
+        DeviceLayer::SystemLayer().CancelTimer(HandleSlowBLEAdvertisementInterval, this);
+        DeviceLayer::SystemLayer().CancelTimer(HandleExtendedBLEAdvertisementInterval, this);
     }
 
     return CHIP_NO_ERROR;
@@ -366,6 +399,9 @@
         ChipLogDetail(DeviceLayer, "CHIPoBLE advertising set to %s", val ? "on" : "off");
 
         mFlags.Set(Flags::kAdvertisingEnabled, val);
+        // Ensure that each enabling/disabling of the standard advertising clears
+        // the extended mode flag.
+        mFlags.Set(Flags::kExtendedAdvertisingEnabled, false);
         PlatformMgr().ScheduleWork(DriveBLEState, 0);
     }
 
@@ -378,9 +414,15 @@
     {
     case BLEAdvertisingMode::kFastAdvertising:
         mFlags.Set(Flags::kFastAdvertisingEnabled, true);
+        mFlags.Set(Flags::kExtendedAdvertisingEnabled, false);
         break;
     case BLEAdvertisingMode::kSlowAdvertising:
         mFlags.Set(Flags::kFastAdvertisingEnabled, false);
+        mFlags.Set(Flags::kExtendedAdvertisingEnabled, false);
+        break;
+    case BLEAdvertisingMode::kExtendedAdvertising:
+        mFlags.Set(Flags::kExtendedAdvertisingEnabled, true);
+        mFlags.Set(Flags::kFastAdvertisingEnabled, false);
         break;
     default:
         return CHIP_ERROR_INVALID_ARGUMENT;
@@ -570,12 +612,18 @@
 }
 #endif
 
-void BLEManagerImpl::HandleBLEAdvertisementIntervalChange(System::Layer * layer, void * param)
+void BLEManagerImpl::HandleSlowBLEAdvertisementInterval(System::Layer * layer, void * param)
 {
     BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kSlowAdvertising);
     ChipLogProgress(DeviceLayer, "CHIPoBLE advertising mode changed to slow");
 }
 
+void BLEManagerImpl::HandleExtendedBLEAdvertisementInterval(System::Layer * layer, void * param)
+{
+    BLEMgr().SetAdvertisingMode(BLEAdvertisingMode::kExtendedAdvertising);
+    ChipLogProgress(DeviceLayer, "CHIPoBLE advertising mode changed to extended");
+}
+
 void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
 {
     CHIP_ERROR err = CHIP_NO_ERROR;
diff --git a/src/platform/Zephyr/BLEManagerImpl.h b/src/platform/Zephyr/BLEManagerImpl.h
index 7db469f..4fb3352 100644
--- a/src/platform/Zephyr/BLEManagerImpl.h
+++ b/src/platform/Zephyr/BLEManagerImpl.h
@@ -91,6 +91,7 @@
         kAdvertisingRefreshNeeded =
             0x0010, /**< The advertising state/configuration has changed, but the SoftDevice has yet to be updated. */
         kChipoBleGattServiceRegister = 0x0020, /**< The system has currently CHIPoBLE GATT service registered. */
+        kExtendedAdvertisingEnabled  = 0x0040, /**< The application has enabled extended advertising. */
     };
 
     struct ServiceData;
@@ -129,7 +130,8 @@
     static void HandleTXIndicated(bt_conn * conn, bt_gatt_indicate_params * attr, uint8_t err);
     static void HandleConnect(bt_conn * conn, uint8_t err);
     static void HandleDisconnect(bt_conn * conn, uint8_t reason);
-    static void HandleBLEAdvertisementIntervalChange(System::Layer * layer, void * param);
+    static void HandleSlowBLEAdvertisementInterval(System::Layer * layer, void * param);
+    static void HandleExtendedBLEAdvertisementInterval(System::Layer * layer, void * param);
 
     // ===== Members for internal use by the following friends.
 
diff --git a/src/platform/Zephyr/CHIPDevicePlatformConfig.h b/src/platform/Zephyr/CHIPDevicePlatformConfig.h
index 3296f3a..e7622f6 100644
--- a/src/platform/Zephyr/CHIPDevicePlatformConfig.h
+++ b/src/platform/Zephyr/CHIPDevicePlatformConfig.h
@@ -130,3 +130,9 @@
 #ifdef CONFIG_CHIP_EXTENDED_DISCOVERY
 #define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1
 #endif // CONFIG_CHIP_EXTENDED_DISCOVERY
+
+#ifdef CONFIG_CHIP_BLE_EXT_ADVERTISING
+#define CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING 1
+#endif // CONFIG_CHIP_BLE_EXT_ADVERTISING
+
+#define CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS (CONFIG_CHIP_BLE_ADVERTISING_DURATION * 60)
diff --git a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h
index 7461d36..f9e445f 100644
--- a/src/platform/nrfconnect/CHIPDevicePlatformConfig.h
+++ b/src/platform/nrfconnect/CHIPDevicePlatformConfig.h
@@ -212,6 +212,12 @@
 #define CHIP_DEVICE_CONFIG_ENABLE_EXTENDED_DISCOVERY 1
 #endif // CONFIG_CHIP_EXTENDED_DISCOVERY
 
+#ifdef CONFIG_CHIP_BLE_EXT_ADVERTISING
+#define CHIP_DEVICE_CONFIG_BLE_EXT_ADVERTISING 1
+#endif // CONFIG_CHIP_BLE_EXT_ADVERTISING
+
+#define CHIP_DEVICE_CONFIG_DISCOVERY_TIMEOUT_SECS (CONFIG_CHIP_BLE_ADVERTISING_DURATION * 60)
+
 #ifndef CHIP_DEVICE_CONFIG_ROTATING_DEVICE_ID_UNIQUE_ID_LENGTH
 #ifdef CONFIG_CHIP_FACTORY_DATA
 // UID will be copied from the externally programmed factory data, so we don't know the actual length and we need to assume some max