Add some changes
authorJihoon Jung <jh8801.jung@samsung.com>
Thu, 25 Mar 2021 23:09:48 +0000 (08:09 +0900)
committerJihoon Jung <jh8801.jung@samsung.com>
Thu, 25 Mar 2021 23:09:48 +0000 (08:09 +0900)
- Add Tizen chip device platform
- change dependency avahi to mdnsresponder
- Add mdns-advertiser example to package

Signed-off-by: Jihoon Jung <jh8801.jung@samsung.com>
60 files changed:
BUILD.gn
examples/chip-tool/commands/common/Commands.cpp
packaging/connectedhomeip.spec
packaging/tizen_fix/tizen_fix.sh
src/platform/BUILD.gn
src/platform/Linux/MdnsImpl.cpp
src/platform/Tizen/BLEManagerImpl.cpp [new file with mode: 0644]
src/platform/Tizen/BLEManagerImpl.h [new file with mode: 0644]
src/platform/Tizen/BlePlatformConfig.h [new file with mode: 0644]
src/platform/Tizen/CHIPDevicePlatformConfig.h [new file with mode: 0644]
src/platform/Tizen/CHIPDevicePlatformEvent.h [new file with mode: 0644]
src/platform/Tizen/CHIPLinuxStorage.cpp [new file with mode: 0644]
src/platform/Tizen/CHIPLinuxStorage.h [new file with mode: 0644]
src/platform/Tizen/CHIPLinuxStorageIni.cpp [new file with mode: 0644]
src/platform/Tizen/CHIPLinuxStorageIni.h [new file with mode: 0644]
src/platform/Tizen/CHIPPlatformConfig.h [new file with mode: 0644]
src/platform/Tizen/ConfigurationManagerImpl.cpp [new file with mode: 0644]
src/platform/Tizen/ConfigurationManagerImpl.h [new file with mode: 0644]
src/platform/Tizen/ConnectivityManagerImpl.cpp [new file with mode: 0644]
src/platform/Tizen/ConnectivityManagerImpl.h [new file with mode: 0644]
src/platform/Tizen/DeviceNetworkProvisioningDelegateImpl.cpp [new file with mode: 0644]
src/platform/Tizen/DeviceNetworkProvisioningDelegateImpl.h [new file with mode: 0644]
src/platform/Tizen/Entropy.cpp [new file with mode: 0644]
src/platform/Tizen/InetPlatformConfig.h [new file with mode: 0644]
src/platform/Tizen/KeyValueStoreManagerImpl.cpp [new file with mode: 0644]
src/platform/Tizen/KeyValueStoreManagerImpl.h [new file with mode: 0644]
src/platform/Tizen/Logging.cpp [new file with mode: 0644]
src/platform/Tizen/MdnsError.cpp [new file with mode: 0644]
src/platform/Tizen/MdnsError.h [new file with mode: 0644]
src/platform/Tizen/MdnsImpl.cpp [new file with mode: 0644]
src/platform/Tizen/MdnsImpl.h [new file with mode: 0644]
src/platform/Tizen/PlatformManagerImpl.cpp [new file with mode: 0644]
src/platform/Tizen/PlatformManagerImpl.h [new file with mode: 0644]
src/platform/Tizen/PosixConfig.cpp [new file with mode: 0644]
src/platform/Tizen/PosixConfig.h [new file with mode: 0644]
src/platform/Tizen/README.md [new file with mode: 0644]
src/platform/Tizen/SystemPlatformConfig.h [new file with mode: 0644]
src/platform/Tizen/SystemTimeSupport.cpp [new file with mode: 0644]
src/platform/Tizen/ThreadStackManagerImpl.cpp [new file with mode: 0644]
src/platform/Tizen/ThreadStackManagerImpl.h [new file with mode: 0644]
src/platform/Tizen/args.gni [new file with mode: 0644]
src/platform/Tizen/bluez/AdapterIterator.cpp [new file with mode: 0644]
src/platform/Tizen/bluez/AdapterIterator.h [new file with mode: 0644]
src/platform/Tizen/bluez/BluezObjectIterator.h [new file with mode: 0644]
src/platform/Tizen/bluez/BluezObjectList.h [new file with mode: 0644]
src/platform/Tizen/bluez/ChipDeviceScanner.cpp [new file with mode: 0644]
src/platform/Tizen/bluez/ChipDeviceScanner.h [new file with mode: 0644]
src/platform/Tizen/bluez/Helper.cpp [new file with mode: 0644]
src/platform/Tizen/bluez/Helper.h [new file with mode: 0644]
src/platform/Tizen/bluez/MainLoop.cpp [new file with mode: 0644]
src/platform/Tizen/bluez/MainLoop.h [new file with mode: 0644]
src/platform/Tizen/bluez/Types.h [new file with mode: 0644]
src/platform/Tizen/dbus/bluez/BUILD.gn [new file with mode: 0644]
src/platform/Tizen/dbus/bluez/DbusBluez.xml [new file with mode: 0644]
src/platform/Tizen/dbus/wpa/BUILD.gn [new file with mode: 0644]
src/platform/Tizen/dbus/wpa/DBusWpa.xml [new file with mode: 0644]
src/platform/Tizen/dbus/wpa/DBusWpaInterface.xml [new file with mode: 0644]
src/platform/Tizen/dbus/wpa/DBusWpaNetwork.xml [new file with mode: 0644]
src/platform/device.gni
src/platform/tests/TestThreadStackMgr.cpp

index 98229f1..cfdaaf0 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -90,6 +90,7 @@ if (current_toolchain != "${dir_pw_toolchain}/dummy:dummy") {
       "${chip_root}/examples/chip-tool",
       "${chip_root}/examples/minimal-mdns:minimal-mdns-client",
       "${chip_root}/examples/minimal-mdns:minimal-mdns-server",
+      "${chip_root}/examples/minimal-mdns:mdns-advertiser",
     ]
   }
 
index 604ded8..4ae8991 100644 (file)
@@ -16,6 +16,8 @@
  *
  */
 
+/* TIZEN_CHIP_MODIFY */
+
 #include "Commands.h"
 
 #include "Command.h"
@@ -46,7 +48,8 @@ int Commands::Run(NodeId localId, NodeId remoteId, int argc, char ** argv)
     err = chip::Platform::MemoryInit();
     VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init Memory failure: %s", chip::ErrorStr(err)));
 
-#if CHIP_DEVICE_LAYER_TARGET_LINUX && CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+#if (CHIP_DEVICE_LAYER_TARGET_LINUX && CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE) || \
+    (CHIP_DEVICE_LAYER_TARGET_TIZEN && CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE)
     // By default, Linux device is configured as a BLE peripheral while the controller needs a BLE central.
     SuccessOrExit(err = chip::DeviceLayer::Internal::BLEMgrImpl().ConfigureBle(/* BLE adapter ID */ 0, /* BLE central */ true));
 #endif
index d515cd9..c7b7f57 100755 (executable)
@@ -11,7 +11,7 @@ BuildRequires: pkgconfig(dbus-1)
 BuildRequires: pkgconfig(gio-2.0)
 BuildRequires: pkgconfig(glib-2.0)
 BuildRequires: pkgconfig(gio-unix-2.0)
-BuildRequires: pkgconfig(avahi-client)
+BuildRequires: pkgconfig(dns_sd)
 
 BuildRequires: python3
 BuildRequires: gn
@@ -43,6 +43,7 @@ cp out/host/chip-all-clusters-app %{buildroot}%{_bindir}/
 cp out/host/chip-shell %{buildroot}%{_bindir}/
 cp out/host/minimal-mdns-client %{buildroot}%{_bindir}/
 cp out/host/minimal-mdns-server %{buildroot}%{_bindir}/
+cp out/host/mdns-advertiser %{buildroot}%{_bindir}/
 
 %post
 
@@ -65,3 +66,4 @@ This package is for CHIP test applications
 %{_bindir}/chip-shell
 %{_bindir}/minimal-mdns-client
 %{_bindir}/minimal-mdns-server
+%{_bindir}/mdns-advertiser
index 931851e..fe76fcc 100755 (executable)
@@ -11,7 +11,8 @@ while true; do
     echo -e "\e[31m********** C A U T I O N **********\e[0m"
     echo -e "\e[31m***********************************\e[0m"
     echo -e "\e[31m This script is a program that downloads the code of CHIP upstream and enables tizen gbs build.\e[0m"
-    echo -e "\e[31m This script contains the contents of deleting all files from CHIP folder (except packaging, git folders)! We ask for safety in use.\e[0m"
+    echo -e "\e[31m This script contains the contents of deleting all files from CHIP folder (except packaging, git, tizen specific folders)! We ask for safety in use.\e[0m"
+    echo -e "\e[31m Also, files with the TIZEN_CHIP_MODIFY keyword will not be deleted.\e[0m"
     echo -e "\e[31m Please do not change the location of this script.\e[0m"
     echo -e "\e[31m Please check if the path of CHIP folder below is correct. \e[0m"
     echo -e "\e[32m CHIP folder path : $PWD\e[0m"
@@ -24,7 +25,11 @@ while true; do
 done
 
 echo -e "\e[33m1. copy tizen modify files to temp folder\e[0m"
-mkdir packaging/tizen_fix/temp/
+mkdir -p packaging/tizen_fix/temp/src/platform/
+
+echo "copy src/platform/Tizen folder to packaging/tizen_fix/temp/src/platform/Tizen"
+cp -rf src/platform/Tizen packaging/tizen_fix/temp/src/platform/
+
 for MODIFY_FILE in $(grep -lr 'TIZEN_CHIP_MODIFY' | grep -v 'tizen_fix.sh')
 do
     MODIFY_FILE_PATH=$(dirname "$MODIFY_FILE")
index 9e24c2e..87056bb 100644 (file)
@@ -12,6 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# TIZEN_CHIP_MODIFY
+
 import("//build_overrides/build.gni")
 import("//build_overrides/chip.gni")
 import("//build_overrides/nlio.gni")
@@ -25,7 +27,7 @@ import("device.gni")
 if (chip_enable_openthread) {
   import("//build_overrides/openthread.gni")
 
-  if (chip_device_platform == "linux" || chip_device_platform == "Darwin") {
+  if (chip_device_platform == "linux" || chip_device_platform == "Darwin" || chip_device_platform == "tizen") {
     import("//build_overrides/ot_br_posix.gni")
   }
 }
@@ -36,6 +38,12 @@ if (chip_device_platform == "linux" && chip_mdns != "none") {
   }
 }
 
+if (chip_device_platform == "tizen" && chip_mdns != "none") {
+  pkg_config("dns_sd") {
+    packages = [ "dns_sd" ]
+  }
+}
+
 if (chip_device_platform != "none") {
   declare_args() {
     # Extra header to include in CHIPDeviceConfig.h for project.
@@ -54,7 +62,7 @@ if (chip_device_platform != "none") {
     chip_enable_additional_data_advertising = true
 
     # Enable adding rotating device id to the additional data.
-    chip_enable_rotating_device_id = true
+    chip_enable_rotating_device_id = false
   }
 
   buildconfig_header("platform_buildconfig") {
@@ -71,7 +79,7 @@ if (chip_device_platform != "none") {
       "OPENTHREAD_CONFIG_ENABLE_TOBLE=false",
     ]
 
-    if (chip_device_platform == "linux" || chip_device_platform == "darwin") {
+    if (chip_device_platform == "linux" || chip_device_platform == "darwin" || chip_device_platform == "tizen") {
       defines += [ "CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE=${chip_enable_ble}" ]
     }
 
@@ -134,6 +142,11 @@ if (chip_device_platform != "none") {
         "CHIP_DEVICE_LAYER_TARGET_LINUX=1",
         "CHIP_DEVICE_LAYER_TARGET=Linux",
       ]
+    } else if (chip_device_platform == "tizen") {
+      defines += [
+        "CHIP_DEVICE_LAYER_TARGET_TIZEN=1",
+        "CHIP_DEVICE_LAYER_TARGET=Tizen",
+      ]
     } else if (chip_device_platform == "nrfconnect") {
       defines += [
         "CHIP_DEVICE_LAYER_TARGET_NRFCONNECT=1",
@@ -520,6 +533,73 @@ if (chip_device_platform != "none" && chip_device_platform != "external") {
       }
 
       public_deps += [ "${chip_root}/third_party/inipp" ]
+    } else if (chip_device_platform == "tizen") {
+      sources += [
+        "Tizen/BLEManagerImpl.cpp",
+        "Tizen/BLEManagerImpl.h",
+        "Tizen/BlePlatformConfig.h",
+        "Tizen/CHIPDevicePlatformConfig.h",
+        "Tizen/CHIPDevicePlatformEvent.h",
+        "Tizen/CHIPLinuxStorage.cpp",
+        "Tizen/CHIPLinuxStorage.h",
+        "Tizen/CHIPLinuxStorageIni.cpp",
+        "Tizen/CHIPLinuxStorageIni.h",
+        "Tizen/CHIPPlatformConfig.h",
+        "Tizen/ConfigurationManagerImpl.cpp",
+        "Tizen/ConfigurationManagerImpl.h",
+        "Tizen/ConnectivityManagerImpl.cpp",
+        "Tizen/ConnectivityManagerImpl.h",
+        "Tizen/DeviceNetworkProvisioningDelegateImpl.cpp",
+        "Tizen/DeviceNetworkProvisioningDelegateImpl.h",
+        "Tizen/InetPlatformConfig.h",
+        "Tizen/KeyValueStoreManagerImpl.cpp",
+        "Tizen/KeyValueStoreManagerImpl.h",
+        "Tizen/Logging.cpp",
+        "Tizen/PlatformManagerImpl.cpp",
+        "Tizen/PlatformManagerImpl.h",
+        "Tizen/PosixConfig.cpp",
+        "Tizen/PosixConfig.h",
+        "Tizen/SystemPlatformConfig.h",
+        "Tizen/SystemTimeSupport.cpp",
+        "Tizen/bluez/AdapterIterator.cpp",
+        "Tizen/bluez/AdapterIterator.h",
+        "Tizen/bluez/ChipDeviceScanner.cpp",
+        "Tizen/bluez/ChipDeviceScanner.h",
+        "Tizen/bluez/Helper.cpp",
+        "Tizen/bluez/Helper.h",
+        "Tizen/bluez/MainLoop.cpp",
+        "Tizen/bluez/MainLoop.h",
+        "Tizen/bluez/Types.h",
+      ]
+
+      if (chip_mdns != "none") {
+        sources += [
+          "Tizen/MdnsImpl.cpp",
+          "Tizen/MdnsImpl.h",
+          "Tizen/MdnsError.cpp",
+          "Tizen/MdnsError.h",
+        ]
+
+        public_configs += [ ":dns_sd" ]
+      }
+
+      if (chip_enable_openthread) {
+        sources += [
+          "Tizen/ThreadStackManagerImpl.cpp",
+          "Tizen/ThreadStackManagerImpl.h",
+        ]
+        public_deps += [ "${ot_br_posix_root}:ot_br_client" ]
+      }
+
+      if (chip_enable_wifi) {
+        public_deps += [ "Tizen/dbus/wpa" ]
+      }
+
+      if (chip_enable_ble) {
+        public_deps += [ "Tizen/dbus/bluez" ]
+      }
+
+      public_deps += [ "${chip_root}/third_party/inipp" ]
     } else if (chip_device_platform == "nrfconnect") {
       sources += [
         "Zephyr/BLEManagerImpl.cpp",
@@ -596,7 +676,7 @@ if (chip_device_platform != "none" && chip_device_platform != "external") {
     }
 
     if (chip_enable_openthread && chip_mdns == "platform" &&
-        chip_device_platform != "linux") {
+        chip_device_platform != "linux" && chip_device_platform != "tizen") {
       sources += [ "OpenThread/MdnsImpl.cpp" ]
     }
 
index 7c35185..c63b3be 100644 (file)
@@ -15,8 +15,6 @@
  *    limitations under the License.
  */
 
-/* TIZEN_CHIP_MODIFY */
-
 #include "MdnsImpl.h"
 
 #include <algorithm>
diff --git a/src/platform/Tizen/BLEManagerImpl.cpp b/src/platform/Tizen/BLEManagerImpl.cpp
new file mode 100644 (file)
index 0000000..f0f515d
--- /dev/null
@@ -0,0 +1,829 @@
+/*
+ *
+ *    Copyright (c) 2020-2021 Project CHIP Authors
+ *    Copyright (c) 2018 Nest Labs, Inc.
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *          Provides an implementation of the BLEManager singleton object
+ *          for Linux platforms.
+ */
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+
+#include <ble/CHIPBleServiceData.h>
+#include <new>
+#include <platform/internal/BLEManager.h>
+#include <support/CodeUtils.h>
+#include <support/SafeInt.h>
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+
+#include "bluez/Helper.h"
+
+using namespace ::nl;
+using namespace ::chip::Ble;
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+namespace {
+
+static constexpr unsigned kNewConnectionScanTimeoutMs = 10000;
+static constexpr unsigned kConnectTimeoutMs           = 5000;
+
+const ChipBleUUID ChipUUID_CHIPoBLEChar_RX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
+                                                 0x9D, 0x11 } };
+const ChipBleUUID ChipUUID_CHIPoBLEChar_TX = { { 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F,
+                                                 0x9D, 0x12 } };
+
+void HandleConnectTimeout(chip::System::Layer *, void * apEndpoint, chip::System::Error)
+{
+    assert(apEndpoint != nullptr);
+
+    CancelConnect(static_cast<BluezEndpoint *>(apEndpoint));
+    BLEManagerImpl::HandleConnectFailed(CHIP_ERROR_TIMEOUT);
+}
+
+} // namespace
+
+BLEManagerImpl BLEManagerImpl::sInstance;
+
+void HandleIncomingBleConnection(BLEEndPoint * bleEP)
+{
+    ChipLogProgress(DeviceLayer, "CHIPoBluez con rcvd");
+}
+
+CHIP_ERROR BLEManagerImpl::_Init()
+{
+    CHIP_ERROR err;
+
+    err = BleLayer::Init(this, this, this, &SystemLayer);
+    SuccessOrExit(err);
+
+    mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled;
+    mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART && !mIsCentral);
+    mFlags.Set(Flags::kFastAdvertisingEnabled, true);
+    mAppState = nullptr;
+
+    memset(mDeviceName, 0, sizeof(mDeviceName));
+
+    OnChipBleConnectReceived = HandleIncomingBleConnection;
+
+    PlatformMgr().ScheduleWork(DriveBLEState, 0);
+
+exit:
+    return err;
+}
+
+CHIP_ERROR BLEManagerImpl::_SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    VerifyOrExit(val != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
+    VerifyOrExit(mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
+
+    if (val != mServiceMode)
+    {
+        mServiceMode = val;
+        PlatformMgr().ScheduleWork(DriveBLEState, 0);
+    }
+
+exit:
+    return err;
+}
+
+CHIP_ERROR BLEManagerImpl::_SetAdvertisingEnabled(bool val)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    if (mFlags.Has(Flags::kAdvertisingEnabled) != val)
+    {
+        mFlags.Set(Flags::kAdvertisingEnabled, val);
+    }
+
+    PlatformMgr().ScheduleWork(DriveBLEState, 0);
+
+    return err;
+}
+
+CHIP_ERROR BLEManagerImpl::_SetAdvertisingMode(BLEAdvertisingMode mode)
+{
+    switch (mode)
+    {
+    case BLEAdvertisingMode::kFastAdvertising:
+        mFlags.Set(Flags::kFastAdvertisingEnabled, true);
+        break;
+    case BLEAdvertisingMode::kSlowAdvertising:
+        mFlags.Set(Flags::kFastAdvertisingEnabled, false);
+        break;
+    default:
+        return CHIP_ERROR_INVALID_ARGUMENT;
+    }
+    mFlags.Set(Flags::kAdvertisingRefreshNeeded);
+    PlatformMgr().ScheduleWork(DriveBLEState, 0);
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR BLEManagerImpl::_GetDeviceName(char * buf, size_t bufSize)
+{
+    if (strlen(mDeviceName) >= bufSize)
+    {
+        return CHIP_ERROR_BUFFER_TOO_SMALL;
+    }
+    strcpy(buf, mDeviceName);
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR BLEManagerImpl::_SetDeviceName(const char * deviceName)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    VerifyOrExit(mServiceMode != ConnectivityManager::kCHIPoBLEServiceMode_NotSupported, err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE);
+
+    if (deviceName != nullptr && deviceName[0] != 0)
+    {
+        VerifyOrExit(strlen(deviceName) < kMaxDeviceNameLength, err = CHIP_ERROR_INVALID_ARGUMENT);
+        strcpy(mDeviceName, deviceName);
+        mFlags.Set(Flags::kUseCustomDeviceName);
+    }
+    else
+    {
+        uint16_t discriminator;
+        SuccessOrExit(err = ConfigurationMgr().GetSetupDiscriminator(discriminator));
+        snprintf(mDeviceName, sizeof(mDeviceName), "%s%04u", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, discriminator);
+        mDeviceName[kMaxDeviceNameLength] = 0;
+        mFlags.Clear(Flags::kUseCustomDeviceName);
+    }
+
+exit:
+    return err;
+}
+
+uint16_t BLEManagerImpl::_NumConnections()
+{
+    uint16_t numCons = 0;
+    return numCons;
+}
+
+CHIP_ERROR BLEManagerImpl::ConfigureBle(uint32_t aAdapterId, bool aIsCentral)
+{
+    CHIP_ERROR err                  = CHIP_NO_ERROR;
+    mBLEAdvConfig.mpBleName         = mDeviceName;
+    mBLEAdvConfig.mAdapterId        = aAdapterId;
+    mBLEAdvConfig.mMajor            = 1;
+    mBLEAdvConfig.mMinor            = 1;
+    mBLEAdvConfig.mVendorId         = 1;
+    mBLEAdvConfig.mProductId        = 1;
+    mBLEAdvConfig.mDeviceId         = 1;
+    mBLEAdvConfig.mDuration         = 2;
+    mBLEAdvConfig.mPairingStatus    = 0;
+    mBLEAdvConfig.mType             = ChipAdvType::BLUEZ_ADV_TYPE_UNDIRECTED_CONNECTABLE_SCANNABLE;
+    mBLEAdvConfig.mpAdvertisingUUID = "0xFEAF";
+
+    mIsCentral = aIsCentral;
+
+    return err;
+}
+
+CHIP_ERROR BLEManagerImpl::StartBLEAdvertising()
+{
+    return StartBluezAdv(mpEndpoint);
+}
+
+CHIP_ERROR BLEManagerImpl::StopBLEAdvertising()
+{
+    return StopBluezAdv(mpEndpoint);
+}
+
+void BLEManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
+{
+    switch (event->Type)
+    {
+    case DeviceEventType::kCHIPoBLESubscribe:
+        HandleSubscribeReceived(event->CHIPoBLESubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
+        {
+            ChipDeviceEvent connectionEvent;
+            connectionEvent.Type = DeviceEventType::kCHIPoBLEConnectionEstablished;
+            PlatformMgr().PostEvent(&connectionEvent);
+        }
+        break;
+
+    case DeviceEventType::kCHIPoBLEUnsubscribe:
+        HandleUnsubscribeReceived(event->CHIPoBLEUnsubscribe.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
+        break;
+
+    case DeviceEventType::kCHIPoBLEWriteReceived:
+        HandleWriteReceived(event->CHIPoBLEWriteReceived.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_RX,
+                            PacketBufferHandle::Adopt(event->CHIPoBLEWriteReceived.Data));
+        break;
+
+    case DeviceEventType::kCHIPoBLEIndicateConfirm:
+        HandleIndicationConfirmation(event->CHIPoBLEIndicateConfirm.ConId, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX);
+        break;
+
+    case DeviceEventType::kCHIPoBLEConnectionError:
+        HandleConnectionError(event->CHIPoBLEConnectionError.ConId, event->CHIPoBLEConnectionError.Reason);
+        break;
+    case DeviceEventType::kFabricMembershipChange:
+    case DeviceEventType::kServiceProvisioningChange:
+    case DeviceEventType::kAccountPairingChange:
+
+        // If CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled, and there is a change to the
+        // device's provisioning state, then automatically disable CHIPoBLE advertising if the device
+        // is now fully provisioned.
+#if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED
+        if (ConfigurationMgr().IsFullyProvisioned())
+        {
+            mFlags.Clear(Flags::kAdvertisingEnabled);
+            ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned");
+        }
+#endif // CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED
+
+        // Force the advertising configuration to be refreshed to reflect new provisioning state.
+        mFlags.Clear(Flags::kAdvertisingConfigured);
+
+        DriveBLEState();
+        break;
+    default:
+        HandlePlatformSpecificBLEEvent(event);
+        break;
+    }
+}
+
+void BLEManagerImpl::HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * apEvent)
+{
+    CHIP_ERROR err         = CHIP_NO_ERROR;
+    bool controlOpComplete = false;
+    ChipLogProgress(DeviceLayer, "HandlePlatformSpecificBLEEvent %d", apEvent->Type);
+    switch (apEvent->Type)
+    {
+    case DeviceEventType::kPlatformLinuxBLECentralConnected:
+        if (mBLEScanConfig.mBleScanState == BleScanState::kConnecting)
+        {
+            OnConnectionComplete(mBLEScanConfig.mAppState, apEvent->Platform.BLECentralConnected.mConnection);
+            CleanScanConfig();
+        }
+        break;
+    case DeviceEventType::kPlatformLinuxBLECentralConnectFailed:
+        if (mBLEScanConfig.mBleScanState == BleScanState::kConnecting)
+        {
+            OnConnectionError(mBLEScanConfig.mAppState, apEvent->Platform.BLECentralConnectFailed.mError);
+            CleanScanConfig();
+        }
+        break;
+    case DeviceEventType::kPlatformLinuxBLEWriteComplete:
+        HandleWriteConfirmation(apEvent->Platform.BLEWriteComplete.mConnection, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_RX);
+        break;
+    case DeviceEventType::kPlatformLinuxBLESubscribeOpComplete:
+        if (apEvent->Platform.BLESubscribeOpComplete.mIsSubscribed)
+            HandleSubscribeComplete(apEvent->Platform.BLESubscribeOpComplete.mConnection, &CHIP_BLE_SVC_ID,
+                                    &ChipUUID_CHIPoBLEChar_TX);
+        else
+            HandleUnsubscribeComplete(apEvent->Platform.BLESubscribeOpComplete.mConnection, &CHIP_BLE_SVC_ID,
+                                      &ChipUUID_CHIPoBLEChar_TX);
+        break;
+    case DeviceEventType::kPlatformLinuxBLEIndicationReceived:
+        HandleIndicationReceived(apEvent->Platform.BLEIndicationReceived.mConnection, &CHIP_BLE_SVC_ID, &ChipUUID_CHIPoBLEChar_TX,
+                                 PacketBufferHandle::Adopt(apEvent->Platform.BLEIndicationReceived.mData));
+        break;
+    case DeviceEventType::kPlatformLinuxBLEPeripheralAdvConfiguredComplete:
+        VerifyOrExit(apEvent->Platform.BLEPeripheralAdvConfiguredComplete.mIsSuccess, err = CHIP_ERROR_INCORRECT_STATE);
+        sInstance.mFlags.Set(Flags::kAdvertisingConfigured).Clear(Flags::kControlOpInProgress);
+        controlOpComplete = true;
+        ChipLogProgress(DeviceLayer, "CHIPoBLE advertising config complete");
+        break;
+    case DeviceEventType::kPlatformLinuxBLEPeripheralAdvStartComplete:
+        VerifyOrExit(apEvent->Platform.BLEPeripheralAdvStartComplete.mIsSuccess, err = CHIP_ERROR_INCORRECT_STATE);
+        sInstance.mFlags.Clear(Flags::kControlOpInProgress).Clear(Flags::kAdvertisingRefreshNeeded);
+
+        if (!sInstance.mFlags.Has(Flags::kAdvertising))
+        {
+            sInstance.mFlags.Set(Flags::kAdvertising);
+        }
+
+        break;
+    case DeviceEventType::kPlatformLinuxBLEPeripheralAdvStopComplete:
+        VerifyOrExit(apEvent->Platform.BLEPeripheralAdvStopComplete.mIsSuccess, err = CHIP_ERROR_INCORRECT_STATE);
+
+        sInstance.mFlags.Clear(Flags::kControlOpInProgress).Clear(Flags::kAdvertisingRefreshNeeded);
+
+        // Transition to the not Advertising state...
+        if (sInstance.mFlags.Has(Flags::kAdvertising))
+        {
+            sInstance.mFlags.Clear(Flags::kAdvertising);
+            ChipLogProgress(DeviceLayer, "CHIPoBLE advertising stopped");
+        }
+        break;
+    case DeviceEventType::kPlatformLinuxBLEPeripheralRegisterAppComplete:
+        VerifyOrExit(apEvent->Platform.BLEPeripheralRegisterAppComplete.mIsSuccess, err = CHIP_ERROR_INCORRECT_STATE);
+        mFlags.Set(Flags::kAppRegistered);
+        controlOpComplete = true;
+        break;
+    default:
+        break;
+    }
+
+exit:
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err));
+        mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
+        sInstance.mFlags.Clear(Flags::kControlOpInProgress);
+    }
+
+    if (controlOpComplete)
+    {
+        mFlags.Clear(Flags::kControlOpInProgress);
+        DriveBLEState();
+    }
+}
+
+uint16_t BLEManagerImpl::GetMTU(BLE_CONNECTION_OBJECT conId) const
+{
+    BluezConnection * connection = static_cast<BluezConnection *>(conId);
+    return (connection != nullptr) ? connection->mMtu : 0;
+}
+
+bool BLEManagerImpl::SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
+{
+    bool result = false;
+
+    VerifyOrExit(Ble::UUIDsMatch(svcId, &CHIP_BLE_SVC_ID),
+                 ChipLogError(DeviceLayer, "SubscribeCharacteristic() called with invalid service ID"));
+    VerifyOrExit(Ble::UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_TX),
+                 ChipLogError(DeviceLayer, "SubscribeCharacteristic() called with invalid characteristic ID"));
+
+    result = BluezSubscribeCharacteristic(conId);
+exit:
+    return result;
+}
+
+bool BLEManagerImpl::UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const ChipBleUUID * charId)
+{
+    bool result = false;
+
+    VerifyOrExit(Ble::UUIDsMatch(svcId, &CHIP_BLE_SVC_ID),
+                 ChipLogError(DeviceLayer, "UnsubscribeCharacteristic() called with invalid service ID"));
+    VerifyOrExit(Ble::UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_TX),
+                 ChipLogError(DeviceLayer, "UnsubscribeCharacteristic() called with invalid characteristic ID"));
+
+    result = BluezUnsubscribeCharacteristic(conId);
+exit:
+    return result;
+}
+
+bool BLEManagerImpl::CloseConnection(BLE_CONNECTION_OBJECT conId)
+{
+    ChipLogProgress(DeviceLayer, "Closing BLE GATT connection (con %p)", conId);
+    return CloseBluezConnection(conId);
+}
+
+bool BLEManagerImpl::SendIndication(BLE_CONNECTION_OBJECT conId, const ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
+                                    chip::System::PacketBufferHandle pBuf)
+{
+    return SendBluezIndication(conId, std::move(pBuf));
+}
+
+bool BLEManagerImpl::SendWriteRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
+                                      chip::System::PacketBufferHandle pBuf)
+{
+    bool result = false;
+
+    VerifyOrExit(Ble::UUIDsMatch(svcId, &CHIP_BLE_SVC_ID),
+                 ChipLogError(DeviceLayer, "SendWriteRequest() called with invalid service ID"));
+    VerifyOrExit(Ble::UUIDsMatch(charId, &ChipUUID_CHIPoBLEChar_RX),
+                 ChipLogError(DeviceLayer, "SendWriteRequest() called with invalid characteristic ID"));
+
+    result = BluezSendWriteRequest(conId, std::move(pBuf));
+exit:
+    return result;
+}
+
+bool BLEManagerImpl::SendReadRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
+                                     chip::System::PacketBufferHandle pBuf)
+{
+    ChipLogError(Ble, "SendReadRequest: Not implemented");
+    return true;
+}
+
+bool BLEManagerImpl::SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext,
+                                      const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId)
+{
+    ChipLogError(Ble, "SendReadRBluezonse: Not implemented");
+    return true;
+}
+
+void BLEManagerImpl::HandleNewConnection(BLE_CONNECTION_OBJECT conId)
+{
+    if (sInstance.mIsCentral)
+    {
+        ChipDeviceEvent event;
+        event.Type                                     = DeviceEventType::kPlatformLinuxBLECentralConnected;
+        event.Platform.BLECentralConnected.mConnection = conId;
+        PlatformMgr().PostEvent(&event);
+    }
+}
+
+void BLEManagerImpl::HandleConnectFailed(CHIP_ERROR error)
+{
+    if (sInstance.mIsCentral)
+    {
+        ChipDeviceEvent event;
+        event.Type                                    = DeviceEventType::kPlatformLinuxBLECentralConnectFailed;
+        event.Platform.BLECentralConnectFailed.mError = error;
+        PlatformMgr().PostEvent(&event);
+    }
+}
+
+void BLEManagerImpl::HandleWriteComplete(BLE_CONNECTION_OBJECT conId)
+{
+    ChipDeviceEvent event;
+    event.Type                                  = DeviceEventType::kPlatformLinuxBLEWriteComplete;
+    event.Platform.BLEWriteComplete.mConnection = conId;
+    PlatformMgr().PostEvent(&event);
+}
+
+void BLEManagerImpl::HandleSubscribeOpComplete(BLE_CONNECTION_OBJECT conId, bool subscribed)
+{
+    ChipDeviceEvent event;
+    event.Type                                          = DeviceEventType::kPlatformLinuxBLESubscribeOpComplete;
+    event.Platform.BLESubscribeOpComplete.mConnection   = conId;
+    event.Platform.BLESubscribeOpComplete.mIsSubscribed = subscribed;
+    PlatformMgr().PostEvent(&event);
+}
+
+void BLEManagerImpl::HandleTXCharChanged(BLE_CONNECTION_OBJECT conId, const uint8_t * value, size_t len)
+{
+    CHIP_ERROR err                 = CHIP_NO_ERROR;
+    System::PacketBufferHandle buf = System::PacketBufferHandle::NewWithData(value, len);
+
+    ChipLogProgress(DeviceLayer, "Indication received, conn = %p", conId);
+
+    VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
+
+    ChipDeviceEvent event;
+    event.Type                                       = DeviceEventType::kPlatformLinuxBLEIndicationReceived;
+    event.Platform.BLEIndicationReceived.mConnection = conId;
+    event.Platform.BLEIndicationReceived.mData       = std::move(buf).UnsafeRelease();
+    PlatformMgr().PostEvent(&event);
+
+exit:
+    if (err != CHIP_NO_ERROR)
+        ChipLogError(DeviceLayer, "HandleTXCharChanged() failed: %s", ErrorStr(err));
+}
+
+void BLEManagerImpl::HandleRXCharWrite(BLE_CONNECTION_OBJECT conId, const uint8_t * value, size_t len)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+    System::PacketBufferHandle buf;
+
+    // Copy the data to a packet buffer.
+    buf = System::PacketBufferHandle::NewWithData(value, len);
+    VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
+
+    // Post an event to the Chip queue to deliver the data into the Chip stack.
+    {
+        ChipDeviceEvent event;
+        event.Type = DeviceEventType::kCHIPoBLEWriteReceived;
+        ChipLogProgress(Ble, "Write request received debug %p", conId);
+        event.CHIPoBLEWriteReceived.ConId = conId;
+        event.CHIPoBLEWriteReceived.Data  = std::move(buf).UnsafeRelease();
+        PlatformMgr().PostEvent(&event);
+    }
+
+exit:
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(DeviceLayer, "HandleRXCharWrite() failed: %s", ErrorStr(err));
+    }
+}
+
+void BLEManagerImpl::CHIPoBluez_ConnectionClosed(BLE_CONNECTION_OBJECT conId)
+{
+    ChipLogProgress(DeviceLayer, "Bluez notify CHIPoBluez connection disconnected");
+
+    // If this was a CHIPoBLE connection, post an event to deliver a connection error to the CHIPoBLE layer.
+    {
+        ChipDeviceEvent event;
+        event.Type                           = DeviceEventType::kCHIPoBLEConnectionError;
+        event.CHIPoBLEConnectionError.ConId  = conId;
+        event.CHIPoBLEConnectionError.Reason = BLE_ERROR_REMOTE_DEVICE_DISCONNECTED;
+        PlatformMgr().PostEvent(&event);
+    }
+}
+
+void BLEManagerImpl::HandleTXCharCCCDWrite(BLE_CONNECTION_OBJECT conId)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    BluezConnection * connection = static_cast<BluezConnection *>(conId);
+
+    VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "Connection is NULL in HandleTXCharCCCDWrite"));
+    VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in HandleTXCharCCCDWrite"));
+
+    // Post an event to the Chip queue to process either a CHIPoBLE Subscribe or Unsubscribe based on
+    // whether the client is enabling or disabling indications.
+    {
+        ChipDeviceEvent event;
+        event.Type = connection->mIsNotify ? DeviceEventType::kCHIPoBLESubscribe : DeviceEventType::kCHIPoBLEUnsubscribe;
+        event.CHIPoBLESubscribe.ConId = connection;
+        PlatformMgr().PostEvent(&event);
+    }
+
+    ChipLogProgress(DeviceLayer, "CHIPoBLE %s received", connection->mIsNotify ? "subscribe" : "unsubscribe");
+
+exit:
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(DeviceLayer, "HandleTXCharCCCDWrite() failed: %s", ErrorStr(err));
+        // TODO: fail connection
+    }
+}
+
+void BLEManagerImpl::HandleTXComplete(BLE_CONNECTION_OBJECT conId)
+{
+    // Post an event to the Chip queue to process the indicate confirmation.
+    ChipDeviceEvent event;
+    event.Type                          = DeviceEventType::kCHIPoBLEIndicateConfirm;
+    event.CHIPoBLEIndicateConfirm.ConId = conId;
+    PlatformMgr().PostEvent(&event);
+}
+
+void BLEManagerImpl::DriveBLEState()
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    // Perform any initialization actions that must occur after the Chip task is running.
+    if (!mFlags.Has(Flags::kAsyncInitCompleted))
+    {
+        mFlags.Set(Flags::kAsyncInitCompleted);
+
+        // If CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED is enabled,
+        // disable CHIPoBLE advertising if the device is fully provisioned.
+#if CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED
+        if (ConfigurationMgr().IsFullyProvisioned())
+        {
+            mFlags.Clear(Flags::kAdvertisingEnabled);
+            ChipLogProgress(DeviceLayer, "CHIPoBLE advertising disabled because device is fully provisioned");
+        }
+#endif // CHIP_DEVICE_CONFIG_CHIPOBLE_DISABLE_ADVERTISING_WHEN_PROVISIONED
+        ExitNow();
+    }
+
+    // If there's already a control operation in progress, wait until it completes.
+    VerifyOrExit(!mFlags.Has(Flags::kControlOpInProgress), /* */);
+
+    // Initializes the Bluez BLE layer if needed.
+    if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && !mFlags.Has(Flags::kBluezBLELayerInitialized))
+    {
+        err = InitBluezBleLayer(mIsCentral, nullptr, mBLEAdvConfig, mpEndpoint);
+        SuccessOrExit(err);
+        mFlags.Set(Flags::kBluezBLELayerInitialized);
+    }
+
+    // Register the CHIPoBLE application with the Bluez BLE layer if needed.
+    if (!mIsCentral && mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && !mFlags.Has(Flags::kAppRegistered))
+    {
+        err = BluezGattsAppRegister(mpEndpoint);
+        mFlags.Set(Flags::kControlOpInProgress);
+        ExitNow();
+    }
+
+    // If the application has enabled CHIPoBLE and BLE advertising...
+    if (mServiceMode == ConnectivityManager::kCHIPoBLEServiceMode_Enabled && mFlags.Has(Flags::kAdvertisingEnabled))
+    {
+        // Start/re-start advertising if not already advertising, or if the advertising state of the
+        // Bluez BLE layer needs to be refreshed.
+        if (!mFlags.Has(Flags::kAdvertising) || mFlags.Has(Flags::kAdvertisingRefreshNeeded))
+        {
+            mFlags.Clear(Flags::kAdvertisingRefreshNeeded);
+
+            // Configure advertising data if it hasn't been done yet.  This is an asynchronous step which
+            // must complete before advertising can be started.  When that happens, this method will
+            // be called again, and execution will proceed to the code below.
+            if (!mFlags.Has(Flags::kAdvertisingConfigured))
+            {
+                err = BluezAdvertisementSetup(mpEndpoint);
+                ExitNow();
+            }
+
+            // Start advertising.  This is also an asynchronous step.
+            err = StartBLEAdvertising();
+            SuccessOrExit(err);
+
+            sInstance.mFlags.Set(Flags::kAdvertising);
+            ExitNow();
+        }
+    }
+
+    // Otherwise stop advertising if needed...
+    else
+    {
+        if (mFlags.Has(Flags::kAdvertising))
+        {
+            err = StopBLEAdvertising();
+            SuccessOrExit(err);
+            mFlags.Set(Flags::kControlOpInProgress);
+
+            ExitNow();
+        }
+    }
+
+exit:
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(DeviceLayer, "Disabling CHIPoBLE service due to error: %s", ErrorStr(err));
+        mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Disabled;
+    }
+}
+
+void BLEManagerImpl::DriveBLEState(intptr_t arg)
+{
+    sInstance.DriveBLEState();
+}
+
+void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId)
+{
+    ChipLogProgress(Ble, "Got notification regarding chip connection closure");
+}
+
+void BLEManagerImpl::InitiateScan(BleScanState scanType)
+{
+    DriveBLEState();
+
+    if (scanType == BleScanState::kNotScanning)
+    {
+        OnConnectionError(mBLEScanConfig.mAppState, CHIP_ERROR_INCORRECT_STATE);
+        ChipLogError(Ble, "Invalid scan type requested");
+        return;
+    }
+
+    if (mpEndpoint == nullptr)
+    {
+        OnConnectionError(mBLEScanConfig.mAppState, CHIP_ERROR_INCORRECT_STATE);
+        ChipLogError(Ble, "BLE Layer is not yet initialized");
+        return;
+    }
+
+    if (mpEndpoint->mpAdapter == nullptr)
+    {
+        OnConnectionError(mBLEScanConfig.mAppState, CHIP_ERROR_INCORRECT_STATE);
+        ChipLogError(Ble, "No adapter available for new connection establishment");
+        return;
+    }
+
+    mDeviceScanner               = Internal::ChipDeviceScanner::Create(mpEndpoint->mpAdapter, this);
+    mBLEScanConfig.mBleScanState = scanType;
+
+    if (!mDeviceScanner)
+    {
+        mBLEScanConfig.mBleScanState = BleScanState::kNotScanning;
+        OnConnectionError(mBLEScanConfig.mAppState, CHIP_ERROR_INTERNAL);
+        ChipLogError(Ble, "Failed to create a BLE device scanner");
+        return;
+    }
+
+    CHIP_ERROR err = mDeviceScanner->StartScan(kNewConnectionScanTimeoutMs);
+    if (err != CHIP_NO_ERROR)
+    {
+        mBLEScanConfig.mBleScanState = BleScanState::kNotScanning;
+        ChipLogError(Ble, "Failed to start a BLE can: %s", chip::ErrorStr(err));
+        OnConnectionError(mBLEScanConfig.mAppState, err);
+        return;
+    }
+}
+
+void BLEManagerImpl::CleanScanConfig()
+{
+    if (mBLEScanConfig.mBleScanState == BleScanState::kConnecting)
+        DeviceLayer::SystemLayer.CancelTimer(HandleConnectTimeout, mpEndpoint);
+
+    mBLEScanConfig.mBleScanState = BleScanState::kNotScanning;
+}
+
+void BLEManagerImpl::InitiateScan(intptr_t arg)
+{
+    sInstance.InitiateScan(static_cast<BleScanState>(arg));
+}
+
+void BLEManagerImpl::NewConnection(BleLayer * bleLayer, void * appState, const uint16_t connDiscriminator)
+{
+    mBLEScanConfig.mDiscriminator = connDiscriminator;
+    mBLEScanConfig.mAppState      = appState;
+
+    // Scan initiation performed async, to ensure that the BLE subsystem is initialized.
+    PlatformMgr().ScheduleWork(InitiateScan, static_cast<intptr_t>(BleScanState::kScanForDiscriminator));
+}
+
+BLE_ERROR BLEManagerImpl::CancelConnection()
+{
+    return BLE_ERROR_NOT_IMPLEMENTED;
+}
+
+void BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(bool aIsSuccess, void * apAppstate)
+{
+    ChipDeviceEvent event;
+    event.Type                                                 = DeviceEventType::kPlatformLinuxBLEPeripheralRegisterAppComplete;
+    event.Platform.BLEPeripheralRegisterAppComplete.mIsSuccess = aIsSuccess;
+    event.Platform.BLEPeripheralRegisterAppComplete.mpAppstate = apAppstate;
+    PlatformMgr().PostEvent(&event);
+}
+
+void BLEManagerImpl::NotifyBLEPeripheralAdvConfiguredComplete(bool aIsSuccess, void * apAppstate)
+{
+    ChipDeviceEvent event;
+    event.Type = DeviceEventType::kPlatformLinuxBLEPeripheralAdvConfiguredComplete;
+    event.Platform.BLEPeripheralAdvConfiguredComplete.mIsSuccess = aIsSuccess;
+    event.Platform.BLEPeripheralAdvConfiguredComplete.mpAppstate = apAppstate;
+    PlatformMgr().PostEvent(&event);
+}
+
+void BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(bool aIsSuccess, void * apAppstate)
+{
+    ChipDeviceEvent event;
+    event.Type                                              = DeviceEventType::kPlatformLinuxBLEPeripheralAdvStartComplete;
+    event.Platform.BLEPeripheralAdvStartComplete.mIsSuccess = aIsSuccess;
+    event.Platform.BLEPeripheralAdvStartComplete.mpAppstate = apAppstate;
+    PlatformMgr().PostEvent(&event);
+}
+
+void BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(bool aIsSuccess, void * apAppstate)
+{
+    ChipDeviceEvent event;
+    event.Type                                             = DeviceEventType::kPlatformLinuxBLEPeripheralAdvStopComplete;
+    event.Platform.BLEPeripheralAdvStopComplete.mIsSuccess = aIsSuccess;
+    event.Platform.BLEPeripheralAdvStopComplete.mpAppstate = apAppstate;
+    PlatformMgr().PostEvent(&event);
+}
+
+void BLEManagerImpl::OnDeviceScanned(BluezDevice1 * device, const chip::Ble::ChipBLEDeviceIdentificationInfo & info)
+{
+    ChipLogProgress(Ble, "New device scanned: %s", bluez_device1_get_address(device));
+
+    if (mBLEScanConfig.mBleScanState == BleScanState::kScanForDiscriminator)
+    {
+        if (info.GetDeviceDiscriminator() != mBLEScanConfig.mDiscriminator)
+        {
+            return;
+        }
+        ChipLogProgress(Ble, "Device discriminator match. Attempting to connect.");
+    }
+    else if (mBLEScanConfig.mBleScanState == BleScanState::kScanForAddress)
+    {
+        if (strcmp(bluez_device1_get_address(device), mBLEScanConfig.mAddress.c_str()) != 0)
+        {
+            return;
+        }
+        ChipLogProgress(Ble, "Device address match. Attempting to connect.");
+    }
+    else
+    {
+        // Internal consistency eerror
+        ChipLogError(Ble, "Unknown discovery type. Ignoring scanned device.");
+        return;
+    }
+
+    mBLEScanConfig.mBleScanState = BleScanState::kConnecting;
+    DeviceLayer::SystemLayer.StartTimer(kConnectTimeoutMs, HandleConnectTimeout, mpEndpoint);
+    mDeviceScanner->StopScan();
+
+    ConnectDevice(device, mpEndpoint);
+}
+
+void BLEManagerImpl::OnScanComplete()
+{
+    if (mBLEScanConfig.mBleScanState != BleScanState::kScanForDiscriminator &&
+        mBLEScanConfig.mBleScanState != BleScanState::kScanForAddress)
+    {
+        ChipLogProgress(Ble, "Scan complete notification without an active scan.");
+        return;
+    }
+
+    OnConnectionError(mBLEScanConfig.mAppState, CHIP_ERROR_TIMEOUT);
+    mBLEScanConfig.mBleScanState = BleScanState::kNotScanning;
+}
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
+
+#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
diff --git a/src/platform/Tizen/BLEManagerImpl.h b/src/platform/Tizen/BLEManagerImpl.h
new file mode 100644 (file)
index 0000000..72705ba
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ *
+ *    Copyright (c) 2020-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.
+ */
+
+/**
+ *    @file
+ *          Provides an implementation of the BLEManager singleton object
+ *          for the Linux platforms.
+ */
+
+#pragma once
+
+#include <ble/BleLayer.h>
+#include <platform/internal/BLEManager.h>
+
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+
+#include "bluez/ChipDeviceScanner.h"
+#include "bluez/Types.h"
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+void HandleIncomingBleConnection(Ble::BLEEndPoint * bleEP);
+
+struct BLEAdvConfig
+{
+    char * mpBleName;
+    uint32_t mAdapterId;
+    uint8_t mMajor;
+    uint8_t mMinor;
+    uint16_t mVendorId;
+    uint16_t mProductId;
+    uint64_t mDeviceId;
+    uint8_t mPairingStatus;
+    ChipAdvType mType;
+    uint16_t mDuration;
+    const char * mpAdvertisingUUID;
+};
+
+enum class BleScanState : uint8_t
+{
+    kNotScanning,
+    kScanForDiscriminator,
+    kScanForAddress,
+    kConnecting,
+};
+
+struct BLEScanConfig
+{
+    // If an active scan for connection is being performed
+    BleScanState mBleScanState = BleScanState::kNotScanning;
+
+    // If scanning by discriminator, what are we scanning for
+    uint16_t mDiscriminator = 0;
+
+    // If scanning by address, what address are we searching for
+    std::string mAddress;
+
+    // Optional argument to be passed to callback functions provided by the BLE scan/connect requestor
+    void * mAppState = nullptr;
+};
+
+/**
+ * Concrete implementation of the BLEManagerImpl singleton object for the Linux platforms.
+ */
+class BLEManagerImpl final : public BLEManager,
+                             private Ble::BleLayer,
+                             private Ble::BlePlatformDelegate,
+                             private Ble::BleApplicationDelegate,
+                             private Ble::BleConnectionDelegate,
+                             private ChipDeviceScannerDelegate
+{
+    // Allow the BLEManager interface class to delegate method calls to
+    // the implementation methods provided by this class.
+    friend BLEManager;
+
+public:
+    CHIP_ERROR ConfigureBle(uint32_t aAdapterId, bool aIsCentral);
+
+    // Driven by BlueZ IO
+    static void HandleNewConnection(BLE_CONNECTION_OBJECT conId);
+    static void HandleConnectFailed(CHIP_ERROR error);
+    static void HandleWriteComplete(BLE_CONNECTION_OBJECT conId);
+    static void HandleSubscribeOpComplete(BLE_CONNECTION_OBJECT conId, bool subscribed);
+    static void HandleTXCharChanged(BLE_CONNECTION_OBJECT conId, const uint8_t * value, size_t len);
+    static void HandleRXCharWrite(BLE_CONNECTION_OBJECT user_data, const uint8_t * value, size_t len);
+    static void CHIPoBluez_ConnectionClosed(BLE_CONNECTION_OBJECT user_data);
+    static void HandleTXCharCCCDWrite(BLE_CONNECTION_OBJECT user_data);
+    static void HandleTXComplete(BLE_CONNECTION_OBJECT user_data);
+
+    static void NotifyBLEPeripheralRegisterAppComplete(bool aIsSuccess, void * apAppstate);
+    static void NotifyBLEPeripheralAdvConfiguredComplete(bool aIsSuccess, void * apAppstate);
+    static void NotifyBLEPeripheralAdvStartComplete(bool aIsSuccess, void * apAppstate);
+    static void NotifyBLEPeripheralAdvStopComplete(bool aIsSuccess, void * apAppstate);
+
+private:
+    // ===== Members that implement the BLEManager internal interface.
+
+    CHIP_ERROR _Init();
+    CHIPoBLEServiceMode _GetCHIPoBLEServiceMode();
+    CHIP_ERROR _SetCHIPoBLEServiceMode(CHIPoBLEServiceMode val);
+    bool _IsAdvertisingEnabled();
+    CHIP_ERROR _SetAdvertisingEnabled(bool val);
+    bool _IsAdvertising();
+    CHIP_ERROR _SetAdvertisingMode(BLEAdvertisingMode mode);
+    CHIP_ERROR _GetDeviceName(char * buf, size_t bufSize);
+    CHIP_ERROR _SetDeviceName(const char * deviceName);
+    uint16_t _NumConnections();
+
+    void _OnPlatformEvent(const ChipDeviceEvent * event);
+    void HandlePlatformSpecificBLEEvent(const ChipDeviceEvent * event);
+    BleLayer * _GetBleLayer();
+
+    // ===== Members that implement virtual methods on BlePlatformDelegate.
+
+    bool SubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId,
+                                 const Ble::ChipBleUUID * charId) override;
+    bool UnsubscribeCharacteristic(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId,
+                                   const Ble::ChipBleUUID * charId) override;
+    bool CloseConnection(BLE_CONNECTION_OBJECT conId) override;
+    uint16_t GetMTU(BLE_CONNECTION_OBJECT conId) const override;
+    bool SendIndication(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
+                        System::PacketBufferHandle pBuf) override;
+    bool SendWriteRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
+                          System::PacketBufferHandle pBuf) override;
+    bool SendReadRequest(BLE_CONNECTION_OBJECT conId, const Ble::ChipBleUUID * svcId, const Ble::ChipBleUUID * charId,
+                         System::PacketBufferHandle pBuf) override;
+    bool SendReadResponse(BLE_CONNECTION_OBJECT conId, BLE_READ_REQUEST_CONTEXT requestContext, const Ble::ChipBleUUID * svcId,
+                          const Ble::ChipBleUUID * charId) override;
+
+    // ===== Members that implement virtual methods on BleApplicationDelegate.
+
+    void NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) override;
+
+    // ===== Members that implement virtual methods on BleConnectionDelegate.
+
+    void NewConnection(BleLayer * bleLayer, void * appState, uint16_t connDiscriminator) override;
+    BLE_ERROR CancelConnection() override;
+
+    // ===== Members that implement virtual methods on ChipDeviceScannerDelegate
+    void OnDeviceScanned(BluezDevice1 * device, const chip::Ble::ChipBLEDeviceIdentificationInfo & info) override;
+    void OnScanComplete() override;
+
+    // ===== Members for internal use by the following friends.
+
+    friend BLEManager & BLEMgr();
+    friend BLEManagerImpl & BLEMgrImpl();
+
+    static BLEManagerImpl sInstance;
+
+    // ===== Private members reserved for use by this class only.
+    enum class Flags : uint16_t
+    {
+        kAsyncInitCompleted       = 0x0001, /**< One-time asynchronous initialization actions have been performed. */
+        kBluezBLELayerInitialized = 0x0002, /**< The Bluez layer has been initialized. */
+        kAppRegistered            = 0x0004, /**< The CHIPoBLE application has been registered with the Bluez layer. */
+        kAdvertisingConfigured    = 0x0008, /**< CHIPoBLE advertising has been configured in the Bluez layer. */
+        kAdvertising              = 0x0010, /**< The system is currently CHIPoBLE advertising. */
+        kControlOpInProgress      = 0x0020, /**< An async control operation has been issued to the ESP BLE layer. */
+        kAdvertisingEnabled       = 0x0040, /**< The application has enabled CHIPoBLE advertising. */
+        kFastAdvertisingEnabled   = 0x0080, /**< The application has enabled fast advertising. */
+        kUseCustomDeviceName      = 0x0100, /**< The application has configured a custom BLE device name. */
+        kAdvertisingRefreshNeeded = 0x0200, /**< The advertising configuration/state in BLE layer needs to be updated. */
+    };
+
+    enum
+    {
+        kMaxConnections             = 1,  // TODO: right max connection
+        kMaxDeviceNameLength        = 20, // TODO: right-size this
+        kMaxAdvertismentDataSetSize = 31  // TODO: verify this
+    };
+
+    CHIP_ERROR StartBLEAdvertising();
+    CHIP_ERROR StopBLEAdvertising();
+
+    void DriveBLEState();
+    static void DriveBLEState(intptr_t arg);
+
+    void InitiateScan(BleScanState scanType);
+    static void InitiateScan(intptr_t arg);
+    void CleanScanConfig();
+
+    CHIPoBLEServiceMode mServiceMode;
+    BLEAdvConfig mBLEAdvConfig;
+    BLEScanConfig mBLEScanConfig;
+    BitFlags<Flags> mFlags;
+    char mDeviceName[kMaxDeviceNameLength + 1];
+    bool mIsCentral            = false;
+    BluezEndpoint * mpEndpoint = nullptr;
+    std::unique_ptr<ChipDeviceScanner> mDeviceScanner;
+};
+
+/**
+ * Returns a reference to the public interface of the BLEManager singleton object.
+ *
+ * Internal components should use this to access features of the BLEManager object
+ * that are common to all platforms.
+ */
+inline BLEManager & BLEMgr()
+{
+    return BLEManagerImpl::sInstance;
+}
+
+/**
+ * Returns the platform-specific implementation of the BLEManager singleton object.
+ *
+ * Internal components can use this to gain access to features of the BLEManager
+ * that are specific to the Linux platforms.
+ */
+inline BLEManagerImpl & BLEMgrImpl()
+{
+    return BLEManagerImpl::sInstance;
+}
+
+inline Ble::BleLayer * BLEManagerImpl::_GetBleLayer()
+{
+    return this;
+}
+
+inline BLEManager::CHIPoBLEServiceMode BLEManagerImpl::_GetCHIPoBLEServiceMode()
+{
+    return mServiceMode;
+}
+
+inline bool BLEManagerImpl::_IsAdvertisingEnabled()
+{
+    return mFlags.Has(Flags::kAdvertisingEnabled);
+}
+
+inline bool BLEManagerImpl::_IsAdvertising()
+{
+    return mFlags.Has(Flags::kAdvertising);
+}
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
+
+#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
diff --git a/src/platform/Tizen/BlePlatformConfig.h b/src/platform/Tizen/BlePlatformConfig.h
new file mode 100644 (file)
index 0000000..4c1ffd4
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *
+ *    Copyright (c) 2020 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.
+ */
+
+/**
+ *    @file
+ *          Platform-specific configuration overrides for the CHIP BLE
+ *          Layer on Linux platforms.
+ *
+ */
+
+#pragma once
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+struct BluezConnection;
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
+
+// ==================== Platform Adaptations ====================
+#define BLE_CONNECTION_UNINITIALIZED nullptr
+// ========== Platform-specific Configuration Overrides =========
+
+/* none so far */
diff --git a/src/platform/Tizen/CHIPDevicePlatformConfig.h b/src/platform/Tizen/CHIPDevicePlatformConfig.h
new file mode 100644 (file)
index 0000000..d948cac
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *
+ *    Copyright (c) 2020 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.
+ */
+
+/**
+ *    @file
+ *          Platform-specific configuration overrides for the chip Device Layer
+ *          on Linux platforms.
+ */
+
+#pragma once
+
+// ==================== Platform Adaptations ====================
+
+#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION 0
+#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP 0
+
+#ifndef CHIP_DEVICE_CONFIG_ENABLE_THREAD
+#define CHIP_DEVICE_CONFIG_ENABLE_THREAD CHIP_ENABLE_OPENTHREAD
+#endif
+
+#ifndef CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+#define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 0
+#endif
+
+#define CHIP_DEVICE_CONFIG_ENABLE_CHIP_TIME_SERVICE_TIME_SYNC 0
+
+#define CHIP_DEVICE_CONFIG_PERSISTED_STORAGE_CRIT_EIDC_KEY 2
+#define CHIP_DEVICE_CONFIG_PERSISTED_STORAGE_PROD_EIDC_KEY 3
+#define CHIP_DEVICE_CONFIG_PERSISTED_STORAGE_INFO_EIDC_KEY 4
+#define CHIP_DEVICE_CONFIG_PERSISTED_STORAGE_DEBUG_EIDC_KEY 5
+
+// ========== Platform-specific Configuration =========
+
+// These are configuration options that are unique to Linux platforms.
+// These can be overridden by the application as needed.
+
+/**
+ * @def CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY
+ *
+ * The priority of the SoftDevice observer event handler registered by the
+ * CHIP BleLayer.
+ */
+#ifndef CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY
+#define CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY 3
+#endif // CHIP_DEVICE_LAYER_BLE_OBSERVER_PRIORITY
+
+/**
+ * @def CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG
+ *
+ * The SoftDevice BLE connection configuration tag used by the CHIP
+ * BleLayer.
+ */
+#ifndef CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG
+#define CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG 1
+#endif // CHIP_DEVICE_LAYER_BLE_CONN_CFG_TAG
+
+// ========== Platform-specific Configuration Overrides =========
+
+#ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE
+#define CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE 8192
+#endif // CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE
+
+#ifndef CHIP_DEVICE_CONFIG_THREAD_TASK_STACK_SIZE
+#define CHIP_DEVICE_CONFIG_THREAD_TASK_STACK_SIZE 8192
+#endif // CHIP_DEVICE_CONFIG_THREAD_TASK_STACK_SIZE
+
+#define CHIP_DEVICE_CONFIG_ENABLE_WIFI_TELEMETRY 0
+#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY 0
+#define CHIP_DEVICE_CONFIG_ENABLE_THREAD_TELEMETRY_FULL 0
+
+// TODO: CHIP has redesigned the crypto interface, pending on the final version of CHIP HASH APIs
+#define CHIP_DEVICE_CONFIG_LOG_PROVISIONING_HASH 0
diff --git a/src/platform/Tizen/CHIPDevicePlatformEvent.h b/src/platform/Tizen/CHIPDevicePlatformEvent.h
new file mode 100644 (file)
index 0000000..6daae6a
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *
+ *    Copyright (c) 2020 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.
+ */
+
+/**
+ *    @file
+ *          Defines platform-specific event types and data for the chip
+ *          Device Layer on Linux platforms.
+ */
+
+#pragma once
+
+#include <platform/CHIPDeviceEvent.h>
+
+namespace chip {
+namespace DeviceLayer {
+
+namespace DeviceEventType {
+
+/**
+ * Enumerates Linux platform-specific event types that are visible to the application.
+ */
+enum PublicPlatformSpecificEventTypes
+{
+    /* None currently defined */
+};
+
+/**
+ * Enumerates Linux platform-specific event types that are internal to the chip Device Layer.
+ */
+enum InternalPlatformSpecificEventTypes
+{
+    kPlatformLinuxEvent = kRange_InternalPlatformSpecific,
+    kPlatformLinuxBLECentralConnected,
+    kPlatformLinuxBLECentralConnectFailed,
+    kPlatformLinuxBLEWriteComplete,
+    kPlatformLinuxBLESubscribeOpComplete,
+    kPlatformLinuxBLEIndicationReceived,
+    kPlatformLinuxBLEC1WriteEvent,
+    kPlatformLinuxBLEOutOfBuffersEvent,
+    kPlatformLinuxBLEPeripheralRegisterAppComplete,
+    kPlatformLinuxBLEPeripheralAdvConfiguredComplete,
+    kPlatformLinuxBLEPeripheralAdvStartComplete,
+    kPlatformLinuxBLEPeripheralAdvStopComplete
+};
+
+} // namespace DeviceEventType
+
+/**
+ * Represents platform-specific event information for Linux platforms.
+ */
+struct ChipDevicePlatformEvent
+{
+    union
+    {
+        struct
+        {
+            BLE_CONNECTION_OBJECT mConnection;
+        } BLECentralConnected;
+        struct
+        {
+            CHIP_ERROR mError;
+        } BLECentralConnectFailed;
+        struct
+        {
+            BLE_CONNECTION_OBJECT mConnection;
+        } BLEWriteComplete;
+        struct
+        {
+            BLE_CONNECTION_OBJECT mConnection;
+            bool mIsSubscribed;
+        } BLESubscribeOpComplete;
+        struct
+        {
+            BLE_CONNECTION_OBJECT mConnection;
+            chip::System::PacketBuffer * mData;
+        } BLEIndicationReceived;
+        struct
+        {
+            bool mIsSuccess;
+            void * mpAppstate;
+        } BLEPeripheralRegisterAppComplete;
+        struct
+        {
+            bool mIsSuccess;
+            void * mpAppstate;
+        } BLEPeripheralAdvConfiguredComplete;
+        struct
+        {
+            bool mIsSuccess;
+            void * mpAppstate;
+        } BLEPeripheralAdvStartComplete;
+        struct
+        {
+            bool mIsSuccess;
+            void * mpAppstate;
+        } BLEPeripheralAdvStopComplete;
+    };
+};
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/CHIPLinuxStorage.cpp b/src/platform/Tizen/CHIPLinuxStorage.cpp
new file mode 100644 (file)
index 0000000..cacb172
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ *
+ *    Copyright (c) 2020 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *         This file implements a class for managing client application
+ *         user-editable settings on Linux platform.
+ *
+ */
+
+#include <errno.h>
+#include <fstream>
+#include <inttypes.h>
+#include <libgen.h>
+#include <string>
+#include <unistd.h>
+
+#include <platform/Linux/CHIPLinuxStorage.h>
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+#include <support/Base64.h>
+#include <support/CHIPMem.h>
+#include <support/CodeUtils.h>
+#include <support/ScopedBuffer.h>
+#include <support/logging/CHIPLogging.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+ChipLinuxStorage::ChipLinuxStorage()
+{
+    mDirty = false;
+}
+
+ChipLinuxStorage::~ChipLinuxStorage() {}
+
+CHIP_ERROR ChipLinuxStorage::Init(const char * configFile)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+
+    mConfigPath.assign(configFile);
+    retval = ChipLinuxStorageIni::Init();
+
+    if (retval == CHIP_NO_ERROR)
+    {
+        std::ifstream ifs;
+
+        ifs.open(configFile, std::ifstream::in);
+
+        // Create default setting file if not exist.
+        if (!ifs.good())
+        {
+            mDirty = true;
+            retval = Commit();
+            mDirty = false;
+        }
+    }
+
+    if (retval == CHIP_NO_ERROR)
+    {
+        retval = ChipLinuxStorageIni::AddConfig(mConfigPath);
+    }
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorage::ReadValue(const char * key, bool & val)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+    uint32_t result;
+
+    mLock.lock();
+
+    retval = ChipLinuxStorageIni::GetUIntValue(key, result);
+    val    = (result != 0);
+
+    mLock.unlock();
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorage::ReadValue(const char * key, uint32_t & val)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+
+    mLock.lock();
+
+    retval = ChipLinuxStorageIni::GetUIntValue(key, val);
+
+    mLock.unlock();
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorage::ReadValue(const char * key, uint64_t & val)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+
+    mLock.lock();
+
+    retval = ChipLinuxStorageIni::GetUInt64Value(key, val);
+
+    mLock.unlock();
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorage::ReadValueStr(const char * key, char * buf, size_t bufSize, size_t & outLen)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+
+    mLock.lock();
+
+    retval = ChipLinuxStorageIni::GetStringValue(key, buf, bufSize, outLen);
+
+    mLock.unlock();
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorage::ReadValueBin(const char * key, uint8_t * buf, size_t bufSize, size_t & outLen)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+
+    mLock.lock();
+
+    retval = ChipLinuxStorageIni::GetBinaryBlobValue(key, buf, bufSize, outLen);
+
+    mLock.unlock();
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorage::WriteValue(const char * key, bool val)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+
+    if (val)
+    {
+        retval = WriteValue(key, static_cast<uint32_t>(1));
+    }
+    else
+    {
+        retval = WriteValue(key, static_cast<uint32_t>(0));
+    }
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorage::WriteValue(const char * key, uint32_t val)
+{
+    char buf[32];
+
+    snprintf(buf, sizeof(buf), "%d", val);
+
+    return WriteValueStr(key, buf);
+}
+
+CHIP_ERROR ChipLinuxStorage::WriteValue(const char * key, uint64_t val)
+{
+    char buf[64];
+
+    snprintf(buf, sizeof(buf), "%" PRIu64, val);
+
+    return WriteValueStr(key, buf);
+}
+
+CHIP_ERROR ChipLinuxStorage::WriteValueStr(const char * key, const char * val)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+
+    mLock.lock();
+
+    retval = ChipLinuxStorageIni::AddEntry(key, val);
+
+    mDirty = true;
+
+    mLock.unlock();
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorage::WriteValueBin(const char * key, const uint8_t * data, size_t dataLen)
+{
+    static const size_t kMaxBlobSize = 5 * 1024;
+
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+    chip::Platform::ScopedMemoryBuffer<char> encodedData;
+    size_t encodedDataLen     = 0;
+    size_t expectedEncodedLen = ((dataLen + 3) * 4) / 3;
+
+    // We only support encoding blobs up to 5kb
+    if (dataLen > kMaxBlobSize)
+    {
+        retval = CHIP_ERROR_INVALID_ARGUMENT;
+    }
+
+    // Compute our expectedEncodedLen
+    // Allocate just enough space for the encoded data, and the NULL terminator
+    if (retval == CHIP_NO_ERROR)
+    {
+        if (!encodedData.Alloc(expectedEncodedLen + 1))
+        {
+            retval = CHIP_ERROR_NO_MEMORY;
+        }
+    }
+
+    // Encode it
+    if (retval == CHIP_NO_ERROR)
+    {
+        // We tested above that dataLen is no more than kMaxBlobSize.
+        static_assert(kMaxBlobSize < UINT16_MAX, "dataLen won't fit");
+        encodedDataLen              = Base64Encode(data, static_cast<uint16_t>(dataLen), encodedData.Get());
+        encodedData[encodedDataLen] = 0;
+    }
+
+    // Store it
+    if (retval == CHIP_NO_ERROR)
+    {
+        WriteValueStr(key, encodedData.Get());
+    }
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorage::ClearValue(const char * key)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+
+    mLock.lock();
+
+    retval = ChipLinuxStorageIni::RemoveEntry(key);
+
+    if (retval == CHIP_NO_ERROR)
+    {
+        mDirty = true;
+    }
+    else
+    {
+        retval = CHIP_ERROR_KEY_NOT_FOUND;
+    }
+
+    mLock.unlock();
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorage::ClearAll()
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+
+    mLock.lock();
+
+    retval = ChipLinuxStorageIni::RemoveAll();
+
+    mLock.unlock();
+
+    if (retval == CHIP_NO_ERROR)
+    {
+        mDirty = true;
+        retval = Commit();
+    }
+    else
+    {
+        retval = CHIP_ERROR_WRITE_FAILED;
+    }
+
+    return retval;
+}
+
+bool ChipLinuxStorage::HasValue(const char * key)
+{
+    bool retval;
+
+    mLock.lock();
+
+    retval = ChipLinuxStorageIni::HasValue(key);
+
+    mLock.unlock();
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorage::Commit()
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+
+    if (mDirty && !mConfigPath.empty())
+    {
+        mLock.lock();
+
+        retval = ChipLinuxStorageIni::CommitConfig(mConfigPath);
+
+        mLock.unlock();
+    }
+    else
+    {
+        retval = CHIP_ERROR_WRITE_FAILED;
+    }
+
+    return retval;
+}
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/CHIPLinuxStorage.h b/src/platform/Tizen/CHIPLinuxStorage.h
new file mode 100644 (file)
index 0000000..e79282a
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ *
+ *    Copyright (c) 2020 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *         This file defines a class for managing client application
+ *         user-editable settings. CHIP settings are partitioned into two
+ *         distinct areas:
+ *
+ *         1. immutable / durable: factory parameters (CHIP_DEFAULT_FACTORY_PATH)
+ *         2. mutable / ephemeral: user parameters (CHIP_DEFAULT_CONFIG_PATH/CHIP_DEFAULT_DATA_PATH)
+ *
+ *         The ephemeral partition should be erased during factory reset.
+ *
+ *         ChipLinuxStorage wraps the storage class ChipLinuxStorageIni with mutex.
+ *
+ */
+
+#pragma once
+
+#include <mutex>
+#include <platform/Linux/CHIPLinuxStorageIni.h>
+
+#ifndef FATCONFDIR
+#define FATCONFDIR "/tmp"
+#endif
+
+#ifndef SYSCONFDIR
+#define SYSCONFDIR "/tmp"
+#endif
+
+#ifndef LOCALSTATEDIR
+#define LOCALSTATEDIR "/tmp"
+#endif
+
+#define CHIP_DEFAULT_FACTORY_PATH                                                                                                  \
+    FATCONFDIR "/"                                                                                                                 \
+               "chip_factory.ini"
+#define CHIP_DEFAULT_CONFIG_PATH                                                                                                   \
+    SYSCONFDIR "/"                                                                                                                 \
+               "chip_config.ini"
+#define CHIP_DEFAULT_DATA_PATH                                                                                                     \
+    LOCALSTATEDIR "/"                                                                                                              \
+                  "chip_counters.ini"
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+class ChipLinuxStorage : private ChipLinuxStorageIni
+{
+public:
+    ChipLinuxStorage();
+    ~ChipLinuxStorage();
+
+    CHIP_ERROR Init(const char * configFile);
+    CHIP_ERROR ReadValue(const char * key, bool & val);
+    CHIP_ERROR ReadValue(const char * key, uint32_t & val);
+    CHIP_ERROR ReadValue(const char * key, uint64_t & val);
+    CHIP_ERROR ReadValueStr(const char * key, char * buf, size_t bufSize, size_t & outLen);
+    CHIP_ERROR ReadValueBin(const char * key, uint8_t * buf, size_t bufSize, size_t & outLen);
+    CHIP_ERROR WriteValue(const char * key, bool val);
+    CHIP_ERROR WriteValue(const char * key, uint32_t val);
+    CHIP_ERROR WriteValue(const char * key, uint64_t val);
+    CHIP_ERROR WriteValueStr(const char * key, const char * val);
+    CHIP_ERROR WriteValueBin(const char * key, const uint8_t * data, size_t dataLen);
+    CHIP_ERROR ClearValue(const char * key);
+    CHIP_ERROR ClearAll();
+    CHIP_ERROR Commit();
+    bool HasValue(const char * key);
+
+private:
+    std::mutex mLock;
+    bool mDirty;
+    std::string mConfigPath;
+};
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/CHIPLinuxStorageIni.cpp b/src/platform/Tizen/CHIPLinuxStorageIni.cpp
new file mode 100644 (file)
index 0000000..0f9fc2a
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ *
+ *    Copyright (c) 2020 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *          Provides an implementation of the Configuration key-value store object
+ *          using IniPP on Linux platform.
+ *
+ */
+
+#include <fstream>
+#include <string>
+#include <unistd.h>
+
+#include <platform/Linux/CHIPLinuxStorageIni.h>
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+#include <support/Base64.h>
+#include <support/CHIPMem.h>
+#include <support/CodeUtils.h>
+#include <support/logging/CHIPLogging.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+CHIP_ERROR ChipLinuxStorageIni::Init()
+{
+    return RemoveAll();
+}
+
+CHIP_ERROR ChipLinuxStorageIni::GetDefaultSection(std::map<std::string, std::string> & section)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+
+    auto it = mConfigStore.sections.find("DEFAULT");
+
+    if (it != mConfigStore.sections.end())
+    {
+        section = mConfigStore.sections["DEFAULT"];
+    }
+    else
+    {
+        retval = CHIP_ERROR_KEY_NOT_FOUND;
+    }
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorageIni::AddConfig(const std::string & configFile)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+    std::ifstream ifs;
+
+    ifs.open(configFile, std::ifstream::in);
+
+    if (ifs.is_open())
+    {
+        mConfigStore.parse(ifs);
+        ifs.close();
+    }
+    else
+    {
+        ChipLogError(DeviceLayer, "Failed to open config file: %s", configFile.c_str());
+        retval = CHIP_ERROR_OPEN_FAILED;
+    }
+
+    return retval;
+}
+
+// Updating a file atomically and durably on Linux requires:
+// 1. Writing to a temporary file
+// 2. Sync'ing the temp file to commit updated data
+// 3. Using rename() to overwrite the existing file
+CHIP_ERROR ChipLinuxStorageIni::CommitConfig(const std::string & configFile)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+    std::ofstream ofs;
+    std::string tmpPath = configFile;
+
+    tmpPath.append(".tmp");
+
+    ofs.open(tmpPath, std::ofstream::out | std::ofstream::trunc);
+
+    if (ofs.is_open())
+    {
+        ChipLogProgress(DeviceLayer, "writing settings to file (%s)", tmpPath.c_str());
+
+        mConfigStore.generate(ofs);
+        ofs.close();
+
+        if (rename(tmpPath.c_str(), configFile.c_str()) == 0)
+        {
+            ChipLogError(DeviceLayer, "renamed tmp file to file (%s)", configFile.c_str());
+        }
+        else
+        {
+            ChipLogError(DeviceLayer, "failed to rename (%s), %s (%d)", tmpPath.c_str(), strerror(errno), errno);
+            retval = CHIP_ERROR_WRITE_FAILED;
+        }
+    }
+    else
+    {
+        ChipLogError(DeviceLayer, "failed to open file (%s) for writing", tmpPath.c_str());
+        retval = CHIP_ERROR_OPEN_FAILED;
+    }
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorageIni::GetUIntValue(const char * key, uint32_t & val)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+    std::map<std::string, std::string> section;
+
+    retval = GetDefaultSection(section);
+
+    if (retval == CHIP_NO_ERROR)
+    {
+        auto it = section.find(key);
+
+        if (it != section.end())
+        {
+            if (!inipp::extract(section[key], val))
+            {
+                retval = CHIP_ERROR_INVALID_ARGUMENT;
+            }
+        }
+        else
+        {
+            retval = CHIP_ERROR_KEY_NOT_FOUND;
+        }
+    }
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorageIni::GetUInt64Value(const char * key, uint64_t & val)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+    std::map<std::string, std::string> section;
+
+    retval = GetDefaultSection(section);
+
+    if (retval == CHIP_NO_ERROR)
+    {
+        auto it = section.find(key);
+
+        if (it != section.end())
+        {
+            if (!inipp::extract(section[key], val))
+            {
+                retval = CHIP_ERROR_INVALID_ARGUMENT;
+            }
+        }
+        else
+        {
+            retval = CHIP_ERROR_KEY_NOT_FOUND;
+        }
+    }
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorageIni::GetStringValue(const char * key, char * buf, size_t bufSize, size_t & outLen)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+    std::map<std::string, std::string> section;
+
+    retval = GetDefaultSection(section);
+
+    if (retval == CHIP_NO_ERROR)
+    {
+        auto it = section.find(key);
+
+        if (it != section.end())
+        {
+            std::string value;
+            if (inipp::extract(section[key], value))
+            {
+                size_t len = value.size();
+
+                if (len > bufSize - 1)
+                {
+                    outLen = len;
+                    retval = CHIP_ERROR_BUFFER_TOO_SMALL;
+                }
+                else
+                {
+                    outLen      = value.copy(buf, len);
+                    buf[outLen] = '\0';
+                }
+            }
+            else
+            {
+                retval = CHIP_ERROR_INVALID_ARGUMENT;
+            }
+        }
+        else
+        {
+            retval = CHIP_ERROR_KEY_NOT_FOUND;
+        }
+    }
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorageIni::GetBinaryBlobDataAndLengths(const char * key,
+                                                            chip::Platform::ScopedMemoryBuffer<char> & encodedData,
+                                                            size_t & encodedDataLen, size_t & decodedDataLen)
+{
+    size_t encodedDataPaddingLen = 0;
+    std::map<std::string, std::string> section;
+    CHIP_ERROR err = GetDefaultSection(section);
+    if (err != CHIP_NO_ERROR)
+    {
+        return err;
+    }
+
+    auto it = section.find(key);
+    if (it == section.end())
+    {
+        return CHIP_ERROR_KEY_NOT_FOUND;
+    }
+
+    std::string value;
+
+    // Compute the expectedDecodedLen
+    if (!inipp::extract(section[key], value))
+    {
+        return CHIP_ERROR_INVALID_ARGUMENT;
+    }
+
+    size_t len = value.size();
+    if (!encodedData.Alloc(len + 1))
+    {
+        return CHIP_ERROR_NO_MEMORY;
+    }
+    encodedDataLen              = value.copy(encodedData.Get(), len);
+    encodedData[encodedDataLen] = '\0';
+
+    // Check if encoded data was padded. Only "=" or "==" padding combinations are allowed.
+    if ((encodedDataLen > 0) && (encodedData[encodedDataLen - 1] == '='))
+    {
+        encodedDataPaddingLen++;
+        if ((encodedDataLen > 1) && (encodedData[encodedDataLen - 2] == '='))
+            encodedDataPaddingLen++;
+    }
+
+    decodedDataLen = ((encodedDataLen - encodedDataPaddingLen) * 3) / 4;
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR ChipLinuxStorageIni::GetBinaryBlobValue(const char * key, uint8_t * decodedData, size_t bufSize, size_t & decodedDataLen)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+    chip::Platform::ScopedMemoryBuffer<char> encodedData;
+    size_t encodedDataLen;
+    size_t expectedDecodedLen = 0;
+
+    retval = GetBinaryBlobDataAndLengths(key, encodedData, encodedDataLen, expectedDecodedLen);
+
+    // Check the size
+    if (retval != CHIP_NO_ERROR)
+    {
+        return retval;
+    }
+
+    if (expectedDecodedLen > bufSize)
+    {
+        decodedDataLen = expectedDecodedLen;
+        return CHIP_ERROR_BUFFER_TOO_SMALL;
+    }
+
+    if (encodedDataLen > UINT16_MAX)
+    {
+        // We can't even pass this length into Base64Decode.
+        return CHIP_ERROR_DECODE_FAILED;
+    }
+
+    // Decode it
+    // Cast is safe because we checked encodedDataLen above.
+    decodedDataLen = Base64Decode(encodedData.Get(), static_cast<uint16_t>(encodedDataLen), decodedData);
+    if (decodedDataLen == UINT16_MAX || decodedDataLen > expectedDecodedLen)
+    {
+        return CHIP_ERROR_DECODE_FAILED;
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+bool ChipLinuxStorageIni::HasValue(const char * key)
+{
+    std::map<std::string, std::string> section;
+
+    if (GetDefaultSection(section) != CHIP_NO_ERROR)
+        return false;
+
+    auto it = section.find(key);
+
+    return it != section.end();
+}
+
+CHIP_ERROR ChipLinuxStorageIni::AddEntry(const char * key, const char * value)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+
+    if ((key != nullptr) && (value != nullptr))
+    {
+        std::map<std::string, std::string> & section = mConfigStore.sections["DEFAULT"];
+        section[key]                                 = std::string(value);
+    }
+    else
+    {
+        ChipLogError(DeviceLayer, "Invalid input argument, failed to add entry");
+        retval = CHIP_ERROR_INVALID_ARGUMENT;
+    }
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorageIni::RemoveEntry(const char * key)
+{
+    CHIP_ERROR retval = CHIP_NO_ERROR;
+
+    std::map<std::string, std::string> & section = mConfigStore.sections["DEFAULT"];
+
+    auto it = section.find(key);
+
+    if (it != section.end())
+    {
+        section.erase(it);
+    }
+    else
+    {
+        retval = CHIP_ERROR_KEY_NOT_FOUND;
+    }
+
+    return retval;
+}
+
+CHIP_ERROR ChipLinuxStorageIni::RemoveAll()
+{
+    mConfigStore.clear();
+
+    return CHIP_NO_ERROR;
+}
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/CHIPLinuxStorageIni.h b/src/platform/Tizen/CHIPLinuxStorageIni.h
new file mode 100644 (file)
index 0000000..240d74c
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *
+ *    Copyright (c) 2020 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *          Provides an implementation of the Configuration key-value store interface
+ *          using IniPP.
+ *
+ */
+
+#pragma once
+
+#include <inipp/inipp.h>
+#include <platform/PersistedStorage.h>
+#include <support/ScopedBuffer.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+class ChipLinuxStorageIni
+{
+public:
+    CHIP_ERROR Init();
+    CHIP_ERROR AddConfig(const std::string & configFile);
+    CHIP_ERROR CommitConfig(const std::string & configFile);
+    CHIP_ERROR GetUIntValue(const char * key, uint32_t & val);
+    CHIP_ERROR GetUInt64Value(const char * key, uint64_t & val);
+    CHIP_ERROR GetStringValue(const char * key, char * buf, size_t bufSize, size_t & outLen);
+    CHIP_ERROR GetBinaryBlobValue(const char * key, uint8_t * decodedData, size_t bufSize, size_t & decodedDataLen);
+    bool HasValue(const char * key);
+
+protected:
+    CHIP_ERROR AddEntry(const char * key, const char * value);
+    CHIP_ERROR RemoveEntry(const char * key);
+    CHIP_ERROR RemoveAll();
+
+private:
+    CHIP_ERROR GetDefaultSection(std::map<std::string, std::string> & section);
+    CHIP_ERROR GetBinaryBlobDataAndLengths(const char * key, chip::Platform::ScopedMemoryBuffer<char> & encodedData,
+                                           size_t & encodedDataLen, size_t & decodedDataLen);
+    inipp::Ini<char> mConfigStore;
+};
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/CHIPPlatformConfig.h b/src/platform/Tizen/CHIPPlatformConfig.h
new file mode 100644 (file)
index 0000000..e5436ae
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *
+ *    Copyright (c) 2020 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.
+ */
+
+/**
+ *    @file
+ *          Platform-specific configuration overrides for CHIP on
+ *          Linux platforms.
+ */
+
+#pragma once
+
+// ==================== General Platform Adaptations ====================
+
+#define ChipDie() abort()
+
+// TODO:(#756) Add FabricState support
+#define CHIP_CONFIG_ENABLE_FABRIC_STATE 0
+
+using CHIP_CONFIG_PERSISTED_STORAGE_KEY_TYPE = const char *;
+#define CHIP_CONFIG_PERSISTED_STORAGE_MAX_KEY_LENGTH 16
+
+#define CHIP_CONFIG_LIFETIIME_PERSISTED_COUNTER_KEY "life-count"
+
+#define CHIP_CONFIG_TIME_ENABLE_CLIENT 1
+#define CHIP_CONFIG_TIME_ENABLE_SERVER 0
+
+// ==================== Security Adaptations ====================
+
+#define CHIP_CONFIG_USE_OPENSSL_ECC 0
+#define CHIP_CONFIG_USE_MICRO_ECC 0
+
+#define CHIP_CONFIG_HASH_IMPLEMENTATION_OPENSSL 0
+#define CHIP_CONFIG_HASH_IMPLEMENTATION_MINCRYPT 1
+#define CHIP_CONFIG_HASH_IMPLEMENTATION_MBEDTLS 0
+#define CHIP_CONFIG_HASH_IMPLEMENTATION_PLATFORM 0
+
+#define CHIP_CONFIG_AES_IMPLEMENTATION_OPENSSL 0
+#define CHIP_CONFIG_AES_IMPLEMENTATION_AESNI 0
+#define CHIP_CONFIG_AES_IMPLEMENTATION_MBEDTLS 1
+#define CHIP_CONFIG_AES_IMPLEMENTATION_PLATFORM 0
+
+#define CHIP_CONFIG_RNG_IMPLEMENTATION_OPENSSL 0
+#define CHIP_CONFIG_RNG_IMPLEMENTATION_CHIPDRBG 1
+#define CHIP_CONFIG_RNG_IMPLEMENTATION_PLATFORM 0
+
+#define CHIP_CONFIG_ENABLE_PASE_INITIATOR 0
+#define CHIP_CONFIG_ENABLE_PASE_RESPONDER 1
+#define CHIP_CONFIG_ENABLE_CASE_INITIATOR 1
+
+#define CHIP_CONFIG_SUPPORT_PASE_CONFIG0 0
+#define CHIP_CONFIG_SUPPORT_PASE_CONFIG1 0
+#define CHIP_CONFIG_SUPPORT_PASE_CONFIG2 0
+#define CHIP_CONFIG_SUPPORT_PASE_CONFIG3 0
+#define CHIP_CONFIG_SUPPORT_PASE_CONFIG4 1
+
+#define CHIP_CONFIG_ENABLE_KEY_EXPORT_INITIATOR 0
+
+#define CHIP_CONFIG_ENABLE_PROVISIONING_BUNDLE_SUPPORT 0
+
+// ==================== General Configuration Overrides ====================
+
+#ifndef CHIP_CONFIG_MAX_PEER_NODES
+#define CHIP_CONFIG_MAX_PEER_NODES 16
+#endif // CHIP_CONFIG_MAX_PEER_NODES
+
+#ifndef CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS
+#define CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS 16
+#endif // CHIP_CONFIG_MAX_UNSOLICITED_MESSAGE_HANDLERS
+
+#ifndef CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS
+#define CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS 8
+#endif // CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS
+
+#ifndef CHIP_CONFIG_RMP_TIMER_DEFAULT_PERIOD_SHIFT
+#define CHIP_CONFIG_RMP_TIMER_DEFAULT_PERIOD_SHIFT 6
+#endif // CHIP_CONFIG_RMP_TIMER_DEFAULT_PERIOD_SHIFT
+
+#ifndef CHIP_LOG_FILTERING
+#define CHIP_LOG_FILTERING 0
+#endif // CHIP_LOG_FILTERING
+
+#ifndef CHIP_CONFIG_BDX_MAX_NUM_TRANSFERS
+#define CHIP_CONFIG_BDX_MAX_NUM_TRANSFERS 1
+#endif // CHIP_CONFIG_BDX_MAX_NUM_TRANSFERS
+
+// ==================== Security Configuration Overrides ====================
+
+#ifndef CHIP_CONFIG_MAX_APPLICATION_GROUPS
+#define CHIP_CONFIG_MAX_APPLICATION_GROUPS 4
+#endif // CHIP_CONFIG_MAX_APPLICATION_GROUPS
+
+#ifndef CHIP_CONFIG_DEBUG_CERT_VALIDATION
+#define CHIP_CONFIG_DEBUG_CERT_VALIDATION 0
+#endif // CHIP_CONFIG_DEBUG_CERT_VALIDATION
+
+#ifndef CHIP_CONFIG_ENABLE_CASE_RESPONDER
+#define CHIP_CONFIG_ENABLE_CASE_RESPONDER 1
+#endif // CHIP_CONFIG_ENABLE_CASE_RESPONDER
diff --git a/src/platform/Tizen/ConfigurationManagerImpl.cpp b/src/platform/Tizen/ConfigurationManagerImpl.cpp
new file mode 100644 (file)
index 0000000..57090c6
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ *
+ *    Copyright (c) 2020 Project CHIP Authors
+ *    Copyright (c) 2018 Nest Labs, Inc.
+ *    All rights reserved.
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *          Provides the implementation of the Device Layer ConfigurationManager object
+ *          for Linux platforms.
+ */
+
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+
+#include <ifaddrs.h>
+#include <netpacket/packet.h>
+
+#include <core/CHIPVendorIdentifiers.hpp>
+#include <platform/ConfigurationManager.h>
+#include <platform/Linux/PosixConfig.h>
+#include <platform/internal/GenericConfigurationManagerImpl.cpp>
+#include <support/CodeUtils.h>
+#include <support/logging/CHIPLogging.h>
+
+namespace chip {
+namespace DeviceLayer {
+
+using namespace ::chip::DeviceLayer::Internal;
+
+/** Singleton instance of the ConfigurationManager implementation object.
+ */
+ConfigurationManagerImpl ConfigurationManagerImpl::sInstance;
+
+CHIP_ERROR ConfigurationManagerImpl::_Init()
+{
+    CHIP_ERROR err;
+    bool failSafeArmed;
+
+    // Force initialization of NVS namespaces if they doesn't already exist.
+    err = EnsureNamespace(kConfigNamespace_ChipFactory);
+    SuccessOrExit(err);
+    err = EnsureNamespace(kConfigNamespace_ChipConfig);
+    SuccessOrExit(err);
+    err = EnsureNamespace(kConfigNamespace_ChipCounters);
+    SuccessOrExit(err);
+
+    // Initialize the generic implementation base class.
+    err = Internal::GenericConfigurationManagerImpl<ConfigurationManagerImpl>::_Init();
+    SuccessOrExit(err);
+
+    // If the fail-safe was armed when the device last shutdown, initiate a factory reset.
+    if (_GetFailSafeArmed(failSafeArmed) == CHIP_NO_ERROR && failSafeArmed)
+    {
+        ChipLogProgress(DeviceLayer, "Detected fail-safe armed on reboot; initiating factory reset");
+        _InitiateFactoryReset();
+    }
+
+    err = CHIP_NO_ERROR;
+
+exit:
+    return err;
+}
+
+CHIP_ERROR ConfigurationManagerImpl::_GetPrimaryWiFiMACAddress(uint8_t * buf)
+{
+    struct ifaddrs * addresses = NULL;
+    CHIP_ERROR error           = CHIP_NO_ERROR;
+    bool found                 = false;
+
+    VerifyOrExit(getifaddrs(&addresses) == 0, error = CHIP_ERROR_INTERNAL);
+    for (auto addr = addresses; addr != NULL; addr = addr->ifa_next)
+    {
+        if ((addr->ifa_addr) && (addr->ifa_addr->sa_family == AF_PACKET) && strncmp(addr->ifa_name, "lo", IFNAMSIZ) != 0)
+        {
+            struct sockaddr_ll * mac = (struct sockaddr_ll *) addr->ifa_addr;
+            memcpy(buf, mac->sll_addr, mac->sll_halen);
+            found = true;
+            break;
+        }
+    }
+    freeifaddrs(addresses);
+    if (!found)
+    {
+        error = CHIP_ERROR_NO_ENDPOINT;
+    }
+
+exit:
+    return error;
+}
+
+bool ConfigurationManagerImpl::_CanFactoryReset()
+{
+    // TODO(#742): query the application to determine if factory reset is allowed.
+    return true;
+}
+
+void ConfigurationManagerImpl::_InitiateFactoryReset()
+{
+    PlatformMgr().ScheduleWork(DoFactoryReset);
+}
+
+CHIP_ERROR ConfigurationManagerImpl::_ReadPersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t & value)
+{
+    PosixConfig::Key configKey{ kConfigNamespace_ChipCounters, key };
+
+    CHIP_ERROR err = ReadConfigValue(configKey, value);
+    if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND)
+    {
+        err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND;
+    }
+    return err;
+}
+
+CHIP_ERROR ConfigurationManagerImpl::_WritePersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t value)
+{
+    PosixConfig::Key configKey{ kConfigNamespace_ChipCounters, key };
+    return WriteConfigValue(configKey, value);
+}
+
+#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION
+CHIP_ERROR ConfigurationManagerImpl::GetWiFiStationSecurityType(Profiles::NetworkProvisioning::WiFiSecurityType & secType)
+{
+    CHIP_ERROR err;
+    uint32_t secTypeInt;
+
+    err = ReadConfigValue(kConfigKey_WiFiStationSecType, secTypeInt);
+    if (err == CHIP_NO_ERROR)
+    {
+        secType = (Profiles::NetworkProvisioning::WiFiSecurityType) secTypeInt;
+    }
+    return err;
+}
+
+CHIP_ERROR ConfigurationManagerImpl::UpdateWiFiStationSecurityType(Profiles::NetworkProvisioning::WiFiSecurityType secType)
+{
+    CHIP_ERROR err;
+    Profiles::NetworkProvisioning::WiFiSecurityType curSecType;
+
+    if (secType != Profiles::NetworkProvisioning::kWiFiSecurityType_NotSpecified)
+    {
+        err = GetWiFiStationSecurityType(curSecType);
+        if (err == CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND || (err == CHIP_NO_ERROR && secType != curSecType))
+        {
+            uint32_t secTypeInt = secType;
+            err                 = WriteConfigValue(kConfigKey_WiFiStationSecType, secTypeInt);
+        }
+        SuccessOrExit(err);
+    }
+    else
+    {
+        err = ClearConfigValue(kConfigKey_WiFiStationSecType);
+        SuccessOrExit(err);
+    }
+
+exit:
+    return err;
+}
+#endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION
+
+void ConfigurationManagerImpl::DoFactoryReset(intptr_t arg)
+{
+    CHIP_ERROR err;
+
+    ChipLogProgress(DeviceLayer, "Performing factory reset");
+
+    err = FactoryResetConfig();
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(DeviceLayer, "FactoryResetConfig() failed: %s", ErrorStr(err));
+    }
+
+#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
+
+    ChipLogProgress(DeviceLayer, "Clearing Thread provision");
+    ThreadStackMgr().ErasePersistentInfo();
+
+#endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD
+
+    // Restart the system.
+    ChipLogProgress(DeviceLayer, "System restarting (not implemented)");
+    // TODO(#742): restart CHIP exe
+}
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/ConfigurationManagerImpl.h b/src/platform/Tizen/ConfigurationManagerImpl.h
new file mode 100644 (file)
index 0000000..7a717ea
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *
+ *    Copyright (c) 2020 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.
+ */
+
+/**
+ *    @file
+ *          Provides an implementation of the ConfigurationManager object
+ *          for Linux platforms.
+ */
+
+#pragma once
+
+#include <platform/internal/GenericConfigurationManagerImpl.h>
+
+#include <platform/Linux/PosixConfig.h>
+
+namespace chip {
+namespace DeviceLayer {
+
+/**
+ * Concrete implementation of the ConfigurationManager singleton object for the Linux platform.
+ */
+class ConfigurationManagerImpl final : public ConfigurationManager,
+                                       public Internal::GenericConfigurationManagerImpl<ConfigurationManagerImpl>,
+                                       private Internal::PosixConfig
+{
+    // Allow the ConfigurationManager interface class to delegate method calls to
+    // the implementation methods provided by this class.
+    friend class ConfigurationManager;
+
+    // Allow the GenericConfigurationManagerImpl base class to access helper methods and types
+    // defined on this class.
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+    friend class Internal::GenericConfigurationManagerImpl<ConfigurationManagerImpl>;
+#endif
+
+private:
+    // ===== Members that implement the ConfigurationManager public interface.
+
+    CHIP_ERROR _Init();
+    CHIP_ERROR _GetPrimaryWiFiMACAddress(uint8_t * buf);
+    bool _CanFactoryReset();
+    void _InitiateFactoryReset();
+    CHIP_ERROR _ReadPersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t & value);
+    CHIP_ERROR _WritePersistedStorageValue(::chip::Platform::PersistedStorage::Key key, uint32_t value);
+
+    // NOTE: Other public interface methods are implemented by GenericConfigurationManagerImpl<>.
+
+    // ===== Members for internal use by the following friends.
+
+    friend ConfigurationManager & ConfigurationMgr();
+    friend ConfigurationManagerImpl & ConfigurationMgrImpl();
+
+    static ConfigurationManagerImpl sInstance;
+
+    // ===== Private members reserved for use by this class only.
+
+    static void DoFactoryReset(intptr_t arg);
+};
+
+/**
+ * Returns the public interface of the ConfigurationManager singleton object.
+ *
+ * chip applications should use this to access features of the ConfigurationManager object
+ * that are common to all platforms.
+ */
+inline ConfigurationManager & ConfigurationMgr()
+{
+    return ConfigurationManagerImpl::sInstance;
+}
+
+/**
+ * Returns the platform-specific implementation of the ConfigurationManager singleton object.
+ *
+ * chip applications can use this to gain access to features of the ConfigurationManager
+ * that are specific to the ESP32 platform.
+ */
+inline ConfigurationManagerImpl & ConfigurationMgrImpl()
+{
+    return ConfigurationManagerImpl::sInstance;
+}
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/ConnectivityManagerImpl.cpp b/src/platform/Tizen/ConnectivityManagerImpl.cpp
new file mode 100644 (file)
index 0000000..f73e0dc
--- /dev/null
@@ -0,0 +1,992 @@
+/*
+ *
+ *    Copyright (c) 2020-2021 Project CHIP Authors
+ *    Copyright (c) 2019 Nest Labs, Inc.
+ *
+ *    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 <platform/internal/CHIPDeviceLayerInternal.h>
+
+#include <platform/ConnectivityManager.h>
+#include <platform/internal/BLEManager.h>
+
+#include <cstdlib>
+#include <new>
+
+#include <support/CodeUtils.h>
+#include <support/logging/CHIPLogging.h>
+
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+#include <platform/internal/GenericConnectivityManagerImpl_BLE.cpp>
+#endif
+
+#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
+#include <platform/internal/GenericConnectivityManagerImpl_Thread.cpp>
+#endif
+
+#if CHIP_DEVICE_CONFIG_ENABLE_WPA
+#include <platform/internal/GenericConnectivityManagerImpl_WiFi.cpp>
+#endif
+
+using namespace ::chip;
+using namespace ::chip::TLV;
+using namespace ::chip::DeviceLayer::Internal;
+
+#if CHIP_DEVICE_CONFIG_ENABLE_WPA
+namespace {
+const char kWpaSupplicantServiceName[] = "fi.w1.wpa_supplicant1";
+const char kWpaSupplicantObjectPath[]  = "/fi/w1/wpa_supplicant1";
+
+constexpr uint16_t kWiFi_BAND_2_4_GHZ = 2400;
+constexpr uint16_t kWiFi_BAND_5_0_GHZ = 5000;
+
+uint16_t Map2400MHz(const uint8_t inChannel)
+{
+    uint16_t frequency = 0;
+
+    if (inChannel >= 1 && inChannel <= 13)
+    {
+        frequency = static_cast<uint16_t>(2412 + ((inChannel - 1) * 5));
+    }
+    else if (inChannel == 14)
+    {
+        frequency = 2484;
+    }
+
+    return frequency;
+}
+
+uint16_t Map5000MHz(const uint8_t inChannel)
+{
+    uint16_t frequency = 0;
+
+    switch (inChannel)
+    {
+
+    case 183:
+        frequency = 4915;
+        break;
+    case 184:
+        frequency = 4920;
+        break;
+    case 185:
+        frequency = 4925;
+        break;
+    case 187:
+        frequency = 4935;
+        break;
+    case 188:
+        frequency = 4940;
+        break;
+    case 189:
+        frequency = 4945;
+        break;
+    case 192:
+        frequency = 4960;
+        break;
+    case 196:
+        frequency = 4980;
+        break;
+    case 7:
+        frequency = 5035;
+        break;
+    case 8:
+        frequency = 5040;
+        break;
+    case 9:
+        frequency = 5045;
+        break;
+    case 11:
+        frequency = 5055;
+        break;
+    case 12:
+        frequency = 5060;
+        break;
+    case 16:
+        frequency = 5080;
+        break;
+    case 34:
+        frequency = 5170;
+        break;
+    case 36:
+        frequency = 5180;
+        break;
+    case 38:
+        frequency = 5190;
+        break;
+    case 40:
+        frequency = 5200;
+        break;
+    case 42:
+        frequency = 5210;
+        break;
+    case 44:
+        frequency = 5220;
+        break;
+    case 46:
+        frequency = 5230;
+        break;
+    case 48:
+        frequency = 5240;
+        break;
+    case 52:
+        frequency = 5260;
+        break;
+    case 56:
+        frequency = 5280;
+        break;
+    case 60:
+        frequency = 5300;
+        break;
+    case 64:
+        frequency = 5320;
+        break;
+    case 100:
+        frequency = 5500;
+        break;
+    case 104:
+        frequency = 5520;
+        break;
+    case 108:
+        frequency = 5540;
+        break;
+    case 112:
+        frequency = 5560;
+        break;
+    case 116:
+        frequency = 5580;
+        break;
+    case 120:
+        frequency = 5600;
+        break;
+    case 124:
+        frequency = 5620;
+        break;
+    case 128:
+        frequency = 5640;
+        break;
+    case 132:
+        frequency = 5660;
+        break;
+    case 136:
+        frequency = 5680;
+        break;
+    case 140:
+        frequency = 5700;
+        break;
+    case 149:
+        frequency = 5745;
+        break;
+    case 153:
+        frequency = 5765;
+        break;
+    case 157:
+        frequency = 5785;
+        break;
+    case 161:
+        frequency = 5805;
+        break;
+    case 165:
+        frequency = 5825;
+        break;
+    }
+
+    return frequency;
+}
+
+static uint16_t MapFrequency(const uint16_t inBand, const uint8_t inChannel)
+{
+    uint16_t frequency = 0;
+
+    if (inBand == kWiFi_BAND_2_4_GHZ)
+    {
+        frequency = Map2400MHz(inChannel);
+    }
+    else if (inBand == kWiFi_BAND_5_0_GHZ)
+    {
+        frequency = Map5000MHz(inChannel);
+    }
+
+    return frequency;
+}
+} // namespace
+#endif
+
+namespace chip {
+namespace DeviceLayer {
+
+ConnectivityManagerImpl ConnectivityManagerImpl::sInstance;
+
+CHIP_ERROR ConnectivityManagerImpl::_Init()
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    mWiFiStationMode                = kWiFiStationMode_Disabled;
+    mWiFiStationReconnectIntervalMS = CHIP_DEVICE_CONFIG_WIFI_STATION_RECONNECT_INTERVAL;
+
+    // Initialize the generic base classes that require it.
+#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
+    GenericConnectivityManagerImpl_Thread<ConnectivityManagerImpl>::_Init();
+#endif
+
+    SuccessOrExit(err);
+
+exit:
+    return err;
+}
+
+void ConnectivityManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
+{
+    // Forward the event to the generic base classes as needed.
+#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
+    GenericConnectivityManagerImpl_Thread<ConnectivityManagerImpl>::_OnPlatformEvent(event);
+#endif
+}
+
+#if CHIP_DEVICE_CONFIG_ENABLE_WPA
+
+BitFlags<Internal::GenericConnectivityManagerImpl_WiFi<ConnectivityManagerImpl>::ConnectivityFlags>
+    ConnectivityManagerImpl::mConnectivityFlag;
+struct GDBusWpaSupplicant ConnectivityManagerImpl::mWpaSupplicant;
+
+bool ConnectivityManagerImpl::_HaveIPv4InternetConnectivity()
+{
+    return mConnectivityFlag.Has(ConnectivityFlags::kHaveIPv4InternetConnectivity);
+}
+
+bool ConnectivityManagerImpl::_HaveIPv6InternetConnectivity()
+{
+    return mConnectivityFlag.Has(ConnectivityFlags::kHaveIPv6InternetConnectivity);
+}
+
+ConnectivityManager::WiFiStationMode ConnectivityManagerImpl::_GetWiFiStationMode()
+{
+    if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled)
+    {
+        mWiFiStationMode = (mWpaSupplicant.iface != nullptr) ? kWiFiStationMode_Enabled : kWiFiStationMode_Disabled;
+    }
+
+    return mWiFiStationMode;
+}
+
+CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationMode(ConnectivityManager::WiFiStationMode val)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    VerifyOrExit(val != ConnectivityManager::kWiFiStationMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
+
+    if (mWiFiStationMode != val)
+    {
+        ChipLogProgress(DeviceLayer, "WiFi station mode change: %s -> %s", WiFiStationModeToStr(mWiFiStationMode),
+                        WiFiStationModeToStr(val));
+    }
+
+    mWiFiStationMode = val;
+exit:
+    return err;
+}
+
+uint32_t ConnectivityManagerImpl::_GetWiFiStationReconnectIntervalMS()
+{
+    return mWiFiStationReconnectIntervalMS;
+}
+
+CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationReconnectIntervalMS(uint32_t val)
+{
+    mWiFiStationReconnectIntervalMS = val;
+
+    return CHIP_NO_ERROR;
+}
+
+bool ConnectivityManagerImpl::_IsWiFiStationEnabled()
+{
+    return GetWiFiStationMode() == kWiFiStationMode_Enabled;
+}
+
+bool ConnectivityManagerImpl::_IsWiFiStationConnected()
+{
+    bool ret            = false;
+    const gchar * state = nullptr;
+
+    if (mWpaSupplicant.state != GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED)
+    {
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: _IsWiFiStationConnected: interface not connected");
+        return false;
+    }
+
+    state = wpa_fi_w1_wpa_supplicant1_interface_get_state(mWpaSupplicant.iface);
+    if (g_strcmp0(state, "completed") == 0)
+    {
+        mConnectivityFlag.Set(ConnectivityFlags::kHaveIPv4InternetConnectivity)
+            .Set(ConnectivityFlags::kHaveIPv6InternetConnectivity);
+        ret = true;
+    }
+
+    return ret;
+}
+
+bool ConnectivityManagerImpl::_IsWiFiStationApplicationControlled()
+{
+    return mWiFiStationMode == ConnectivityManager::kWiFiStationMode_ApplicationControlled;
+}
+
+bool ConnectivityManagerImpl::_IsWiFiStationProvisioned()
+{
+    bool ret          = false;
+    const gchar * bss = nullptr;
+
+    if (mWpaSupplicant.state != GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED)
+    {
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: _IsWiFiStationProvisioned: interface not connected");
+        return false;
+    }
+
+    bss = wpa_fi_w1_wpa_supplicant1_interface_get_current_bss(mWpaSupplicant.iface);
+    if (g_str_match_string("BSSs", bss, true))
+    {
+        ret = true;
+    }
+
+    return ret;
+}
+
+void ConnectivityManagerImpl::_ClearWiFiStationProvision()
+{
+    if (mWpaSupplicant.state != GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED)
+    {
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: _ClearWiFiStationProvision: interface not connected");
+        return;
+    }
+
+    if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled)
+    {
+        GError * err = nullptr;
+        wpa_fi_w1_wpa_supplicant1_interface_call_remove_all_networks_sync(mWpaSupplicant.iface, nullptr, &err);
+
+        if (err != nullptr)
+        {
+            ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to remove all networks with error: %s",
+                            err ? err->message : "unknown error");
+            g_error_free(err);
+        }
+    }
+}
+
+bool ConnectivityManagerImpl::_CanStartWiFiScan()
+{
+    return mWpaSupplicant.state == GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED &&
+        mWpaSupplicant.scanState == GDBusWpaSupplicant::WIFI_SCANNING_IDLE;
+}
+
+CHIP_ERROR ConnectivityManagerImpl::_SetWiFiAPMode(WiFiAPMode val)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    VerifyOrExit(val != kWiFiAPMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
+
+    if (mWiFiAPMode != val)
+    {
+        ChipLogProgress(DeviceLayer, "WiFi AP mode change: %s -> %s", WiFiAPModeToStr(mWiFiAPMode), WiFiAPModeToStr(val));
+        mWiFiAPMode = val;
+
+        SystemLayer.ScheduleWork(DriveAPState, NULL);
+    }
+
+exit:
+    return err;
+}
+
+void ConnectivityManagerImpl::_DemandStartWiFiAP()
+{
+    if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
+    {
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand start WiFi AP");
+        mLastAPDemandTime = System::Layer::GetClock_MonotonicMS();
+        SystemLayer.ScheduleWork(DriveAPState, NULL);
+    }
+    else
+    {
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand start WiFi AP ignored, mode: %s", WiFiAPModeToStr(mWiFiAPMode));
+    }
+}
+
+void ConnectivityManagerImpl::_StopOnDemandWiFiAP()
+{
+    if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
+    {
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand stop WiFi AP");
+        mLastAPDemandTime = 0;
+        SystemLayer.ScheduleWork(DriveAPState, NULL);
+    }
+    else
+    {
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: Demand stop WiFi AP ignored, mode: %s", WiFiAPModeToStr(mWiFiAPMode));
+    }
+}
+
+void ConnectivityManagerImpl::_MaintainOnDemandWiFiAP()
+{
+    if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
+    {
+        if (mWiFiAPState == kWiFiAPState_Active)
+        {
+            mLastAPDemandTime = System::Layer::GetClock_MonotonicMS();
+        }
+    }
+}
+
+void ConnectivityManagerImpl::_SetWiFiAPIdleTimeoutMS(uint32_t val)
+{
+    mWiFiAPIdleTimeoutMS = val;
+    SystemLayer.ScheduleWork(DriveAPState, NULL);
+}
+
+void ConnectivityManagerImpl::_OnWpaInterfaceProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data)
+{
+    GError * err                            = nullptr;
+    WpaFiW1Wpa_supplicant1Interface * iface = wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus_finish(res, &err);
+
+    if (mWpaSupplicant.iface)
+    {
+        g_object_unref(mWpaSupplicant.iface);
+        mWpaSupplicant.iface = nullptr;
+    }
+
+    if (iface != nullptr && err == nullptr)
+    {
+        mWpaSupplicant.iface = iface;
+        mWpaSupplicant.state = GDBusWpaSupplicant::WPA_INTERFACE_CONNECTED;
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to wpa_supplicant interface proxy");
+    }
+    else
+    {
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create wpa_supplicant1 interface proxy %s: %s",
+                        mWpaSupplicant.interfacePath, err ? err->message : "unknown error");
+
+        mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NOT_CONNECTED;
+    }
+
+    if (err != nullptr)
+        g_error_free(err);
+}
+
+void ConnectivityManagerImpl::_OnWpaInterfaceReady(GObject * source_object, GAsyncResult * res, gpointer user_data)
+{
+    GError * err = nullptr;
+
+    gboolean result =
+        wpa_fi_w1_wpa_supplicant1_call_get_interface_finish(mWpaSupplicant.proxy, &mWpaSupplicant.interfacePath, res, &err);
+    if (result)
+    {
+        mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH;
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface: %s", mWpaSupplicant.interfacePath);
+
+        wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName,
+                                                              mWpaSupplicant.interfacePath, nullptr, _OnWpaInterfaceProxyReady,
+                                                              nullptr);
+    }
+    else
+    {
+        GError * error  = nullptr;
+        GVariant * args = nullptr;
+        GVariantBuilder builder;
+
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: can't find interface %s: %s", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME,
+                        err ? err->message : "unknown error");
+
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: try to create interface %s", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME);
+
+        g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+        g_variant_builder_add(&builder, "{sv}", "Ifname", g_variant_new_string(CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME));
+        args = g_variant_builder_end(&builder);
+
+        result = wpa_fi_w1_wpa_supplicant1_call_create_interface_sync(mWpaSupplicant.proxy, args, &mWpaSupplicant.interfacePath,
+                                                                      nullptr, &error);
+
+        if (result)
+        {
+            mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH;
+            ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface: %s", mWpaSupplicant.interfacePath);
+
+            wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE,
+                                                                  kWpaSupplicantServiceName, mWpaSupplicant.interfacePath, nullptr,
+                                                                  _OnWpaInterfaceProxyReady, nullptr);
+        }
+        else
+        {
+            ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create interface %s: %s",
+                            CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME, error ? error->message : "unknown error");
+
+            mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NO_INTERFACE_PATH;
+
+            if (mWpaSupplicant.interfacePath)
+            {
+                g_free(mWpaSupplicant.interfacePath);
+                mWpaSupplicant.interfacePath = nullptr;
+            }
+        }
+
+        if (error != nullptr)
+            g_error_free(error);
+    }
+
+    if (err != nullptr)
+        g_error_free(err);
+}
+
+void ConnectivityManagerImpl::_OnWpaInterfaceAdded(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties,
+                                                   gpointer user_data)
+{
+    if (mWpaSupplicant.interfacePath)
+        return;
+
+    mWpaSupplicant.interfacePath = const_cast<gchar *>(path);
+    if (mWpaSupplicant.interfacePath)
+    {
+        mWpaSupplicant.state = GDBusWpaSupplicant::WPA_GOT_INTERFACE_PATH;
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface added: %s", mWpaSupplicant.interfacePath);
+
+        wpa_fi_w1_wpa_supplicant1_interface_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName,
+                                                              mWpaSupplicant.interfacePath, nullptr, _OnWpaInterfaceProxyReady,
+                                                              nullptr);
+    }
+}
+
+void ConnectivityManagerImpl::_OnWpaInterfaceRemoved(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties,
+                                                     gpointer user_data)
+{
+    if (mWpaSupplicant.interfacePath == nullptr)
+        return;
+
+    if (g_strcmp0(mWpaSupplicant.interfacePath, path) == 0)
+    {
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: WiFi interface removed: %s", path);
+
+        mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NO_INTERFACE_PATH;
+
+        if (mWpaSupplicant.interfacePath)
+        {
+            g_free(mWpaSupplicant.interfacePath);
+            mWpaSupplicant.interfacePath = nullptr;
+        }
+
+        if (mWpaSupplicant.iface)
+        {
+            g_object_unref(mWpaSupplicant.iface);
+            mWpaSupplicant.iface = nullptr;
+        }
+
+        mWpaSupplicant.scanState = GDBusWpaSupplicant::WIFI_SCANNING_IDLE;
+    }
+}
+
+void ConnectivityManagerImpl::_OnWpaProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data)
+{
+    GError * err = nullptr;
+
+    mWpaSupplicant.proxy = wpa_fi_w1_wpa_supplicant1_proxy_new_for_bus_finish(res, &err);
+    if (mWpaSupplicant.proxy != nullptr && err == nullptr)
+    {
+        mWpaSupplicant.state = GDBusWpaSupplicant::WPA_CONNECTED;
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to wpa_supplicant proxy");
+
+        g_signal_connect(mWpaSupplicant.proxy, "interface-added", G_CALLBACK(_OnWpaInterfaceAdded), NULL);
+
+        g_signal_connect(mWpaSupplicant.proxy, "interface-removed", G_CALLBACK(_OnWpaInterfaceRemoved), NULL);
+
+        wpa_fi_w1_wpa_supplicant1_call_get_interface(mWpaSupplicant.proxy, CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME, nullptr,
+                                                     _OnWpaInterfaceReady, nullptr);
+    }
+    else
+    {
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to create wpa_supplicant proxy %s",
+                        err ? err->message : "unknown error");
+        mWpaSupplicant.state = GDBusWpaSupplicant::WPA_NOT_CONNECTED;
+    }
+
+    if (err != nullptr)
+        g_error_free(err);
+}
+
+void ConnectivityManagerImpl::StartWiFiManagement()
+{
+    mConnectivityFlag.ClearAll();
+    mWpaSupplicant.state         = GDBusWpaSupplicant::INIT;
+    mWpaSupplicant.scanState     = GDBusWpaSupplicant::WIFI_SCANNING_IDLE;
+    mWpaSupplicant.proxy         = nullptr;
+    mWpaSupplicant.iface         = nullptr;
+    mWpaSupplicant.interfacePath = nullptr;
+    mWpaSupplicant.networkPath   = nullptr;
+
+    wpa_fi_w1_wpa_supplicant1_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, kWpaSupplicantServiceName,
+                                                kWpaSupplicantObjectPath, nullptr, _OnWpaProxyReady, nullptr);
+}
+
+void ConnectivityManagerImpl::DriveAPState()
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+    WiFiAPState targetState;
+    uint64_t now;
+    uint32_t apTimeout;
+
+    // If the AP interface is not under application control...
+    if (mWiFiAPMode != kWiFiAPMode_ApplicationControlled)
+    {
+        // Determine the target (desired) state for AP interface...
+
+        // The target state is 'NotActive' if the application has expressly disabled the AP interface.
+        if (mWiFiAPMode == kWiFiAPMode_Disabled)
+        {
+            targetState = kWiFiAPState_NotActive;
+        }
+
+        // The target state is 'Active' if the application has expressly enabled the AP interface.
+        else if (mWiFiAPMode == kWiFiAPMode_Enabled)
+        {
+            targetState = kWiFiAPState_Active;
+        }
+
+        // The target state is 'Active' if the AP mode is 'On demand, when no station is available'
+        // and the station interface is not provisioned or the application has disabled the station
+        // interface.
+        else if (mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision &&
+                 (!IsWiFiStationProvisioned() || GetWiFiStationMode() == kWiFiStationMode_Disabled))
+        {
+            targetState = kWiFiAPState_Active;
+        }
+
+        // The target state is 'Active' if the AP mode is one of the 'On demand' modes and there
+        // has been demand for the AP within the idle timeout period.
+        else if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision)
+        {
+            now = System::Layer::GetClock_MonotonicMS();
+
+            if (mLastAPDemandTime != 0 && now < (mLastAPDemandTime + mWiFiAPIdleTimeoutMS))
+            {
+                targetState = kWiFiAPState_Active;
+
+                // Compute the amount of idle time before the AP should be deactivated and
+                // arm a timer to fire at that time.
+                apTimeout = (uint32_t)((mLastAPDemandTime + mWiFiAPIdleTimeoutMS) - now);
+                err       = SystemLayer.StartTimer(apTimeout, DriveAPState, NULL);
+                SuccessOrExit(err);
+                ChipLogProgress(DeviceLayer, "Next WiFi AP timeout in %" PRIu32 " s", apTimeout / 1000);
+            }
+            else
+            {
+                targetState = kWiFiAPState_NotActive;
+            }
+        }
+
+        // Otherwise the target state is 'NotActive'.
+        else
+        {
+            targetState = kWiFiAPState_NotActive;
+        }
+
+        // If the current AP state does not match the target state...
+        if (mWiFiAPState != targetState)
+        {
+            if (targetState == kWiFiAPState_Active)
+            {
+                err = ConfigureWiFiAP();
+                SuccessOrExit(err);
+
+                ChangeWiFiAPState(kWiFiAPState_Active);
+            }
+            else
+            {
+                if (mWpaSupplicant.networkPath)
+                {
+                    GError * error = nullptr;
+
+                    gboolean result = wpa_fi_w1_wpa_supplicant1_interface_call_remove_network_sync(
+                        mWpaSupplicant.iface, mWpaSupplicant.networkPath, nullptr, &error);
+
+                    if (result)
+                    {
+                        ChipLogProgress(DeviceLayer, "wpa_supplicant: removed network: %s", mWpaSupplicant.networkPath);
+                        g_free(mWpaSupplicant.networkPath);
+                        mWpaSupplicant.networkPath = nullptr;
+                        ChangeWiFiAPState(kWiFiAPState_NotActive);
+                    }
+                    else
+                    {
+                        ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to stop AP mode with error: %s",
+                                        error ? error->message : "unknown error");
+                        err = CHIP_ERROR_INTERNAL;
+                    }
+
+                    if (error != nullptr)
+                        g_error_free(error);
+                }
+            }
+        }
+    }
+
+exit:
+    if (err != CHIP_NO_ERROR)
+    {
+        SetWiFiAPMode(kWiFiAPMode_Disabled);
+        ChipLogError(DeviceLayer, "Drive AP state failed: %s", ErrorStr(err));
+    }
+}
+
+CHIP_ERROR ConnectivityManagerImpl::ConfigureWiFiAP()
+{
+    CHIP_ERROR ret  = CHIP_NO_ERROR;
+    GError * err    = nullptr;
+    GVariant * args = nullptr;
+    GVariantBuilder builder;
+
+    uint16_t channel       = 1;
+    uint16_t discriminator = 0;
+    char ssid[32];
+
+    channel = MapFrequency(kWiFi_BAND_2_4_GHZ, CHIP_DEVICE_CONFIG_WIFI_AP_CHANNEL);
+
+    if (ConfigurationMgr().GetSetupDiscriminator(discriminator) != CHIP_NO_ERROR)
+        discriminator = 0;
+
+    snprintf(ssid, 32, "%s%04u", CHIP_DEVICE_CONFIG_WIFI_AP_SSID_PREFIX, discriminator);
+
+    ChipLogProgress(DeviceLayer, "wpa_supplicant: ConfigureWiFiAP, ssid: %s, channel: %d", ssid, channel);
+
+    // Clean up current network if exists
+    if (mWpaSupplicant.networkPath)
+    {
+        g_object_unref(mWpaSupplicant.networkPath);
+        mWpaSupplicant.networkPath = nullptr;
+    }
+
+    g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+    g_variant_builder_add(&builder, "{sv}", "ssid", g_variant_new_string(ssid));
+    g_variant_builder_add(&builder, "{sv}", "key_mgmt", g_variant_new_string("NONE"));
+    g_variant_builder_add(&builder, "{sv}", "mode", g_variant_new_int32(2));
+    g_variant_builder_add(&builder, "{sv}", "frequency", g_variant_new_int32(channel));
+    args = g_variant_builder_end(&builder);
+
+    gboolean result = wpa_fi_w1_wpa_supplicant1_interface_call_add_network_sync(mWpaSupplicant.iface, args,
+                                                                                &mWpaSupplicant.networkPath, nullptr, &err);
+
+    if (result)
+    {
+        GError * error = nullptr;
+
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: added network: SSID: %s: %s", ssid, mWpaSupplicant.networkPath);
+
+        result = wpa_fi_w1_wpa_supplicant1_interface_call_select_network_sync(mWpaSupplicant.iface, mWpaSupplicant.networkPath,
+                                                                              nullptr, &error);
+        if (result)
+        {
+            ChipLogProgress(DeviceLayer, "wpa_supplicant: succeeded to start softAP: SSID: %s", ssid);
+        }
+        else
+        {
+            ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to start softAP: SSID: %s: %s", ssid,
+                            error ? error->message : "unknown error");
+
+            ret = CHIP_ERROR_INTERNAL;
+        }
+
+        if (error != nullptr)
+            g_error_free(error);
+    }
+    else
+    {
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to add network: %s: %s", ssid, err ? err->message : "unknown error");
+
+        if (mWpaSupplicant.networkPath)
+        {
+            g_object_unref(mWpaSupplicant.networkPath);
+            mWpaSupplicant.networkPath = nullptr;
+        }
+
+        ret = CHIP_ERROR_INTERNAL;
+    }
+
+    if (err != nullptr)
+        g_error_free(err);
+
+    return ret;
+}
+
+void ConnectivityManagerImpl::ChangeWiFiAPState(WiFiAPState newState)
+{
+    if (mWiFiAPState != newState)
+    {
+        ChipLogProgress(DeviceLayer, "WiFi AP state change: %s -> %s", WiFiAPStateToStr(mWiFiAPState), WiFiAPStateToStr(newState));
+        mWiFiAPState = newState;
+    }
+}
+
+void ConnectivityManagerImpl::DriveAPState(::chip::System::Layer * aLayer, void * aAppState, ::chip::System::Error aError)
+{
+    sInstance.DriveAPState();
+}
+#endif // CHIP_DEVICE_CONFIG_ENABLE_WPA
+
+CHIP_ERROR ConnectivityManagerImpl::ProvisionWiFiNetwork(const char * ssid, const char * key)
+{
+#if CHIP_DEVICE_CONFIG_ENABLE_WPA
+    CHIP_ERROR ret  = CHIP_NO_ERROR;
+    GError * err    = nullptr;
+    GVariant * args = nullptr;
+    GVariantBuilder builder;
+    gboolean result;
+
+    // Clean up current network if exists
+    if (mWpaSupplicant.networkPath)
+    {
+        GError * error = nullptr;
+
+        result = wpa_fi_w1_wpa_supplicant1_interface_call_remove_network_sync(mWpaSupplicant.iface, mWpaSupplicant.networkPath,
+                                                                              nullptr, &error);
+
+        if (result)
+        {
+            ChipLogProgress(DeviceLayer, "wpa_supplicant: removed network: %s", mWpaSupplicant.networkPath);
+            g_free(mWpaSupplicant.networkPath);
+            mWpaSupplicant.networkPath = nullptr;
+        }
+        else
+        {
+            ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to stop AP mode with error: %s",
+                            error ? error->message : "unknown error");
+            ret = CHIP_ERROR_INTERNAL;
+        }
+
+        if (error != nullptr)
+            g_error_free(error);
+
+        SuccessOrExit(ret);
+    }
+
+    g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
+    g_variant_builder_add(&builder, "{sv}", "ssid", g_variant_new_string(ssid));
+    g_variant_builder_add(&builder, "{sv}", "psk", g_variant_new_string(key));
+    g_variant_builder_add(&builder, "{sv}", "key_mgmt", g_variant_new_string("WPA-PSK"));
+    args = g_variant_builder_end(&builder);
+
+    result = wpa_fi_w1_wpa_supplicant1_interface_call_add_network_sync(mWpaSupplicant.iface, args, &mWpaSupplicant.networkPath,
+                                                                       nullptr, &err);
+
+    if (result)
+    {
+        GError * error = nullptr;
+
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: added network: SSID: %s: %s", ssid, mWpaSupplicant.networkPath);
+
+        result = wpa_fi_w1_wpa_supplicant1_interface_call_select_network_sync(mWpaSupplicant.iface, mWpaSupplicant.networkPath,
+                                                                              nullptr, &error);
+        if (result)
+        {
+            GError * gerror = nullptr;
+
+            ChipLogProgress(DeviceLayer, "wpa_supplicant: connected to network: SSID: %s", ssid);
+
+            result = wpa_fi_w1_wpa_supplicant1_interface_call_save_config_sync(mWpaSupplicant.iface, nullptr, &gerror);
+
+            if (result)
+            {
+                ChipLogProgress(DeviceLayer, "wpa_supplicant: save config succeeded!");
+            }
+            else
+            {
+                ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to save config: %s",
+                                gerror ? gerror->message : "unknown error");
+            }
+
+            if (gerror != nullptr)
+                g_error_free(gerror);
+
+            // Iterate on the network interface to see if we already have beed assigned addresses.
+            // The temporary hack for getting IP address change on linux for network provisioning in the rendezvous session.
+            // This should be removed or find a better place once we depercate the rendezvous session.
+            for (chip::Inet::InterfaceAddressIterator it; it.HasCurrent(); it.Next())
+            {
+                char ifName[chip::Inet::InterfaceIterator::kMaxIfNameLength];
+                if (it.IsUp() && CHIP_NO_ERROR == it.GetInterfaceName(ifName, sizeof(ifName)) &&
+                    strncmp(ifName, CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME, sizeof(ifName)) == 0)
+                {
+                    chip::Inet::IPAddress addr = it.GetAddress();
+                    if (addr.IsIPv4())
+                    {
+                        ChipDeviceEvent event;
+                        event.Type                            = DeviceEventType::kInternetConnectivityChange;
+                        event.InternetConnectivityChange.IPv4 = kConnectivity_Established;
+                        event.InternetConnectivityChange.IPv6 = kConnectivity_NoChange;
+                        addr.ToString(event.InternetConnectivityChange.address);
+
+                        ChipLogDetail(DeviceLayer, "Got IP address on interface: %s IP: %s", ifName,
+                                      event.InternetConnectivityChange.address);
+
+                        PlatformMgr().PostEvent(&event);
+                    }
+                }
+            }
+
+            // Run dhclient for IP on WiFi.
+            // TODO: The wifi can be managed by networkmanager on linux so we don't have to care about this.
+            char cmdBuffer[128];
+            sprintf(cmdBuffer, "dhclient -nw %s", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME);
+            int dhclientSystemRet = system(cmdBuffer);
+            if (dhclientSystemRet != 0)
+            {
+                ChipLogError(DeviceLayer, "Failed to run dhclient, system() returns %d", dhclientSystemRet);
+            }
+            else
+            {
+                ChipLogProgress(DeviceLayer, "dhclient is running on the %s interface.", CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME);
+            }
+
+            // Return success as long as the device is connected to the network
+            ret = CHIP_NO_ERROR;
+        }
+        else
+        {
+            ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to connect to network: SSID: %s: %s", ssid,
+                            error ? error->message : "unknown error");
+
+            ret = CHIP_ERROR_INTERNAL;
+        }
+
+        if (error != nullptr)
+            g_error_free(error);
+    }
+    else
+    {
+        ChipLogProgress(DeviceLayer, "wpa_supplicant: failed to add network: %s: %s", ssid, err ? err->message : "unknown error");
+
+        if (mWpaSupplicant.networkPath)
+        {
+            g_object_unref(mWpaSupplicant.networkPath);
+            mWpaSupplicant.networkPath = nullptr;
+        }
+
+        ret = CHIP_ERROR_INTERNAL;
+    }
+
+exit:
+    if (err != nullptr)
+        g_error_free(err);
+
+    return ret;
+#else
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+#endif
+}
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/ConnectivityManagerImpl.h b/src/platform/Tizen/ConnectivityManagerImpl.h
new file mode 100644 (file)
index 0000000..f381470
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ *
+ *    Copyright (c) 2020-2021 Project CHIP Authors
+ *    Copyright (c) 2018 Nest Labs, Inc.
+ *
+ *    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 <platform/ConnectivityManager.h>
+#include <platform/internal/GenericConnectivityManagerImpl.h>
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+#include <platform/internal/GenericConnectivityManagerImpl_BLE.h>
+#else
+#include <platform/internal/GenericConnectivityManagerImpl_NoBLE.h>
+#endif
+#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
+#include <platform/internal/GenericConnectivityManagerImpl_Thread.h>
+#else
+#include <platform/internal/GenericConnectivityManagerImpl_NoThread.h>
+#endif
+#if CHIP_DEVICE_CONFIG_ENABLE_WPA
+#include <platform/internal/GenericConnectivityManagerImpl_WiFi.h>
+#else
+#include <platform/internal/GenericConnectivityManagerImpl_NoWiFi.h>
+#endif
+
+#if CHIP_DEVICE_CONFIG_ENABLE_WPA
+#include <platform/Linux/dbus/wpa/DBusWpa.h>
+#include <platform/Linux/dbus/wpa/DBusWpaInterface.h>
+#include <platform/Linux/dbus/wpa/DBusWpaNetwork.h>
+#endif
+
+namespace chip {
+namespace Inet {
+class IPAddress;
+} // namespace Inet
+} // namespace chip
+
+namespace chip {
+namespace DeviceLayer {
+
+#if CHIP_DEVICE_CONFIG_ENABLE_WPA
+struct GDBusWpaSupplicant
+{
+    enum
+    {
+        INIT,
+        WPA_CONNECTING,
+        WPA_CONNECTED,
+        WPA_NOT_CONNECTED,
+        WPA_NO_INTERFACE_PATH,
+        WPA_GOT_INTERFACE_PATH,
+        WPA_INTERFACE_CONNECTED,
+    } state;
+
+    enum
+    {
+        WIFI_SCANNING_IDLE,
+        WIFI_SCANNING,
+    } scanState;
+
+    WpaFiW1Wpa_supplicant1 * proxy;
+    WpaFiW1Wpa_supplicant1Interface * iface;
+    gchar * interfacePath;
+    gchar * networkPath;
+};
+#endif
+
+/**
+ * Concrete implementation of the ConnectivityManager singleton object for Linux platforms.
+ */
+class ConnectivityManagerImpl final : public ConnectivityManager,
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+                                      public Internal::GenericConnectivityManagerImpl_BLE<ConnectivityManagerImpl>,
+#else
+                                      public Internal::GenericConnectivityManagerImpl_NoBLE<ConnectivityManagerImpl>,
+#endif
+#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
+                                      public Internal::GenericConnectivityManagerImpl_Thread<ConnectivityManagerImpl>,
+#else
+                                      public Internal::GenericConnectivityManagerImpl_NoThread<ConnectivityManagerImpl>,
+#endif
+#if CHIP_DEVICE_CONFIG_ENABLE_WPA
+                                      public Internal::GenericConnectivityManagerImpl_WiFi<ConnectivityManagerImpl>,
+#else
+                                      public Internal::GenericConnectivityManagerImpl_NoWiFi<ConnectivityManagerImpl>,
+#endif
+                                      public Internal::GenericConnectivityManagerImpl<ConnectivityManagerImpl>
+{
+    // Allow the ConnectivityManager interface class to delegate method calls to
+    // the implementation methods provided by this class.
+    friend class ConnectivityManager;
+
+public:
+    CHIP_ERROR ProvisionWiFiNetwork(const char * ssid, const char * key);
+
+#if CHIP_DEVICE_CONFIG_ENABLE_WPA
+    void StartWiFiManagement();
+#endif
+
+private:
+    // ===== Members that implement the ConnectivityManager abstract interface.
+
+    bool _HaveIPv4InternetConnectivity();
+    bool _HaveIPv6InternetConnectivity();
+    bool _HaveServiceConnectivity();
+    CHIP_ERROR _Init();
+    void _OnPlatformEvent(const ChipDeviceEvent * event);
+
+#if CHIP_DEVICE_CONFIG_ENABLE_WPA
+    WiFiStationMode _GetWiFiStationMode();
+    CHIP_ERROR _SetWiFiStationMode(ConnectivityManager::WiFiStationMode val);
+    uint32_t _GetWiFiStationReconnectIntervalMS();
+    CHIP_ERROR _SetWiFiStationReconnectIntervalMS(uint32_t val);
+    bool _IsWiFiStationEnabled();
+    bool _IsWiFiStationConnected();
+    bool _IsWiFiStationApplicationControlled();
+    bool _IsWiFiStationProvisioned();
+    void _ClearWiFiStationProvision();
+    bool _CanStartWiFiScan();
+
+    WiFiAPMode _GetWiFiAPMode();
+    CHIP_ERROR _SetWiFiAPMode(WiFiAPMode val);
+    bool _IsWiFiAPActive();
+    bool _IsWiFiAPApplicationControlled();
+    void _DemandStartWiFiAP();
+    void _StopOnDemandWiFiAP();
+    void _MaintainOnDemandWiFiAP();
+    uint32_t _GetWiFiAPIdleTimeoutMS();
+    void _SetWiFiAPIdleTimeoutMS(uint32_t val);
+
+    static void _OnWpaProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data);
+    static void _OnWpaInterfaceRemoved(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties,
+                                       gpointer user_data);
+    static void _OnWpaInterfaceAdded(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties, gpointer user_data);
+    static void _OnWpaInterfaceReady(GObject * source_object, GAsyncResult * res, gpointer user_data);
+    static void _OnWpaInterfaceProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data);
+
+    static BitFlags<ConnectivityFlags> mConnectivityFlag;
+    static struct GDBusWpaSupplicant mWpaSupplicant;
+#endif
+
+    // ==================== ConnectivityManager Private Methods ====================
+
+#if CHIP_DEVICE_CONFIG_ENABLE_WPA
+    void DriveAPState();
+    CHIP_ERROR ConfigureWiFiAP();
+    void ChangeWiFiAPState(WiFiAPState newState);
+    static void DriveAPState(::chip::System::Layer * aLayer, void * aAppState, ::chip::System::Error aError);
+#endif
+
+    // ===== Members for internal use by the following friends.
+
+    friend ConnectivityManager & ConnectivityMgr();
+    friend ConnectivityManagerImpl & ConnectivityMgrImpl();
+
+    static ConnectivityManagerImpl sInstance;
+
+    // ===== Private members reserved for use by this class only.
+
+    ConnectivityManager::WiFiStationMode mWiFiStationMode;
+    ConnectivityManager::WiFiAPMode mWiFiAPMode;
+    WiFiAPState mWiFiAPState;
+    uint64_t mLastAPDemandTime;
+    uint32_t mWiFiStationReconnectIntervalMS;
+    uint32_t mWiFiAPIdleTimeoutMS;
+};
+
+#if CHIP_DEVICE_CONFIG_ENABLE_WPA
+inline ConnectivityManager::WiFiAPMode ConnectivityManagerImpl::_GetWiFiAPMode()
+{
+    return mWiFiAPMode;
+}
+
+inline bool ConnectivityManagerImpl::_IsWiFiAPActive()
+{
+    return mWiFiAPState == kWiFiAPState_Active;
+}
+
+inline bool ConnectivityManagerImpl::_IsWiFiAPApplicationControlled()
+{
+    return mWiFiAPMode == kWiFiAPMode_ApplicationControlled;
+}
+
+inline uint32_t ConnectivityManagerImpl::_GetWiFiAPIdleTimeoutMS()
+{
+    return mWiFiAPIdleTimeoutMS;
+}
+
+inline bool ConnectivityManagerImpl::_HaveServiceConnectivity()
+{
+    return _HaveServiceConnectivityViaThread();
+}
+#endif
+
+/**
+ * Returns the public interface of the ConnectivityManager singleton object.
+ *
+ * chip applications should use this to access features of the ConnectivityManager object
+ * that are common to all platforms.
+ */
+inline ConnectivityManager & ConnectivityMgr()
+{
+    return ConnectivityManagerImpl::sInstance;
+}
+
+/**
+ * Returns the platform-specific implementation of the ConnectivityManager singleton object.
+ *
+ * chip applications can use this to gain access to features of the ConnectivityManager
+ * that are specific to the ESP32 platform.
+ */
+inline ConnectivityManagerImpl & ConnectivityMgrImpl()
+{
+    return ConnectivityManagerImpl::sInstance;
+}
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/DeviceNetworkProvisioningDelegateImpl.cpp b/src/platform/Tizen/DeviceNetworkProvisioningDelegateImpl.cpp
new file mode 100644 (file)
index 0000000..994ddf1
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *
+ *    Copyright (c) 2020 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 <support/ErrorStr.h>
+#include <support/logging/CHIPLogging.h>
+
+#include "DeviceNetworkProvisioningDelegateImpl.h"
+
+namespace chip {
+namespace DeviceLayer {
+
+CHIP_ERROR DeviceNetworkProvisioningDelegateImpl::_ProvisionWiFiNetwork(const char * ssid, const char * key)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    ChipLogProgress(NetworkProvisioning, "LinuxNetworkProvisioningDelegate: SSID: %s", ssid);
+
+    err = ConnectivityMgrImpl().ProvisionWiFiNetwork(ssid, key);
+
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(NetworkProvisioning, "Failed to connect to WiFi network: %s", chip::ErrorStr(err));
+    }
+
+    return err;
+}
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/DeviceNetworkProvisioningDelegateImpl.h b/src/platform/Tizen/DeviceNetworkProvisioningDelegateImpl.h
new file mode 100644 (file)
index 0000000..0db3663
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *
+ *    Copyright (c) 2020 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 <platform/internal/GenericDeviceNetworkProvisioningDelegateImpl.h>
+
+namespace chip {
+namespace DeviceLayer {
+
+namespace Internal {
+
+template <class ImplClass>
+class GenericDeviceNetworkProvisioningDelegateImpl;
+
+} // namespace Internal
+
+class DeviceNetworkProvisioningDelegateImpl final
+    : public Internal::GenericDeviceNetworkProvisioningDelegateImpl<DeviceNetworkProvisioningDelegateImpl>
+{
+    friend class GenericDeviceNetworkProvisioningDelegateImpl<DeviceNetworkProvisioningDelegateImpl>;
+
+private:
+    CHIP_ERROR _ProvisionWiFiNetwork(const char * ssid, const char * passwd);
+    CHIP_ERROR _ProvisionThreadNetwork(DeviceLayer::Internal::DeviceNetworkInfo & threadData) { return CHIP_ERROR_NOT_IMPLEMENTED; }
+};
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/Entropy.cpp b/src/platform/Tizen/Entropy.cpp
new file mode 100644 (file)
index 0000000..f1b23e4
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *
+ *    Copyright (c) 2020 Project CHIP Authors
+ *    Copyright (c) 2019 Google LLC.
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *          Provides implementations for the chip entropy sourcing functions
+ *          on the Linux platforms.
+ */
+
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+#include <support/crypto/CHIPRNG.h>
+
+using namespace ::chip;
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+CHIP_ERROR InitEntropy()
+{
+    CHIP_ERROR err;
+    unsigned int seed;
+
+    // Initialize the source used by CHIP to get secure random data.
+    err = Platform::Security::InitSecureRandomDataSource(getentropy, 64, NULL, 0);
+    SuccessOrExit(err);
+
+    // Seed the standard rand() pseudo-random generator with data from the secure random source.
+    err = Platform::Security::GetSecureRandomData((uint8_t *) &seed, sizeof(seed));
+    SuccessOrExit(err);
+    srand(seed);
+exit:
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(Crypto, "InitEntropy() failed: %d" err);
+    }
+    return err;
+}
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/InetPlatformConfig.h b/src/platform/Tizen/InetPlatformConfig.h
new file mode 100644 (file)
index 0000000..add9c8c
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *
+ *    Copyright (c) 2020 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.
+ */
+
+/**
+ *    @file
+ *          Platform-specific configuration overrides for the CHIP Inet
+ *          Layer on Linux platforms.
+ *
+ */
+
+#pragma once
+
+// ==================== Platform Adaptations ====================
+
+#define INET_CONFIG_ENABLE_IPV4 1
+
+// ========== Platform-specific Configuration Overrides =========
+
+#ifndef INET_CONFIG_NUM_TCP_ENDPOINTS
+#define INET_CONFIG_NUM_TCP_ENDPOINTS 32
+#endif // INET_CONFIG_NUM_TCP_ENDPOINTS
+
+#ifndef INET_CONFIG_NUM_UDP_ENDPOINTS
+#define INET_CONFIG_NUM_UDP_ENDPOINTS 32
+#endif // INET_CONFIG_NUM_UDP_ENDPOINTS
+
+// On linux platform, we have sys/socket.h, so HAVE_SO_BINDTODEVICE should be set to 1
+#define HAVE_SO_BINDTODEVICE 1
diff --git a/src/platform/Tizen/KeyValueStoreManagerImpl.cpp b/src/platform/Tizen/KeyValueStoreManagerImpl.cpp
new file mode 100644 (file)
index 0000000..5fd78ff
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ *
+ *    Copyright (c) 2021 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *          Platform-specific implementatiuon of KVS for linux.
+ */
+
+#include <platform/KeyValueStoreManager.h>
+
+#include <algorithm>
+#include <string.h>
+
+#include <platform/Linux/CHIPLinuxStorage.h>
+#include <support/CodeUtils.h>
+#include <support/logging/CHIPLogging.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace PersistedStorage {
+
+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)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+    size_t read_size;
+    size_t copy_size;
+
+    // On linux read first without a buffer which returns the size, and then
+    // use a local buffer to read the entire object, which allows partial and
+    // offset reads.
+    err = mStorage.ReadValueBin(key, nullptr, 0, read_size);
+    uint8_t buf[read_size];
+    if (err == CHIP_ERROR_KEY_NOT_FOUND)
+    {
+        ExitNow(err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+    }
+    err = mStorage.ReadValueBin(key, buf, read_size, read_size);
+    SuccessOrExit(err);
+
+    // Copy data into value buffer
+    if (!value)
+    {
+        ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT);
+    }
+    copy_size = std::min(value_size, read_size - offset_bytes);
+    if (read_bytes_size)
+    {
+        *read_bytes_size = copy_size;
+    }
+    ::memcpy(value, buf + offset_bytes, copy_size);
+
+exit:
+    return err;
+}
+
+CHIP_ERROR KeyValueStoreManagerImpl::_Put(const char * key, const void * value, size_t value_size)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+
+    err = mStorage.WriteValueBin(key, reinterpret_cast<const uint8_t *>(value), value_size);
+    SuccessOrExit(err);
+
+    // Commit the value to the persistent store.
+    err = mStorage.Commit();
+    SuccessOrExit(err);
+
+exit:
+    return err;
+}
+
+CHIP_ERROR KeyValueStoreManagerImpl::_Delete(const char * key)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+    err            = mStorage.ClearValue(key);
+
+    if (err == CHIP_ERROR_KEY_NOT_FOUND)
+    {
+        ExitNow(err = CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND);
+    }
+    SuccessOrExit(err);
+
+    // Commit the value to the persistent store.
+    err = mStorage.Commit();
+    SuccessOrExit(err);
+
+exit:
+    return err;
+}
+
+} // namespace PersistedStorage
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/KeyValueStoreManagerImpl.h b/src/platform/Tizen/KeyValueStoreManagerImpl.h
new file mode 100644 (file)
index 0000000..a8a9b73
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *
+ *    Copyright (c) 2021 Project CHIP Authors
+ *    All rights reserved.
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *          Platform-specific implementation of KVS for linux.
+ */
+
+#pragma once
+
+#include <platform/Linux/CHIPLinuxStorage.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace PersistedStorage {
+
+class KeyValueStoreManagerImpl : public KeyValueStoreManager
+{
+public:
+    /**
+     * @brief
+     * Initalize the KVS, must be called before using.
+     */
+    void Init(const char * file) { mStorage.Init(file); }
+
+    CHIP_ERROR _Get(const char * key, void * value, size_t value_size, size_t * read_bytes_size = nullptr, size_t offset = 0);
+    CHIP_ERROR _Delete(const char * key);
+    CHIP_ERROR _Put(const char * key, const void * value, size_t value_size);
+
+private:
+    DeviceLayer::Internal::ChipLinuxStorage mStorage;
+
+    // ===== Members for internal use by the following friends.
+    friend KeyValueStoreManager & KeyValueStoreMgr();
+    friend KeyValueStoreManagerImpl & KeyValueStoreMgrImpl();
+
+    static KeyValueStoreManagerImpl sInstance;
+};
+
+/**
+ * Returns the public interface of the KeyValueStoreManager singleton object.
+ *
+ * Chip applications should use this to access features of the KeyValueStoreManager object
+ * that are common to all platforms.
+ */
+inline KeyValueStoreManager & KeyValueStoreMgr(void)
+{
+    return KeyValueStoreManagerImpl::sInstance;
+}
+
+/**
+ * Returns the platform-specific implementation of the KeyValueStoreManager singleton object.
+ *
+ * Chip applications can use this to gain access to features of the KeyValueStoreManager
+ * that are specific to the ESP32 platform.
+ */
+inline KeyValueStoreManagerImpl & KeyValueStoreMgrImpl(void)
+{
+    return KeyValueStoreManagerImpl::sInstance;
+}
+
+} // namespace PersistedStorage
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/Logging.cpp b/src/platform/Tizen/Logging.cpp
new file mode 100644 (file)
index 0000000..fd693ce
--- /dev/null
@@ -0,0 +1,38 @@
+/* See Project CHIP LICENSE file for licensing information. */
+
+#include <platform/logging/LogV.h>
+
+#include <stdio.h>
+
+namespace chip {
+namespace DeviceLayer {
+
+/**
+ * Called whenever a log message is emitted by chip or LwIP.
+ *
+ * This function is intended be overridden by the application to, e.g.,
+ * schedule output of queued log entries.
+ */
+void __attribute__((weak)) OnLogOutput() {}
+
+} // namespace DeviceLayer
+
+namespace Logging {
+namespace Platform {
+
+/**
+ * CHIP log output functions.
+ */
+void LogV(const char * module, uint8_t category, const char * msg, va_list v)
+{
+    printf("CHIP:%s: ", module);
+    vprintf(msg, v);
+    printf("\n");
+
+    // Let the application know that a log message has been emitted.
+    DeviceLayer::OnLogOutput();
+}
+
+} // namespace Platform
+} // namespace Logging
+} // namespace chip
diff --git a/src/platform/Tizen/MdnsError.cpp b/src/platform/Tizen/MdnsError.cpp
new file mode 100644 (file)
index 0000000..b5939be
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *
+ *    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 "MdnsImpl.h"
+
+namespace chip {
+namespace Mdns {
+namespace Error {
+
+const char * ToString(DNSServiceErrorType errorCode)
+{
+    switch (errorCode)
+    {
+    case kDNSServiceErr_NoError:
+        return "kDNSServiceErr_NoError";
+    case kDNSServiceErr_Unknown:
+        return "kDNSServiceErr_Unknown";
+    case kDNSServiceErr_NoSuchName:
+        return "kDNSServiceErr_NoSuchName";
+    case kDNSServiceErr_NoMemory:
+        return "kDNSServiceErr_NoMemory";
+    case kDNSServiceErr_BadParam:
+        return "kDNSServiceErr_BadParam";
+    case kDNSServiceErr_BadReference:
+        return "kDNSServiceErr_BadReference";
+    case kDNSServiceErr_BadState:
+        return "kDNSServiceErr_BadState";
+    case kDNSServiceErr_BadFlags:
+        return "kDNSServiceErr_BadFlags";
+    case kDNSServiceErr_Unsupported:
+        return "kDNSServiceErr_Unsupported";
+    case kDNSServiceErr_NotInitialized:
+        return "kDNSServiceErr_NotInitialized";
+    case kDNSServiceErr_AlreadyRegistered:
+        return "kDNSServiceErr_AlreadyRegistered";
+    case kDNSServiceErr_NameConflict:
+        return "kDNSServiceErr_NameConflict";
+    case kDNSServiceErr_Invalid:
+        return "kDNSServiceErr_Invalid";
+    case kDNSServiceErr_Firewall:
+        return "kDNSServiceErr_Firewall";
+    case kDNSServiceErr_Incompatible:
+        return "kDNSServiceErr_Incompatible";
+    case kDNSServiceErr_BadInterfaceIndex:
+        return "kDNSServiceErr_BadInterfaceIndex";
+    case kDNSServiceErr_Refused:
+        return "kDNSServiceErr_Refused";
+    case kDNSServiceErr_NoSuchRecord:
+        return "kDNSServiceErr_NoSuchRecord";
+    case kDNSServiceErr_NoAuth:
+        return "kDNSServiceErr_NoAuth";
+    case kDNSServiceErr_NoSuchKey:
+        return "kDNSServiceErr_NoSuchKey";
+    case kDNSServiceErr_NATTraversal:
+        return "kDNSServiceErr_NATTraversal";
+    case kDNSServiceErr_DoubleNAT:
+        return "kDNSServiceErr_DoubleNAT";
+    case kDNSServiceErr_BadTime:
+        return "kDNSServiceErr_BadTime";
+    case kDNSServiceErr_BadSig:
+        return "kDNSServiceErr_BadSig";
+    case kDNSServiceErr_BadKey:
+        return "kDNSServiceErr_BadKey";
+    case kDNSServiceErr_Transient:
+        return "kDNSServiceErr_Transient";
+    case kDNSServiceErr_ServiceNotRunning:
+        return "kDNSServiceErr_ServiceNotRunning";
+    case kDNSServiceErr_NATPortMappingUnsupported:
+        return "kDNSServiceErr_NATPortMappingUnsupported";
+    case kDNSServiceErr_NATPortMappingDisabled:
+        return "kDNSServiceErr_NATPortMappingDisabled";
+    case kDNSServiceErr_NoRouter:
+        return "kDNSServiceErr_NoRouter";
+    case kDNSServiceErr_PollingMode:
+        return "kDNSServiceErr_PollingMode";
+    case kDNSServiceErr_Timeout:
+        return "kDNSServiceErr_Timeout";
+    default:
+        return "Unknown DNSService error code";
+    }
+}
+
+} // namespace Error
+} // namespace Mdns
+} // namespace chip
diff --git a/src/platform/Tizen/MdnsError.h b/src/platform/Tizen/MdnsError.h
new file mode 100644 (file)
index 0000000..3a2fc96
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *
+ *    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 "MdnsImpl.h"
+
+namespace chip {
+namespace Mdns {
+namespace Error {
+
+const char * ToString(DNSServiceErrorType errorCode);
+
+} // namespace Error
+} // namespace Mdns
+} // namespace chip
diff --git a/src/platform/Tizen/MdnsImpl.cpp b/src/platform/Tizen/MdnsImpl.cpp
new file mode 100644 (file)
index 0000000..fc4878e
--- /dev/null
@@ -0,0 +1,517 @@
+/*
+ *
+ *    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 "MdnsImpl.h"
+
+#include "MdnsError.h"
+
+#include <cstdio>
+#include <sstream>
+#include <string.h>
+#include <algorithm>
+
+#include <platform/CHIPDeviceLayer.h>
+#include <support/CHIPMem.h>
+#include <support/CodeUtils.h>
+#include <support/SafeInt.h>
+#include <support/logging/CHIPLogging.h>
+
+using namespace chip::Mdns;
+
+namespace {
+
+constexpr const char * kLocalDomain = "local.";
+constexpr const char * kProtocolTcp = "._tcp";
+constexpr const char * kProtocolUdp = "._udp";
+constexpr uint8_t kMdnsKeyMaxSize   = 32;
+
+bool IsSupportedProtocol(MdnsServiceProtocol protocol)
+{
+    return (protocol == MdnsServiceProtocol::kMdnsProtocolUdp) || (protocol == MdnsServiceProtocol::kMdnsProtocolTcp);
+}
+
+uint32_t GetInterfaceId(chip::Inet::InterfaceId interfaceId)
+{
+    return INET_NULL_INTERFACEID ? 0 : interfaceId;
+}
+
+std::string GetFullType(const char * type, MdnsServiceProtocol protocol)
+{
+    std::ostringstream typeBuilder;
+    typeBuilder << type;
+    typeBuilder << (protocol == MdnsServiceProtocol::kMdnsProtocolUdp ? kProtocolUdp : kProtocolTcp);
+    return typeBuilder.str();
+}
+
+} // namespace
+
+namespace chip {
+namespace Mdns {
+
+MdnsContexts MdnsContexts::sInstance;
+
+void MdnsContexts::Delete(GenericContext * context)
+{
+    if (context->type == ContextType::GetAddrInfo)
+    {
+        GetAddrInfoContext * addrInfoContext = reinterpret_cast<GetAddrInfoContext *>(context);
+        std::vector<TextEntry>::iterator textEntry;
+        for (textEntry = addrInfoContext->textEntries.begin(); textEntry != addrInfoContext->textEntries.end(); textEntry++)
+        {
+            free(const_cast<char *>(textEntry->mKey));
+            free(const_cast<uint8_t *>(textEntry->mData));
+        }
+    }
+
+    DNSServiceRefDeallocate(context->serviceRef);
+    chip::Platform::Delete(context);
+}
+
+MdnsContexts::~MdnsContexts()
+{
+    std::vector<GenericContext *>::const_iterator iter = mContexts.cbegin();
+    while (iter != mContexts.cend())
+    {
+        Delete(*iter);
+        mContexts.erase(iter);
+    }
+}
+
+CHIP_ERROR MdnsContexts::Add(GenericContext * context, DNSServiceRef sdRef)
+{
+    VerifyOrReturnError(context != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+    VerifyOrReturnError(sdRef != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+
+    context->serviceRef = sdRef;
+    mContexts.push_back(context);
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR MdnsContexts::Remove(GenericContext * context)
+{
+    bool found = false;
+
+    std::vector<GenericContext *>::const_iterator iter = mContexts.cbegin();
+    while (iter != mContexts.cend())
+    {
+        if (*iter != context)
+        {
+            iter++;
+            continue;
+        }
+
+        Delete(*iter);
+        mContexts.erase(iter);
+        found = true;
+        break;
+    }
+
+    return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND;
+}
+
+CHIP_ERROR MdnsContexts::Removes(ContextType type)
+{
+    bool found = false;
+
+    std::vector<GenericContext *>::const_iterator iter = mContexts.cbegin();
+    while (iter != mContexts.cend())
+    {
+        if ((*iter)->type != type)
+        {
+            iter++;
+            continue;
+        }
+
+        Delete(*iter);
+        mContexts.erase(iter);
+        found = true;
+    }
+
+    return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND;
+}
+
+CHIP_ERROR MdnsContexts::Get(ContextType type, GenericContext * context)
+{
+    bool found = false;
+    std::vector<GenericContext *>::iterator iter;
+
+    for (iter = mContexts.begin(); iter != mContexts.end(); iter++)
+    {
+        if ((*iter)->type == type)
+        {
+            context = *iter;
+            if (context != nullptr)
+                found   = true;
+
+            break;
+        }
+    }
+
+    return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND;
+}
+
+void MdnsContexts::PrepareSelect(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet, int & maxFd, timeval & timeout)
+{
+    std::vector<DNSServiceRef> serviceRefs(mContexts.size());
+    std::transform(mContexts.begin(), mContexts.end(), serviceRefs.begin(),
+                   [](GenericContext * context) { return context->serviceRef; });
+
+    std::vector<DNSServiceRef>::iterator iter;
+    for (iter = serviceRefs.begin(); iter != serviceRefs.end(); iter++)
+    {
+        int fd = DNSServiceRefSockFD(*iter);
+        FD_SET(fd, &readFdSet);
+        if (maxFd < fd)
+        {
+            maxFd = fd;
+        }
+    }
+}
+
+void MdnsContexts::HandleSelectResult(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet)
+{
+    std::vector<DNSServiceRef> serviceRefs(mContexts.size());
+    std::transform(mContexts.begin(), mContexts.end(), serviceRefs.begin(),
+                   [](GenericContext * context) { return context->serviceRef; });
+
+    std::vector<DNSServiceRef>::iterator iter;
+    for (iter = serviceRefs.begin(); iter != serviceRefs.end(); iter++)
+    {
+        int fd = DNSServiceRefSockFD(*iter);
+        if (FD_ISSET(fd, &readFdSet))
+        {
+            DNSServiceProcessResult(*iter);
+        }
+    }
+}
+
+CHIP_ERROR PopulateTextRecord(TXTRecordRef * record, char * buffer, uint16_t bufferLen, TextEntry * textEntries,
+                              size_t textEntrySize)
+{
+    VerifyOrReturnError(textEntrySize <= kMdnsTextMaxSize, CHIP_ERROR_INVALID_ARGUMENT);
+
+    DNSServiceErrorType err;
+    TXTRecordCreate(record, bufferLen, buffer);
+
+    for (size_t i = 0; i < textEntrySize; i++)
+    {
+        TextEntry entry = textEntries[i];
+        VerifyOrReturnError(chip::CanCastTo<uint8_t>(entry.mDataSize), CHIP_ERROR_INVALID_ARGUMENT);
+
+        err = TXTRecordSetValue(record, entry.mKey, static_cast<uint8_t>(entry.mDataSize), entry.mData);
+        VerifyOrReturnError(err == kDNSServiceErr_NoError, CHIP_ERROR_INVALID_ARGUMENT);
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+bool CheckForSuccess(GenericContext * context, const char * name, DNSServiceErrorType err, bool useCallback = false)
+{
+    if (context == nullptr)
+    {
+        ChipLogError(DeviceLayer, "%s (%s)", name, "Mdns context is null.");
+        return false;
+    }
+
+    if (kDNSServiceErr_NoError != err)
+    {
+        ChipLogError(DeviceLayer, "%s (%s)", name, Error::ToString(err));
+
+        if (useCallback)
+        {
+            switch (context->type)
+            {
+            case ContextType::Register:
+                // Nothing special to do. Maybe ChipMdnsPublishService should take a callback ?
+                break;
+            case ContextType::Browse: {
+                BrowseContext * browseContext = reinterpret_cast<BrowseContext *>(context);
+                browseContext->callback(browseContext->context, nullptr, 0, CHIP_ERROR_INTERNAL);
+                break;
+            }
+            case ContextType::Resolve: {
+                ResolveContext * resolveContext = reinterpret_cast<ResolveContext *>(context);
+                resolveContext->callback(resolveContext->context, nullptr, CHIP_ERROR_INTERNAL);
+                break;
+            }
+            case ContextType::GetAddrInfo: {
+                GetAddrInfoContext * resolveContext = reinterpret_cast<GetAddrInfoContext *>(context);
+                resolveContext->callback(resolveContext->context, nullptr, CHIP_ERROR_INTERNAL);
+                break;
+            }
+            }
+        }
+
+        if (CHIP_ERROR_KEY_NOT_FOUND == MdnsContexts::GetInstance().Remove(context))
+        {
+            chip::Platform::Delete(context);
+        }
+
+        return false;
+    }
+
+    return true;
+}
+
+static void OnRegister(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType err, const char * name, const char * type,
+                       const char * domain, void * context)
+{
+    RegisterContext * sdCtx = reinterpret_cast<RegisterContext *>(context);
+    VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err));
+
+    ChipLogDetail(DeviceLayer, "Mdns: %s name: %s, type: %s, domain: %s, flags: %d", __func__, name, type, domain, flags);
+};
+
+CHIP_ERROR Register(uint32_t interfaceId, const char * type, const char * name, uint16_t port, TXTRecordRef * recordRef)
+{
+    DNSServiceErrorType err;
+    DNSServiceRef sdRef;
+    RegisterContext * sdCtx = nullptr;
+
+    uint16_t recordLen          = TXTRecordGetLength(recordRef);
+    const void * recordBytesPtr = TXTRecordGetBytesPtr(recordRef);
+
+    if (CHIP_NO_ERROR == MdnsContexts::GetInstance().Get(ContextType::Register, sdCtx))
+    {
+        err = DNSServiceUpdateRecord(sdCtx->serviceRef, NULL, 0 /* flags */, recordLen, recordBytesPtr, 0 /* ttl */);
+        TXTRecordDeallocate(recordRef);
+        VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), CHIP_ERROR_INTERNAL);
+        return CHIP_NO_ERROR;
+    }
+
+    sdCtx = chip::Platform::New<RegisterContext>(nullptr);
+    err   = DNSServiceRegister(&sdRef, 0 /* flags */, interfaceId, name, type, kLocalDomain, NULL, port, recordLen, recordBytesPtr,
+                             OnRegister, sdCtx);
+    TXTRecordDeallocate(recordRef);
+
+    VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), CHIP_ERROR_INTERNAL);
+
+    return MdnsContexts::GetInstance().Add(sdCtx, sdRef);
+}
+
+void OnBrowseAdd(BrowseContext * context, const char * name, const char * type, const char * domain, uint32_t interfaceId)
+{
+    ChipLogDetail(DeviceLayer, "Mdns: %s  name: %s, type: %s, domain: %s, interface: %d", __func__, name, type, domain,
+                  interfaceId);
+
+    VerifyOrReturn(strcmp(kLocalDomain, domain) == 0);
+
+    char * tokens  = strdup(type);
+    char * regtype = strtok(tokens, ".");
+    free(tokens);
+
+    MdnsService service = {};
+    service.mInterface  = interfaceId;
+    service.mProtocol   = context->protocol;
+
+    strncpy(service.mName, name, sizeof(service.mName));
+    service.mName[kMdnsNameMaxSize] = 0;
+
+    strncpy(service.mType, regtype, sizeof(service.mType));
+    service.mType[kMdnsTypeMaxSize] = 0;
+
+    context->services.push_back(service);
+}
+
+void OnBrowseRemove(BrowseContext * context, const char * name, const char * type, const char * domain, uint32_t interfaceId)
+{
+    ChipLogDetail(DeviceLayer, "Mdns: %s  name: %s, type: %s, domain: %s, interface: %d", __func__, name, type, domain,
+                  interfaceId);
+
+    VerifyOrReturn(strcmp(kLocalDomain, domain) == 0);
+
+    std::remove_if(context->services.begin(), context->services.end(), [name, type, interfaceId](const MdnsService & service) {
+        return strcmp(name, service.mName) == 0 && type == GetFullType(service.mType, service.mProtocol) &&
+            service.mInterface == interfaceId;
+    });
+}
+
+static void OnBrowse(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceId, DNSServiceErrorType err, const char * name,
+                     const char * type, const char * domain, void * context)
+{
+    BrowseContext * sdCtx = reinterpret_cast<BrowseContext *>(context);
+    VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err, true));
+
+    (flags & kDNSServiceFlagsAdd) ? OnBrowseAdd(sdCtx, name, type, domain, interfaceId)
+                                  : OnBrowseRemove(sdCtx, name, type, domain, interfaceId);
+
+    if (!(flags & kDNSServiceFlagsMoreComing))
+    {
+        sdCtx->callback(sdCtx->context, sdCtx->services.data(), sdCtx->services.size(), CHIP_NO_ERROR);
+        MdnsContexts::GetInstance().Remove(sdCtx);
+    }
+}
+
+CHIP_ERROR Browse(void * context, MdnsBrowseCallback callback, uint32_t interfaceId, const char * type,
+                  MdnsServiceProtocol protocol)
+{
+    DNSServiceErrorType err;
+    DNSServiceRef sdRef;
+    BrowseContext * sdCtx;
+
+    sdCtx = chip::Platform::New<BrowseContext>(context, callback, protocol);
+    err   = DNSServiceBrowse(&sdRef, 0 /* flags */, interfaceId, type, kLocalDomain, OnBrowse, sdCtx);
+    VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), CHIP_ERROR_INTERNAL);
+
+    return MdnsContexts::GetInstance().Add(sdCtx, sdRef);
+}
+
+static void OnGetAddrInfo(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceId, DNSServiceErrorType err,
+                          const char * hostname, const struct sockaddr * address, uint32_t ttl, void * context)
+{
+    GetAddrInfoContext * sdCtx = reinterpret_cast<GetAddrInfoContext *>(context);
+    VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err, true));
+
+    ChipLogDetail(DeviceLayer, "Mdns: %s hostname:%s", __func__, hostname);
+
+    MdnsService service    = {};
+    service.mPort          = sdCtx->port;
+    service.mTextEntries   = sdCtx->textEntries.empty() ? nullptr : sdCtx->textEntries.data();
+    service.mTextEntrySize = sdCtx->textEntries.empty() ? 0 : sdCtx->textEntries.size();
+    service.mAddress.SetValue(chip::Inet::IPAddress::FromSockAddr(*address));
+
+    sdCtx->callback(sdCtx->context, &service, CHIP_NO_ERROR);
+    MdnsContexts::GetInstance().Remove(sdCtx);
+}
+
+CHIP_ERROR GetAddrInfo(void * context, MdnsResolveCallback callback, uint32_t interfaceId, const char * hostname, uint16_t port,
+                       uint16_t txtLen, const unsigned char * txtRecord)
+{
+    DNSServiceErrorType err;
+    DNSServiceRef sdRef;
+    GetAddrInfoContext * sdCtx;
+
+    sdCtx = chip::Platform::New<GetAddrInfoContext>(context, callback, port);
+
+    char key[kMdnsKeyMaxSize];
+    char value[kMdnsTextMaxSize];
+    uint8_t valueLen;
+    const void * valuePtr;
+
+    uint16_t recordCount = TXTRecordGetCount(txtLen, txtRecord);
+    for (uint16_t i = 0; i < recordCount; i++)
+    {
+        err = TXTRecordGetItemAtIndex(txtLen, txtRecord, i, kMdnsKeyMaxSize, key, &valueLen, &valuePtr);
+        VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err, true), CHIP_ERROR_INTERNAL);
+
+        strncpy(value, reinterpret_cast<const char *>(valuePtr), valueLen);
+        value[valueLen] = 0;
+
+        sdCtx->textEntries.push_back(TextEntry{ strdup(key), reinterpret_cast<const uint8_t *>(strdup(value)), valueLen });
+    }
+
+    err = DNSServiceGetAddrInfo(&sdRef, 0 /* flags */, interfaceId, kDNSServiceProtocol_IPv4, hostname, OnGetAddrInfo, sdCtx);
+    VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err, true), CHIP_ERROR_INTERNAL);
+
+    return MdnsContexts::GetInstance().Add(sdCtx, sdRef);
+}
+
+static void OnResolve(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceId, DNSServiceErrorType err,
+                      const char * fullname, const char * hostname, uint16_t port, uint16_t txtLen, const unsigned char * txtRecord,
+                      void * context)
+{
+    ResolveContext * sdCtx = reinterpret_cast<ResolveContext *>(context);
+    VerifyOrReturn(CheckForSuccess(sdCtx, __func__, err, true));
+
+    GetAddrInfo(sdCtx->context, sdCtx->callback, interfaceId, hostname, port, txtLen, txtRecord);
+    MdnsContexts::GetInstance().Remove(sdCtx);
+}
+
+CHIP_ERROR Resolve(void * context, MdnsResolveCallback callback, uint32_t interfaceId, const char * type, const char * name)
+{
+    DNSServiceErrorType err;
+    DNSServiceRef sdRef;
+    ResolveContext * sdCtx;
+
+    sdCtx = chip::Platform::New<ResolveContext>(context, callback);
+    err   = DNSServiceResolve(&sdRef, 0 /* flags */, interfaceId, name, type, kLocalDomain, OnResolve, sdCtx);
+    VerifyOrReturnError(CheckForSuccess(sdCtx, __func__, err), CHIP_ERROR_INTERNAL);
+
+    return MdnsContexts::GetInstance().Add(sdCtx, sdRef);
+}
+
+CHIP_ERROR ChipMdnsInit(MdnsAsyncReturnCallback successCallback, MdnsAsyncReturnCallback errorCallback, void * context)
+{
+    VerifyOrReturnError(successCallback != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+    VerifyOrReturnError(errorCallback != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+
+    successCallback(context, CHIP_NO_ERROR);
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR ChipMdnsSetHostname(const char * hostname)
+{
+    MdnsContexts::GetInstance().SetHostname(hostname);
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR ChipMdnsPublishService(const MdnsService * service)
+{
+    VerifyOrReturnError(service != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+    VerifyOrReturnError(IsSupportedProtocol(service->mProtocol), CHIP_ERROR_INVALID_ARGUMENT);
+
+    std::string regtype  = GetFullType(service->mType, service->mProtocol);
+    uint32_t interfaceId = GetInterfaceId(service->mInterface);
+
+    TXTRecordRef record;
+    char buffer[kMdnsTextMaxSize];
+    ReturnErrorOnFailure(PopulateTextRecord(&record, buffer, sizeof(buffer), service->mTextEntries, service->mTextEntrySize));
+
+    return Register(interfaceId, regtype.c_str(), service->mName, service->mPort, &record);
+}
+
+CHIP_ERROR ChipMdnsStopPublish()
+{
+    return MdnsContexts::GetInstance().Removes(ContextType::Register);
+}
+
+CHIP_ERROR ChipMdnsBrowse(const char * type, MdnsServiceProtocol protocol, chip::Inet::IPAddressType addressType,
+                          chip::Inet::InterfaceId interface, MdnsBrowseCallback callback, void * context)
+{
+    VerifyOrReturnError(type != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+    VerifyOrReturnError(callback != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+    VerifyOrReturnError(IsSupportedProtocol(protocol), CHIP_ERROR_INVALID_ARGUMENT);
+
+    std::string regtype  = GetFullType(type, protocol);
+    uint32_t interfaceId = GetInterfaceId(interface);
+
+    return Browse(context, callback, interfaceId, regtype.c_str(), protocol);
+}
+
+CHIP_ERROR ChipMdnsResolve(MdnsService * service, chip::Inet::InterfaceId interface, MdnsResolveCallback callback, void * context)
+{
+    VerifyOrReturnError(service != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
+    VerifyOrReturnError(IsSupportedProtocol(service->mProtocol), CHIP_ERROR_INVALID_ARGUMENT);
+
+    std::string regtype  = GetFullType(service->mType, service->mProtocol);
+    uint32_t interfaceId = GetInterfaceId(service->mInterface);
+
+    return Resolve(context, callback, interfaceId, regtype.c_str(), service->mName);
+}
+
+void UpdateMdnsDataset(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet, int & maxFd, timeval & timeout)
+{
+    MdnsContexts::GetInstance().PrepareSelect(readFdSet, writeFdSet, errorFdSet, maxFd, timeout);
+}
+
+void ProcessMdns(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet)
+{
+    MdnsContexts::GetInstance().HandleSelectResult(readFdSet, writeFdSet, errorFdSet);
+}
+
+} // namespace Mdns
+} // namespace chip
diff --git a/src/platform/Tizen/MdnsImpl.h b/src/platform/Tizen/MdnsImpl.h
new file mode 100644 (file)
index 0000000..287e896
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *
+ *    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 <dns_sd.h>
+#include <lib/mdns/platform/Mdns.h>
+#include <string>
+#include <vector>
+
+namespace chip {
+namespace Mdns {
+
+enum class ContextType
+{
+    Register,
+    Browse,
+    Resolve,
+    GetAddrInfo,
+};
+
+struct GenericContext
+{
+    ContextType type;
+    void * context;
+    DNSServiceRef serviceRef;
+};
+
+struct RegisterContext : public GenericContext
+{
+    RegisterContext(void * cbContext)
+    {
+        type    = ContextType::Register;
+        context = cbContext;
+    }
+};
+
+struct BrowseContext : public GenericContext
+{
+    MdnsBrowseCallback callback;
+    std::vector<MdnsService> services;
+    MdnsServiceProtocol protocol;
+
+    BrowseContext(void * cbContext, MdnsBrowseCallback cb, MdnsServiceProtocol cbContextProtocol)
+    {
+        type     = ContextType::Browse;
+        context  = cbContext;
+        callback = cb;
+        protocol = cbContextProtocol;
+    }
+};
+
+struct ResolveContext : public GenericContext
+{
+    MdnsResolveCallback callback;
+
+    ResolveContext(void * cbContext, MdnsResolveCallback cb)
+    {
+        type     = ContextType::Resolve;
+        context  = cbContext;
+        callback = cb;
+    }
+};
+
+struct GetAddrInfoContext : public GenericContext
+{
+    MdnsResolveCallback callback;
+    std::vector<TextEntry> textEntries;
+    uint16_t port;
+
+    GetAddrInfoContext(void * cbContext, MdnsResolveCallback cb, uint16_t cbContextPort)
+    {
+        type     = ContextType::GetAddrInfo;
+        context  = cbContext;
+        callback = cb;
+        port     = cbContextPort;
+    }
+};
+
+class MdnsContexts
+{
+public:
+    MdnsContexts(const MdnsContexts &) = delete;
+    MdnsContexts & operator=(const MdnsContexts &) = delete;
+    ~MdnsContexts();
+    static MdnsContexts & GetInstance() { return sInstance; }
+
+    void PrepareSelect(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet, int & maxFd, timeval & timeout);
+    void HandleSelectResult(fd_set & readFdSet, fd_set & writeFdSet, fd_set & errorFdSet);
+
+    CHIP_ERROR Add(GenericContext * context, DNSServiceRef sdRef);
+    CHIP_ERROR Remove(GenericContext * context);
+    CHIP_ERROR Removes(ContextType type);
+    CHIP_ERROR Get(ContextType type, GenericContext * context);
+
+    void SetHostname(const char * name) { mHostname = name; }
+    const char * GetHostname() { return mHostname.c_str(); }
+
+private:
+    MdnsContexts(){};
+    static MdnsContexts sInstance;
+    std::string mHostname;
+
+    void Delete(GenericContext * context);
+    std::vector<GenericContext *> mContexts;
+};
+
+} // namespace Mdns
+} // namespace chip
diff --git a/src/platform/Tizen/PlatformManagerImpl.cpp b/src/platform/Tizen/PlatformManagerImpl.cpp
new file mode 100644 (file)
index 0000000..b45e6d0
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ *
+ *    Copyright (c) 2020 Project CHIP Authors
+ *    Copyright (c) 2018 Nest Labs, Inc.
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *          Provides an implementation of the PlatformManager object
+ *          for Linux platforms.
+ */
+
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+
+#include <platform/PlatformManager.h>
+#include <platform/internal/GenericPlatformManagerImpl_POSIX.cpp>
+#include <support/CHIPMem.h>
+#include <support/logging/CHIPLogging.h>
+
+#include <thread>
+
+#include <arpa/inet.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+namespace chip {
+namespace DeviceLayer {
+
+PlatformManagerImpl PlatformManagerImpl::sInstance;
+
+#if CHIP_WITH_GIO
+static void GDBus_Thread()
+{
+    GMainLoop * loop = g_main_loop_new(nullptr, false);
+
+    g_main_loop_run(loop);
+    g_main_loop_unref(loop);
+}
+#endif
+
+void PlatformManagerImpl::WiFIIPChangeListener()
+{
+    int sock;
+    if ((sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
+    {
+        ChipLogError(DeviceLayer, "Failed to init netlink socket for ip addresses.");
+        return;
+    }
+
+    struct sockaddr_nl addr;
+    memset(&addr, 0, sizeof(addr));
+    addr.nl_family = AF_NETLINK;
+    addr.nl_groups = RTMGRP_IPV4_IFADDR;
+
+    if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) == -1)
+    {
+        ChipLogError(DeviceLayer, "Failed to bind netlink socket for ip addresses.");
+        return;
+    }
+
+    ssize_t len;
+    char buffer[4096];
+    for (struct nlmsghdr * header = reinterpret_cast<struct nlmsghdr *>(buffer); (len = recv(sock, header, sizeof(buffer), 0)) > 0;)
+    {
+        for (struct nlmsghdr * messageHeader = header;
+             (NLMSG_OK(messageHeader, static_cast<uint32_t>(len))) && (messageHeader->nlmsg_type != NLMSG_DONE);
+             messageHeader = NLMSG_NEXT(messageHeader, len))
+        {
+            if (header->nlmsg_type == RTM_NEWADDR)
+            {
+                struct ifaddrmsg * addressMessage = (struct ifaddrmsg *) NLMSG_DATA(header);
+                struct rtattr * routeInfo         = IFA_RTA(addressMessage);
+                size_t rtl                        = IFA_PAYLOAD(header);
+
+                while (rtl && RTA_OK(routeInfo, rtl))
+                {
+                    if (routeInfo->rta_type == IFA_LOCAL)
+                    {
+                        char name[IFNAMSIZ];
+                        ChipDeviceEvent event;
+                        if_indextoname(addressMessage->ifa_index, name);
+                        if (strcmp(name, CHIP_DEVICE_CONFIG_WIFI_STATION_IF_NAME) != 0)
+                        {
+                            continue;
+                        }
+
+                        event.Type                            = DeviceEventType::kInternetConnectivityChange;
+                        event.InternetConnectivityChange.IPv4 = kConnectivity_Established;
+                        event.InternetConnectivityChange.IPv6 = kConnectivity_NoChange;
+                        inet_ntop(AF_INET, RTA_DATA(routeInfo), event.InternetConnectivityChange.address,
+                                  sizeof(event.InternetConnectivityChange.address));
+
+                        ChipLogDetail(DeviceLayer, "Got IP address on interface: %s IP: %s", name,
+                                      event.InternetConnectivityChange.address);
+
+                        PlatformMgr().LockChipStack();
+                        PlatformMgr().PostEvent(&event);
+                        PlatformMgr().UnlockChipStack();
+                    }
+                    routeInfo = RTA_NEXT(routeInfo, rtl);
+                }
+            }
+        }
+    }
+}
+
+CHIP_ERROR PlatformManagerImpl::_InitChipStack()
+{
+    CHIP_ERROR err;
+
+#if CHIP_WITH_GIO
+    GError * error = nullptr;
+
+    this->mpGDBusConnection = UniqueGDBusConnection(g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error));
+
+    std::thread gdbusThread(GDBus_Thread);
+    gdbusThread.detach();
+#endif
+
+    std::thread wifiIPThread(WiFIIPChangeListener);
+    wifiIPThread.detach();
+
+    // Initialize the configuration system.
+    err = Internal::PosixConfig::Init();
+    SuccessOrExit(err);
+    // Call _InitChipStack() on the generic implementation base class
+    // to finish the initialization process.
+    err = Internal::GenericPlatformManagerImpl_POSIX<PlatformManagerImpl>::_InitChipStack();
+    SuccessOrExit(err);
+
+exit:
+    return err;
+}
+
+#if CHIP_WITH_GIO
+GDBusConnection * PlatformManagerImpl::GetGDBusConnection()
+{
+    return this->mpGDBusConnection.get();
+}
+#endif
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/PlatformManagerImpl.h b/src/platform/Tizen/PlatformManagerImpl.h
new file mode 100644 (file)
index 0000000..be1757c
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ *
+ *    Copyright (c) 2020 Project CHIP Authors
+ *    Copyright (c) 2018 Nest Labs, Inc.
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *          Provides an implementation of the PlatformManager object.
+ */
+
+#pragma once
+
+#include <memory>
+#include <platform/internal/GenericPlatformManagerImpl_POSIX.h>
+
+#if CHIP_WITH_GIO
+#include <gio/gio.h>
+#endif
+
+namespace chip {
+namespace DeviceLayer {
+
+/**
+ * Concrete implementation of the PlatformManager singleton object for Linux platforms.
+ */
+class PlatformManagerImpl final : public PlatformManager, public Internal::GenericPlatformManagerImpl_POSIX<PlatformManagerImpl>
+{
+    // Allow the PlatformManager interface class to delegate method calls to
+    // the implementation methods provided by this class.
+    friend PlatformManager;
+
+    // Allow the generic implementation base class to call helper methods on
+    // this class.
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+    friend Internal::GenericPlatformManagerImpl_POSIX<PlatformManagerImpl>;
+#endif
+
+public:
+    // ===== Platform-specific members that may be accessed directly by the application.
+#if CHIP_WITH_GIO
+    GDBusConnection * GetGDBusConnection();
+#endif
+
+private:
+    // ===== Methods that implement the PlatformManager abstract interface.
+
+    CHIP_ERROR _InitChipStack();
+
+    // ===== Members for internal use by the following friends.
+
+    friend PlatformManager & PlatformMgr();
+    friend PlatformManagerImpl & PlatformMgrImpl();
+    friend class Internal::BLEManagerImpl;
+
+    static PlatformManagerImpl sInstance;
+
+    // The temporary hack for getting IP address change on linux for network provisioning in the rendezvous session.
+    // This should be removed or find a better place once we depercate the rendezvous session.
+    static void WiFIIPChangeListener();
+
+#if CHIP_WITH_GIO
+    struct GDBusConnectionDeleter
+    {
+        void operator()(GDBusConnection * conn) { g_object_unref(conn); }
+    };
+    using UniqueGDBusConnection = std::unique_ptr<GDBusConnection, GDBusConnectionDeleter>;
+    UniqueGDBusConnection mpGDBusConnection;
+#endif
+};
+
+/**
+ * Returns the public interface of the PlatformManager singleton object.
+ *
+ * chip applications should use this to access features of the PlatformManager object
+ * that are common to all platforms.
+ */
+inline PlatformManager & PlatformMgr()
+{
+    return PlatformManagerImpl::sInstance;
+}
+
+/**
+ * Returns the platform-specific implementation of the PlatformManager singleton object.
+ *
+ * chip applications can use this to gain access to features of the PlatformManager
+ * that are specific to the ESP32 platform.
+ */
+inline PlatformManagerImpl & PlatformMgrImpl()
+{
+    return PlatformManagerImpl::sInstance;
+}
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/PosixConfig.cpp b/src/platform/Tizen/PosixConfig.cpp
new file mode 100644 (file)
index 0000000..ebe9eb1
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ *
+ *    Copyright (c) 2020 Project CHIP Authors
+ *    Copyright (c) 2019-2020 Google LLC.
+ *    Copyright (c) 2018 Nest Labs, Inc.
+ *    All rights reserved.
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *          Utilities for interacting with multiple file partitions and maps
+ *          key-value config calls to the correct partition.
+ */
+
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+#include <platform/internal/testing/ConfigUnitTest.h>
+
+#include <core/CHIPEncoding.h>
+#include <platform/Linux/CHIPLinuxStorage.h>
+#include <platform/Linux/PosixConfig.h>
+#include <support/CodeUtils.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+static ChipLinuxStorage gChipLinuxFactoryStorage;
+static ChipLinuxStorage gChipLinuxConfigStorage;
+static ChipLinuxStorage gChipLinuxCountersStorage;
+
+// *** CAUTION ***: Changing the names or namespaces of these values will *break* existing devices.
+
+// NVS namespaces used to store device configuration information.
+const char PosixConfig::kConfigNamespace_ChipFactory[]  = "chip-factory";
+const char PosixConfig::kConfigNamespace_ChipConfig[]   = "chip-config";
+const char PosixConfig::kConfigNamespace_ChipCounters[] = "chip-counters";
+
+// Keys stored in the Chip-factory namespace
+const PosixConfig::Key PosixConfig::kConfigKey_SerialNum           = { kConfigNamespace_ChipFactory, "serial-num" };
+const PosixConfig::Key PosixConfig::kConfigKey_MfrDeviceId         = { kConfigNamespace_ChipFactory, "device-id" };
+const PosixConfig::Key PosixConfig::kConfigKey_MfrDeviceCert       = { kConfigNamespace_ChipFactory, "device-cert" };
+const PosixConfig::Key PosixConfig::kConfigKey_MfrDeviceICACerts   = { kConfigNamespace_ChipFactory, "device-ca-certs" };
+const PosixConfig::Key PosixConfig::kConfigKey_MfrDevicePrivateKey = { kConfigNamespace_ChipFactory, "device-key" };
+const PosixConfig::Key PosixConfig::kConfigKey_ProductRevision     = { kConfigNamespace_ChipFactory, "product-rev" };
+const PosixConfig::Key PosixConfig::kConfigKey_ManufacturingDate   = { kConfigNamespace_ChipFactory, "mfg-date" };
+const PosixConfig::Key PosixConfig::kConfigKey_SetupPinCode        = { kConfigNamespace_ChipFactory, "pin-code" };
+const PosixConfig::Key PosixConfig::kConfigKey_SetupDiscriminator  = { kConfigNamespace_ChipFactory, "discriminator" };
+
+// Keys stored in the Chip-config namespace
+const PosixConfig::Key PosixConfig::kConfigKey_FabricId                    = { kConfigNamespace_ChipConfig, "fabric-id" };
+const PosixConfig::Key PosixConfig::kConfigKey_ServiceConfig               = { kConfigNamespace_ChipConfig, "service-config" };
+const PosixConfig::Key PosixConfig::kConfigKey_PairedAccountId             = { kConfigNamespace_ChipConfig, "account-id" };
+const PosixConfig::Key PosixConfig::kConfigKey_ServiceId                   = { kConfigNamespace_ChipConfig, "service-id" };
+const PosixConfig::Key PosixConfig::kConfigKey_FabricSecret                = { kConfigNamespace_ChipConfig, "fabric-secret" };
+const PosixConfig::Key PosixConfig::kConfigKey_GroupKeyIndex               = { kConfigNamespace_ChipConfig, "group-key-index" };
+const PosixConfig::Key PosixConfig::kConfigKey_LastUsedEpochKeyId          = { kConfigNamespace_ChipConfig, "last-ek-id" };
+const PosixConfig::Key PosixConfig::kConfigKey_FailSafeArmed               = { kConfigNamespace_ChipConfig, "fail-safe-armed" };
+const PosixConfig::Key PosixConfig::kConfigKey_WiFiStationSecType          = { kConfigNamespace_ChipConfig, "sta-sec-type" };
+const PosixConfig::Key PosixConfig::kConfigKey_OperationalDeviceId         = { kConfigNamespace_ChipConfig, "op-device-id" };
+const PosixConfig::Key PosixConfig::kConfigKey_OperationalDeviceCert       = { kConfigNamespace_ChipConfig, "op-device-cert" };
+const PosixConfig::Key PosixConfig::kConfigKey_OperationalDeviceICACerts   = { kConfigNamespace_ChipConfig, "op-device-ca-certs" };
+const PosixConfig::Key PosixConfig::kConfigKey_OperationalDevicePrivateKey = { kConfigNamespace_ChipConfig, "op-device-key" };
+
+// Prefix used for NVS keys that contain Chip group encryption keys.
+const char PosixConfig::kGroupKeyNamePrefix[] = "gk-";
+
+ChipLinuxStorage * PosixConfig::GetStorageForNamespace(Key key)
+{
+    if (strcmp(key.Namespace, kConfigNamespace_ChipFactory) == 0)
+        return &gChipLinuxFactoryStorage;
+
+    if (strcmp(key.Namespace, kConfigNamespace_ChipConfig) == 0)
+        return &gChipLinuxConfigStorage;
+
+    if (strcmp(key.Namespace, kConfigNamespace_ChipCounters) == 0)
+        return &gChipLinuxCountersStorage;
+
+    return nullptr;
+}
+
+CHIP_ERROR PosixConfig::Init()
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+    return err;
+}
+
+CHIP_ERROR PosixConfig::ReadConfigValue(Key key, bool & val)
+{
+    CHIP_ERROR err;
+    ChipLinuxStorage * storage;
+    uint32_t intVal;
+
+    storage = GetStorageForNamespace(key);
+    VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
+
+    err = storage->ReadValue(key.Name, intVal);
+    if (err == CHIP_ERROR_KEY_NOT_FOUND)
+    {
+        err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
+    }
+    SuccessOrExit(err);
+
+    val = (intVal != 0);
+
+exit:
+    return err;
+}
+
+CHIP_ERROR PosixConfig::ReadConfigValue(Key key, uint32_t & val)
+{
+    CHIP_ERROR err;
+    ChipLinuxStorage * storage;
+
+    storage = GetStorageForNamespace(key);
+    VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
+
+    err = storage->ReadValue(key.Name, val);
+    if (err == CHIP_ERROR_KEY_NOT_FOUND)
+    {
+        err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
+    }
+    SuccessOrExit(err);
+
+exit:
+    return err;
+}
+
+CHIP_ERROR PosixConfig::ReadConfigValue(Key key, uint64_t & val)
+{
+    CHIP_ERROR err;
+    ChipLinuxStorage * storage;
+
+    storage = GetStorageForNamespace(key);
+    VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
+
+    // Special case the MfrDeviceId value, optionally allowing it to be read as a blob containing
+    // a 64-bit big-endian integer, instead of a u64 value.
+    if (key == kConfigKey_MfrDeviceId)
+    {
+        uint8_t deviceIdBytes[sizeof(uint64_t)];
+        size_t deviceIdLen = sizeof(deviceIdBytes);
+        size_t deviceIdOutLen;
+        err = storage->ReadValueBin(key.Name, deviceIdBytes, deviceIdLen, deviceIdOutLen);
+        if (err == CHIP_NO_ERROR)
+        {
+            VerifyOrExit(deviceIdOutLen == sizeof(deviceIdBytes), err = CHIP_ERROR_INCORRECT_STATE);
+            val = Encoding::BigEndian::Get64(deviceIdBytes);
+            ExitNow();
+        }
+    }
+
+    err = storage->ReadValue(key.Name, val);
+    if (err == CHIP_ERROR_KEY_NOT_FOUND)
+    {
+        err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
+    }
+    SuccessOrExit(err);
+
+exit:
+    return err;
+}
+
+CHIP_ERROR PosixConfig::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen)
+{
+    CHIP_ERROR err;
+    ChipLinuxStorage * storage;
+
+    storage = GetStorageForNamespace(key);
+    VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
+
+    err = storage->ReadValueStr(key.Name, buf, bufSize, outLen);
+    if (err == CHIP_ERROR_KEY_NOT_FOUND)
+    {
+        outLen = 0;
+        err    = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
+    }
+    else if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
+    {
+        err = (buf == nullptr) ? CHIP_NO_ERROR : CHIP_ERROR_BUFFER_TOO_SMALL;
+    }
+    SuccessOrExit(err);
+
+exit:
+    return err;
+}
+
+CHIP_ERROR PosixConfig::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen)
+{
+    CHIP_ERROR err;
+    ChipLinuxStorage * storage;
+
+    storage = GetStorageForNamespace(key);
+    VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
+
+    err = storage->ReadValueBin(key.Name, buf, bufSize, outLen);
+    if (err == CHIP_ERROR_KEY_NOT_FOUND)
+    {
+        outLen = 0;
+        err    = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
+    }
+    else if (err == CHIP_ERROR_BUFFER_TOO_SMALL)
+    {
+        err = (buf == nullptr) ? CHIP_NO_ERROR : CHIP_ERROR_BUFFER_TOO_SMALL;
+    }
+    SuccessOrExit(err);
+
+exit:
+    return err;
+}
+
+CHIP_ERROR PosixConfig::WriteConfigValue(Key key, bool val)
+{
+    CHIP_ERROR err;
+    ChipLinuxStorage * storage;
+
+    storage = GetStorageForNamespace(key);
+    VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
+
+    err = storage->WriteValue(key.Name, val);
+    SuccessOrExit(err);
+
+    // Commit the value to the persistent store.
+    err = storage->Commit();
+    SuccessOrExit(err);
+
+    ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %s", key.Namespace, key.Name, val ? "true" : "false");
+
+exit:
+    return err;
+}
+
+CHIP_ERROR PosixConfig::WriteConfigValue(Key key, uint32_t val)
+{
+    CHIP_ERROR err;
+    ChipLinuxStorage * storage;
+
+    storage = GetStorageForNamespace(key);
+    VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
+
+    err = storage->WriteValue(key.Name, val);
+    SuccessOrExit(err);
+
+    // Commit the value to the persistent store.
+    err = storage->Commit();
+    SuccessOrExit(err);
+
+    ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %" PRIu32 " (0x%" PRIX32 ")", key.Namespace, key.Name, val, val);
+
+exit:
+    return err;
+}
+
+CHIP_ERROR PosixConfig::WriteConfigValue(Key key, uint64_t val)
+{
+    CHIP_ERROR err;
+    ChipLinuxStorage * storage;
+
+    storage = GetStorageForNamespace(key);
+    VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
+
+    err = storage->WriteValue(key.Name, val);
+    SuccessOrExit(err);
+
+    // Commit the value to the persistent store.
+    err = storage->Commit();
+    SuccessOrExit(err);
+
+    ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %" PRIu64 " (0x%" PRIX64 ")", key.Namespace, key.Name, val, val);
+
+exit:
+    return err;
+}
+
+CHIP_ERROR PosixConfig::WriteConfigValueStr(Key key, const char * str)
+{
+    CHIP_ERROR err;
+    ChipLinuxStorage * storage;
+
+    if (str != nullptr)
+    {
+        storage = GetStorageForNamespace(key);
+        VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
+
+        err = storage->WriteValueStr(key.Name, str);
+        SuccessOrExit(err);
+
+        // Commit the value to the persistent store.
+        err = storage->Commit();
+        SuccessOrExit(err);
+
+        ChipLogProgress(DeviceLayer, "NVS set: %s/%s = \"%s\"", key.Namespace, key.Name, str);
+    }
+
+    else
+    {
+        err = ClearConfigValue(key);
+        SuccessOrExit(err);
+    }
+
+exit:
+    return err;
+}
+
+CHIP_ERROR PosixConfig::WriteConfigValueStr(Key key, const char * str, size_t strLen)
+{
+#if CHIP_CONFIG_MEMORY_MGMT_MALLOC
+    CHIP_ERROR err;
+    char * strCopy = nullptr;
+
+    if (str != nullptr)
+    {
+        strCopy = strndup(str, strLen);
+        VerifyOrExit(strCopy != nullptr, err = CHIP_ERROR_NO_MEMORY);
+    }
+
+    err = PosixConfig::WriteConfigValueStr(key, strCopy);
+
+exit:
+    if (strCopy != nullptr)
+    {
+        free(strCopy);
+    }
+    return err;
+#else
+#error "Unsupported CHIP_CONFIG_MEMORY_MGMT configuration"
+#endif
+}
+
+CHIP_ERROR PosixConfig::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen)
+{
+    CHIP_ERROR err;
+    ChipLinuxStorage * storage;
+
+    if (data != nullptr)
+    {
+        storage = GetStorageForNamespace(key);
+        VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
+
+        err = storage->WriteValueBin(key.Name, data, dataLen);
+        SuccessOrExit(err);
+
+        // Commit the value to the persistent store.
+        err = storage->Commit();
+        SuccessOrExit(err);
+
+        ChipLogProgress(DeviceLayer, "NVS set: %s/%s = (blob length %" PRId32 ")", key.Namespace, key.Name, dataLen);
+    }
+    else
+    {
+        err = ClearConfigValue(key);
+        SuccessOrExit(err);
+    }
+
+exit:
+    return err;
+}
+
+CHIP_ERROR PosixConfig::ClearConfigValue(Key key)
+{
+    CHIP_ERROR err;
+    ChipLinuxStorage * storage;
+
+    storage = GetStorageForNamespace(key);
+    VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
+
+    err = storage->ClearValue(key.Name);
+    if (err == CHIP_ERROR_KEY_NOT_FOUND)
+    {
+        ExitNow(err = CHIP_NO_ERROR);
+    }
+    SuccessOrExit(err);
+
+    // Commit the value to the persistent store.
+    err = storage->Commit();
+    SuccessOrExit(err);
+
+    ChipLogProgress(DeviceLayer, "NVS erase: %s/%s", key.Namespace, key.Name);
+
+exit:
+    return err;
+}
+
+bool PosixConfig::ConfigValueExists(Key key)
+{
+    ChipLinuxStorage * storage;
+
+    storage = GetStorageForNamespace(key);
+    if (storage == nullptr)
+        return false;
+
+    return storage->HasValue(key.Name);
+}
+
+CHIP_ERROR PosixConfig::EnsureNamespace(const char * ns)
+{
+    CHIP_ERROR err             = CHIP_NO_ERROR;
+    ChipLinuxStorage * storage = nullptr;
+
+    if (strcmp(ns, kConfigNamespace_ChipFactory) == 0)
+    {
+        storage = &gChipLinuxFactoryStorage;
+        err     = storage->Init(CHIP_DEFAULT_FACTORY_PATH);
+    }
+    else if (strcmp(ns, kConfigNamespace_ChipConfig) == 0)
+    {
+        storage = &gChipLinuxConfigStorage;
+        err     = storage->Init(CHIP_DEFAULT_CONFIG_PATH);
+    }
+    else if (strcmp(ns, kConfigNamespace_ChipCounters) == 0)
+    {
+        storage = &gChipLinuxCountersStorage;
+        err     = storage->Init(CHIP_DEFAULT_DATA_PATH);
+    }
+
+    SuccessOrExit(err);
+
+exit:
+    return err;
+}
+
+CHIP_ERROR PosixConfig::ClearNamespace(const char * ns)
+{
+    CHIP_ERROR err             = CHIP_NO_ERROR;
+    ChipLinuxStorage * storage = nullptr;
+
+    if (strcmp(ns, kConfigNamespace_ChipConfig) == 0)
+    {
+        storage = &gChipLinuxConfigStorage;
+    }
+    else if (strcmp(ns, kConfigNamespace_ChipCounters) == 0)
+    {
+        storage = &gChipLinuxCountersStorage;
+    }
+
+    VerifyOrExit(storage != nullptr, err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND);
+
+    err = storage->ClearAll();
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(DeviceLayer, "Storage ClearAll failed: %s", ErrorStr(err));
+    }
+    SuccessOrExit(err);
+
+    err = storage->Commit();
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(DeviceLayer, "Storage Commit failed: %s", ErrorStr(err));
+    }
+
+exit:
+    return err;
+}
+
+CHIP_ERROR PosixConfig::FactoryResetConfig()
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+    ChipLinuxStorage * storage;
+
+    ChipLogProgress(DeviceLayer, "Performing factory reset");
+
+    storage = &gChipLinuxConfigStorage;
+    if (storage == nullptr)
+    {
+        ChipLogError(DeviceLayer, "Storage get failed");
+        err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
+    }
+    SuccessOrExit(err);
+
+    err = storage->ClearAll();
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(DeviceLayer, "Storage ClearAll failed: %s", ErrorStr(err));
+    }
+    SuccessOrExit(err);
+
+    err = storage->Commit();
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(DeviceLayer, "Storage Commit failed: %s", ErrorStr(err));
+    }
+
+exit:
+    return err;
+}
+
+void PosixConfig::RunConfigUnitTest()
+{
+    // Run common unit test.
+    ::chip::DeviceLayer::Internal::RunConfigUnitTest<PosixConfig>();
+}
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/PosixConfig.h b/src/platform/Tizen/PosixConfig.h
new file mode 100644 (file)
index 0000000..bac6963
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *
+ *    Copyright (c) 2020 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.
+ */
+
+/**
+ *    @file
+ *          Utilities for accessing persisted device configuration on
+ *          Linux platforms.
+ */
+
+#pragma once
+
+#include <functional>
+#include <inttypes.h>
+
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+class ChipLinuxStorage;
+
+/**
+ * Provides functions and definitions for accessing device configuration information on the Posix.
+ *
+ * This class is designed to be mixed-in to concrete implementation classes as a means to
+ * provide access to configuration information to generic base classes.
+ */
+class PosixConfig
+{
+public:
+    struct Key;
+
+    // Maximum length of an NVS key name.
+    static constexpr size_t kMaxConfigKeyNameLength = 15;
+
+    // NVS namespaces used to store device configuration information.
+    static const char kConfigNamespace_ChipFactory[];
+    static const char kConfigNamespace_ChipConfig[];
+    static const char kConfigNamespace_ChipCounters[];
+
+    // Key definitions for well-known keys.
+    static const Key kConfigKey_SerialNum;
+    static const Key kConfigKey_MfrDeviceId;
+    static const Key kConfigKey_MfrDeviceCert;
+    static const Key kConfigKey_MfrDeviceICACerts;
+    static const Key kConfigKey_MfrDevicePrivateKey;
+    static const Key kConfigKey_ProductRevision;
+    static const Key kConfigKey_ManufacturingDate;
+    static const Key kConfigKey_SetupPinCode;
+    static const Key kConfigKey_FabricId;
+    static const Key kConfigKey_ServiceConfig;
+    static const Key kConfigKey_PairedAccountId;
+    static const Key kConfigKey_ServiceId;
+    static const Key kConfigKey_FabricSecret;
+    static const Key kConfigKey_GroupKeyIndex;
+    static const Key kConfigKey_LastUsedEpochKeyId;
+    static const Key kConfigKey_FailSafeArmed;
+    static const Key kConfigKey_WiFiStationSecType;
+    static const Key kConfigKey_OperationalDeviceId;
+    static const Key kConfigKey_OperationalDeviceCert;
+    static const Key kConfigKey_OperationalDeviceICACerts;
+    static const Key kConfigKey_OperationalDevicePrivateKey;
+    static const Key kConfigKey_SetupDiscriminator;
+
+    static const char kGroupKeyNamePrefix[];
+
+    static CHIP_ERROR Init();
+
+    // Config value accessors.
+    static CHIP_ERROR ReadConfigValue(Key key, bool & val);
+    static CHIP_ERROR ReadConfigValue(Key key, uint32_t & val);
+    static CHIP_ERROR ReadConfigValue(Key key, uint64_t & val);
+    static CHIP_ERROR ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen);
+    static CHIP_ERROR ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen);
+    static CHIP_ERROR WriteConfigValue(Key key, bool val);
+    static CHIP_ERROR WriteConfigValue(Key key, uint32_t val);
+    static CHIP_ERROR WriteConfigValue(Key key, uint64_t val);
+    static CHIP_ERROR WriteConfigValueStr(Key key, const char * str);
+    static CHIP_ERROR WriteConfigValueStr(Key key, const char * str, size_t strLen);
+    static CHIP_ERROR WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen);
+    static CHIP_ERROR ClearConfigValue(Key key);
+    static bool ConfigValueExists(Key key);
+    static CHIP_ERROR FactoryResetConfig();
+
+    static void RunConfigUnitTest();
+
+protected:
+    // NVS Namespace helper functions.
+    static CHIP_ERROR EnsureNamespace(const char * ns);
+    static CHIP_ERROR ClearNamespace(const char * ns);
+
+private:
+    static ChipLinuxStorage * GetStorageForNamespace(Key key);
+};
+
+struct PosixConfig::Key
+{
+    const char * Namespace;
+    const char * Name;
+
+    bool operator==(const Key & other) const;
+};
+
+inline bool PosixConfig::Key::operator==(const Key & other) const
+{
+    return strcmp(Namespace, other.Namespace) == 0 && strcmp(Name, other.Name) == 0;
+}
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/README.md b/src/platform/Tizen/README.md
new file mode 100644 (file)
index 0000000..aa7178d
--- /dev/null
@@ -0,0 +1,59 @@
+# Overview of CHIP Linux Adaption
+
+The following is a quick overview of the Linux adaptation of CHIP. Most of this
+code will have parallels in any new adaptation.
+
+(All file names are relative to `connectedhomeip/src/...`).
+
+`include/platform/Linux/PlatformManagerImpl.h`<br>`Linux/PlatformManagerImpl.cpp`
+
+-   Concrete implementation of PlatformManager interface
+-   Provides initialization of the CHIP stack and core event loop for the chip
+    task
+-   Relies on GenericPlatformManagerImpl_POSIX<> class to provide most of the
+    implementation
+
+`include/platform/Linux/ConfigurationManagerImpl.h`<br>`Linux/ConfigurationManagerImpl.cpp`
+
+-   Concrete implementation of ConfigurationManager interface
+-   Manages storage and retrieval of persistent configuration data
+-   Relies on GenericConfigurationManagerImpl<> classes to implement most API
+    functionality
+-   Delegates low-level reading and writing of persistent values to PosixConfig
+    class
+
+`include/platform/Linux/ConnectivityManagerImpl.h`<br>`Linux/ConnectivityManagerImpl.cpp`
+
+-   Concrete implementation of ConnectivityManager interface
+-   Provides high-level APIs for managing device connectivity
+-   Relies on various generic implementation classes to provide API
+    functionality
+-   Very much a work-in-progress in the Linux branch
+
+`include/platform/Linux/ThreadStackManagerImpl.h`<br>`Linux/ThreadStackManagerImpl.cpp`
+
+-   Concrete implementation of ThreadStackManager interface
+-   Supports Thread stack initialization and core event loop processing
+-   Relies on GenericThreadStackManagerImpl_OpenThread/POSIX<> classes to
+    implement most API functionaltiy
+
+`include/platform/Linux/BLEManagerImpl.h`<br>`Linux/BLEManagerImpl.cpp`
+
+-   Concrete implementation of the BLEManager interface
+-   Maps CHIP's BLE interface abstractions (BleLayer, BlePlatformDelegate,
+    BleApplicationDelegate) onto the platform's native BLE services
+-   Implements chip-compatible BLE advertising.
+
+`platform/Linux/Entropy.cpp`
+
+-   Implements interface to platform entropy source
+
+`platform/Linux/Logging.cpp`
+
+-   Adaption of chip debug logging to platform logging facility.
+
+`platform/Linux/PosixConfig.cpp`
+
+-   Implements low-level read/write of persistent configuration values
+-   Class API specifically designed to work in conjunction with the
+    GenericConfigurationManagerImpl<> class.
diff --git a/src/platform/Tizen/SystemPlatformConfig.h b/src/platform/Tizen/SystemPlatformConfig.h
new file mode 100644 (file)
index 0000000..8c8520f
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *
+ *    Copyright (c) 2020 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.
+ */
+
+/**
+ *    @file
+ *          Platform-specific configuration overrides for the CHIP System
+ *          Layer on Linux platforms.
+ *
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+namespace chip {
+namespace DeviceLayer {
+struct ChipDeviceEvent;
+} // namespace DeviceLayer
+} // namespace chip
+
+// ==================== Platform Adaptations ====================
+
+#define CHIP_SYSTEM_CONFIG_POSIX_LOCKING 1
+#define CHIP_SYSTEM_CONFIG_FREERTOS_LOCKING 0
+#define CHIP_SYSTEM_CONFIG_NO_LOCKING 0
+#define CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_EVENT_FUNCTIONS 1
+#define CHIP_SYSTEM_CONFIG_PLATFORM_PROVIDES_TIME 0
+
+#define CHIP_SYSTEM_CONFIG_USE_POSIX_TIME_FUNCTS 1
+
+// ========== Platform-specific Configuration Overrides =========
+
+#ifndef CHIP_SYSTEM_CONFIG_NUM_TIMERS
+#define CHIP_SYSTEM_CONFIG_NUM_TIMERS 16
+#endif // CHIP_SYSTEM_CONFIG_NUM_TIMERS
diff --git a/src/platform/Tizen/SystemTimeSupport.cpp b/src/platform/Tizen/SystemTimeSupport.cpp
new file mode 100644 (file)
index 0000000..c2fdc91
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *
+ *    Copyright (c) 2018 Nest Labs, Inc.
+ *    All rights reserved.
+ *
+ *    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.
+ */
+
+/**
+ *    @file
+ *          Provides implementations of the CHIP System Layer platform
+ *          time/clock functions that are suitable for use on the Posix platform.
+ */
+
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+
+#include <support/TimeUtils.h>
+#include <support/logging/CHIPLogging.h>
+
+#include <chrono>
+#include <errno.h>
+#include <inttypes.h>
+#include <sys/time.h>
+
+namespace chip {
+namespace System {
+namespace Platform {
+namespace Layer {
+
+uint64_t GetClock_Monotonic()
+{
+    std::chrono::microseconds epoch =
+        std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch());
+    // count() is nominally signed, but for a monotonic clock it cannot be
+    // negative.
+    return static_cast<uint64_t>(epoch.count());
+}
+
+uint64_t GetClock_MonotonicMS()
+{
+    std::chrono::milliseconds epoch =
+        std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch());
+    // count() is nominally signed, but for a monotonic clock it cannot be
+    // negative.
+    return static_cast<uint64_t>(epoch.count());
+}
+
+uint64_t GetClock_MonotonicHiRes()
+{
+    std::chrono::microseconds epoch =
+        std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch());
+    // count() is nominally signed, but for a monotonic clock it cannot be
+    // negative.
+    return static_cast<uint64_t>(epoch.count());
+}
+
+System::Error GetClock_RealTime(uint64_t & curTime)
+{
+    struct timeval tv;
+    int res = gettimeofday(&tv, nullptr);
+    if (res != 0)
+    {
+        return MapErrorPOSIX(errno);
+    }
+    if (tv.tv_sec < CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD)
+    {
+        return CHIP_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED;
+    }
+    if (tv.tv_usec < 0)
+    {
+        return CHIP_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED;
+    }
+    static_assert(CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD >= 0, "We might be letting through negative tv_sec values!");
+    curTime = (static_cast<uint64_t>(tv.tv_sec) * UINT64_C(1000000)) + static_cast<uint64_t>(tv.tv_usec);
+    return CHIP_SYSTEM_NO_ERROR;
+}
+
+System::Error GetClock_RealTimeMS(uint64_t & curTime)
+{
+    struct timeval tv;
+    int res = gettimeofday(&tv, nullptr);
+    if (res != 0)
+    {
+        return MapErrorPOSIX(errno);
+    }
+    if (tv.tv_sec < CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD)
+    {
+        return CHIP_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED;
+    }
+    if (tv.tv_usec < 0)
+    {
+        return CHIP_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED;
+    }
+    static_assert(CHIP_SYSTEM_CONFIG_VALID_REAL_TIME_THRESHOLD >= 0, "We might be letting through negative tv_sec values!");
+    curTime = (static_cast<uint64_t>(tv.tv_sec) * UINT64_C(1000)) + (static_cast<uint64_t>(tv.tv_usec) / 1000);
+    return CHIP_SYSTEM_NO_ERROR;
+}
+
+System::Error SetClock_RealTime(uint64_t newCurTime)
+{
+    struct timeval tv;
+    tv.tv_sec  = static_cast<time_t>(newCurTime / UINT64_C(1000000));
+    tv.tv_usec = static_cast<long>(newCurTime % UINT64_C(1000000));
+    int res    = settimeofday(&tv, nullptr);
+    if (res != 0)
+    {
+        return (errno == EPERM) ? CHIP_SYSTEM_ERROR_ACCESS_DENIED : MapErrorPOSIX(errno);
+    }
+#if CHIP_PROGRESS_LOGGING
+    {
+        const time_t timep = tv.tv_sec;
+        struct tm calendar;
+        localtime_r(&timep, &calendar);
+        ChipLogProgress(
+            DeviceLayer,
+            "Real time clock set to %ld (%04" PRId16 "/%02" PRId8 "/%02" PRId8 " %02" PRId8 ":%02" PRId8 ":%02" PRId8 " UTC)",
+            tv.tv_sec, calendar.tm_year, calendar.tm_mon, calendar.tm_mday, calendar.tm_hour, calendar.tm_min, calendar.tm_sec);
+    }
+#endif // CHIP_PROGRESS_LOGGING
+    return CHIP_SYSTEM_NO_ERROR;
+}
+
+} // namespace Layer
+} // namespace Platform
+} // namespace System
+} // namespace chip
diff --git a/src/platform/Tizen/ThreadStackManagerImpl.cpp b/src/platform/Tizen/ThreadStackManagerImpl.cpp
new file mode 100644 (file)
index 0000000..e956192
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ *
+ *    Copyright (c) 2020 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 <array>
+#include <limits.h>
+#include <string.h>
+
+#include "platform/internal/CHIPDeviceLayerInternal.h"
+#include "platform/internal/DeviceNetworkInfo.h"
+
+#include "platform/PlatformManager.h"
+#include "platform/ThreadStackManager.h"
+#include "support/CodeUtils.h"
+#include "support/logging/CHIPLogging.h"
+
+#include "dbus/client/thread_api_dbus.hpp"
+
+using chip::DeviceLayer::Internal::DeviceNetworkInfo;
+using otbr::DBus::ClientError;
+using otbr::DBus::DeviceRole;
+using otbr::DBus::LinkModeConfig;
+using otbr::DBus::NeighborInfo;
+
+#ifndef CHIP_CONFIG_OTBR_CLIENT_ERROR_MIN
+#define CHIP_CONFIG_OTBR_CLIENT_ERROR_MIN 8000000
+#endif
+
+#define OTBR_TO_CHIP_ERROR(x)                                                                                                      \
+    (x == ClientError::ERROR_NONE ? CHIP_NO_ERROR : _CHIP_ERROR(CHIP_CONFIG_OTBR_CLIENT_ERROR_MIN + static_cast<int>(x)))
+
+#define LogClientError(error)                                                                                                      \
+    do                                                                                                                             \
+    {                                                                                                                              \
+        if (error != ClientError::ERROR_NONE)                                                                                      \
+        {                                                                                                                          \
+            ChipLogError(DeviceLayer, __FILE__ " %d: Otbr ClientError %d", __LINE__, static_cast<int>(error));                     \
+        }                                                                                                                          \
+    } while (0)
+
+constexpr int kDBusConnectionPollingTimeoutMS = 10;
+
+namespace chip {
+namespace DeviceLayer {
+
+ThreadStackManagerImpl ThreadStackManagerImpl::sInstance;
+
+ThreadStackManagerImpl::ThreadStackManagerImpl() : mThreadApi(nullptr), mConnection(nullptr), mNetworkInfo(), mAttached(false) {}
+
+CHIP_ERROR ThreadStackManagerImpl::_InitThreadStack()
+{
+    ClientError error;
+    DeviceRole role;
+    DBusError dbusError;
+    DBusConnection * dispatchConnection;
+
+    dbus_error_init(&dbusError);
+    mConnection = UniqueDBusConnection(dbus_bus_get_private(DBUS_BUS_SYSTEM, &dbusError));
+
+    VerifyOrExit(mConnection != nullptr, error = ClientError::ERROR_DBUS);
+    mThreadApi = std::unique_ptr<otbr::DBus::ThreadApiDBus>(new otbr::DBus::ThreadApiDBus(mConnection.get()));
+    mThreadApi->AddDeviceRoleHandler([this](DeviceRole newRole) { this->_ThreadDevcieRoleChangedHandler(newRole); });
+
+    SuccessOrExit(error = mThreadApi->GetDeviceRole(role));
+    _ThreadDevcieRoleChangedHandler(role);
+    mAttached = (role != DeviceRole::OTBR_DEVICE_ROLE_DETACHED && role != DeviceRole::OTBR_DEVICE_ROLE_DISABLED);
+
+    dispatchConnection = mConnection.get();
+    mDBusEventLoop     = std::thread([dispatchConnection]() {
+        while (true)
+        {
+            // The dbus_connection_read_write will lock the connection until new message comes or timeout.
+            // This will block ot-br-posix APIs. Set timeout to 10ms so it can work.
+            // TODO: we should have a global event loop for dbus to take care of this.
+            dbus_connection_read_write_dispatch(dispatchConnection, kDBusConnectionPollingTimeoutMS);
+        }
+    });
+    mDBusEventLoop.detach();
+exit:
+    dbus_error_free(&dbusError);
+    LogClientError(error);
+    return OTBR_TO_CHIP_ERROR(error);
+}
+
+void ThreadStackManagerImpl::_ThreadDevcieRoleChangedHandler(DeviceRole role)
+{
+    bool attached         = (role != DeviceRole::OTBR_DEVICE_ROLE_DETACHED && role != DeviceRole::OTBR_DEVICE_ROLE_DISABLED);
+    ChipDeviceEvent event = ChipDeviceEvent{};
+
+    if (attached != mAttached)
+    {
+        event.Type = DeviceEventType::kThreadConnectivityChange;
+        event.ThreadConnectivityChange.Result =
+            attached ? ConnectivityChange::kConnectivity_Established : ConnectivityChange::kConnectivity_Lost;
+        PlatformMgr().PostEvent(&event);
+    }
+
+    event.Type                          = DeviceEventType::kThreadStateChange;
+    event.ThreadStateChange.RoleChanged = true;
+    PlatformMgr().PostEvent(&event);
+}
+
+void ThreadStackManagerImpl::_ProcessThreadActivity() {}
+
+static bool RouteMatch(const otbr::DBus::Ip6Prefix & prefix, const Inet::IPAddress & addr)
+{
+    bool match = true;
+    const uint8_t * prefixBuffer;
+    const uint8_t * addrBuffer;
+    uint8_t wholeBytes  = prefix.mLength / CHAR_BIT;
+    uint8_t pendingBits = prefix.mLength % CHAR_BIT;
+
+    VerifyOrExit(addr.IsIPv6(), match = false);
+    VerifyOrExit(prefix.mLength > 0, match = false);
+
+    prefixBuffer = static_cast<const uint8_t *>(&prefix.mPrefix[0]);
+    addrBuffer   = reinterpret_cast<const uint8_t *>(&addr.Addr);
+    VerifyOrExit(memcmp(addrBuffer, prefixBuffer, wholeBytes) == 0, match = false);
+    if (pendingBits)
+    {
+        uint8_t mask = static_cast<uint8_t>(((UINT8_MAX >> pendingBits) << (CHAR_BIT - pendingBits)));
+
+        VerifyOrExit((addrBuffer[wholeBytes] & mask) == (addrBuffer[wholeBytes] & mask), match = false);
+    }
+    VerifyOrExit(memcmp(addrBuffer, prefixBuffer, wholeBytes) == 0, match = false);
+
+exit:
+    return match;
+}
+
+bool ThreadStackManagerImpl::_HaveRouteToAddress(const Inet::IPAddress & destAddr)
+{
+    std::vector<otbr::DBus::ExternalRoute> routes;
+    bool match = false;
+
+    VerifyOrExit(mThreadApi->GetExternalRoutes(routes) == ClientError::ERROR_NONE, match = false);
+    VerifyOrExit(_IsThreadAttached(), match = false);
+    VerifyOrExit(destAddr.IsIPv6LinkLocal(), match = true);
+    for (const auto & route : routes)
+    {
+        VerifyOrExit(!(match = RouteMatch(route.mPrefix, destAddr)), );
+    }
+
+exit:
+    return match;
+}
+
+void ThreadStackManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
+{
+    (void) event;
+    // The otbr-agent processes the Thread state handling by itself so there
+    // isn't much to do in the Chip stack.
+}
+
+CHIP_ERROR ThreadStackManagerImpl::_SetThreadProvision(const Internal::DeviceNetworkInfo & netInfo)
+{
+    mNetworkInfo = netInfo;
+
+    // post an event alerting other subsystems about change in provisioning state
+    ChipDeviceEvent event;
+    event.Type                                           = DeviceEventType::kServiceProvisioningChange;
+    event.ServiceProvisioningChange.IsServiceProvisioned = true;
+    PlatformMgr().PostEvent(&event);
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR ThreadStackManagerImpl::_SetThreadProvision(const uint8_t * operationalDataset, size_t operationalDatasetLen)
+{
+    mOperationalDatasetTlv = std::vector<uint8_t>(operationalDataset, operationalDataset + operationalDatasetLen);
+
+    // post an event alerting other subsystems about change in provisioning state
+    ChipDeviceEvent event;
+    event.Type                                           = DeviceEventType::kServiceProvisioningChange;
+    event.ServiceProvisioningChange.IsServiceProvisioned = true;
+    PlatformMgr().PostEvent(&event);
+
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR ThreadStackManagerImpl::_GetThreadProvision(Internal::DeviceNetworkInfo & netInfo, bool includeCredentials)
+{
+    netInfo = mNetworkInfo;
+
+    if (!includeCredentials)
+    {
+        memset(&netInfo.ThreadMasterKey, 0, sizeof(netInfo.ThreadMasterKey));
+        memset(&netInfo.ThreadPSKc, 0, sizeof(netInfo.ThreadPSKc));
+        netInfo.FieldPresent.ThreadPSKc = false;
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+bool ThreadStackManagerImpl::_IsThreadProvisioned()
+{
+    return mNetworkInfo.ThreadNetworkName[0] != '\0';
+}
+
+void ThreadStackManagerImpl::_ErasePersistentInfo()
+{
+    mNetworkInfo = Internal::DeviceNetworkInfo{};
+}
+
+bool ThreadStackManagerImpl::_IsThreadEnabled()
+{
+    bool enabled = false;
+    DeviceRole role;
+    ClientError error;
+
+    SuccessOrExit(error = mThreadApi->GetDeviceRole(role));
+    enabled = (role != DeviceRole::OTBR_DEVICE_ROLE_DISABLED);
+exit:
+    LogClientError(error);
+    return enabled;
+}
+
+bool ThreadStackManagerImpl::_IsThreadAttached()
+{
+    return mAttached;
+}
+
+CHIP_ERROR ThreadStackManagerImpl::_SetThreadEnabled(bool val)
+{
+    ClientError error = ClientError::ERROR_NONE;
+
+    if (val)
+    {
+        if (mOperationalDatasetTlv.size() > 0)
+        {
+            SuccessOrExit(error = mThreadApi->SetActiveDatasetTlvs(mOperationalDatasetTlv));
+            SuccessOrExit(error = mThreadApi->Attach([](ClientError result) {
+                // ThreadDevcieRoleChangedHandler should take care of this, so we don't emit another event.
+                ChipLogProgress(DeviceLayer, "Thread attach result %d", result);
+            }));
+        }
+        else
+        {
+            std::vector<uint8_t> masterkey(std::begin(mNetworkInfo.ThreadMasterKey), std::end(mNetworkInfo.ThreadMasterKey));
+            std::vector<uint8_t> pskc;
+            uint64_t extPanId    = UINT64_MAX;
+            uint32_t channelMask = UINT32_MAX;
+
+            if (mNetworkInfo.FieldPresent.ThreadExtendedPANId)
+            {
+                extPanId = 0;
+                for (size_t i = 0; i < extPanId; i++)
+                {
+                    extPanId <<= CHAR_BIT;
+                    extPanId |= mNetworkInfo.ThreadExtendedPANId[i];
+                }
+            }
+            if (mNetworkInfo.FieldPresent.ThreadPSKc)
+            {
+                pskc = std::vector<uint8_t>(std::begin(mNetworkInfo.ThreadPSKc), std::end(mNetworkInfo.ThreadPSKc));
+            }
+            if (mNetworkInfo.ThreadChannel != Internal::kThreadChannel_NotSpecified)
+            {
+                channelMask = 1 << mNetworkInfo.ThreadChannel;
+            }
+
+            if (mNetworkInfo.FieldPresent.ThreadMeshPrefix)
+            {
+                std::array<uint8_t, Internal::kThreadMeshPrefixLength> prefix;
+
+                std::copy(std::begin(mNetworkInfo.ThreadMeshPrefix), std::end(mNetworkInfo.ThreadMeshPrefix), std::begin(prefix));
+                SuccessOrExit(error = mThreadApi->SetMeshLocalPrefix(prefix));
+            }
+
+            mThreadApi->Attach(mNetworkInfo.ThreadNetworkName, mNetworkInfo.ThreadPANId, extPanId, masterkey, pskc, channelMask,
+                               [](ClientError result) { ChipLogProgress(DeviceLayer, "Thread attach result %d", result); });
+        }
+    }
+    else
+    {
+        mThreadApi->Reset();
+    }
+exit:
+    LogClientError(error);
+    return OTBR_TO_CHIP_ERROR(error);
+}
+
+ConnectivityManager::ThreadDeviceType ThreadStackManagerImpl::_GetThreadDeviceType()
+{
+    ClientError error;
+    DeviceRole role;
+    LinkModeConfig linkMode;
+    ConnectivityManager::ThreadDeviceType type = ConnectivityManager::ThreadDeviceType::kThreadDeviceType_NotSupported;
+
+    SuccessOrExit(error = mThreadApi->GetDeviceRole(role));
+
+    switch (role)
+    {
+    case DeviceRole::OTBR_DEVICE_ROLE_DISABLED:
+    case DeviceRole::OTBR_DEVICE_ROLE_DETACHED:
+        break;
+    case DeviceRole::OTBR_DEVICE_ROLE_CHILD:
+        SuccessOrExit(error = mThreadApi->GetLinkMode(linkMode));
+        if (!linkMode.mRxOnWhenIdle)
+        {
+            type = ConnectivityManager::ThreadDeviceType::kThreadDeviceType_SleepyEndDevice;
+        }
+        else
+        {
+            type = linkMode.mDeviceType ? ConnectivityManager::ThreadDeviceType::kThreadDeviceType_FullEndDevice
+                                        : ConnectivityManager::ThreadDeviceType::kThreadDeviceType_MinimalEndDevice;
+        }
+        break;
+    case DeviceRole::OTBR_DEVICE_ROLE_ROUTER:
+    case DeviceRole::OTBR_DEVICE_ROLE_LEADER:
+        type = ConnectivityManager::ThreadDeviceType::kThreadDeviceType_Router;
+        break;
+    default:
+        ChipLogError(DeviceLayer, "Unknown Thread role: %d", static_cast<int>(role));
+        break;
+    }
+
+exit:
+    LogClientError(error);
+    return type;
+}
+
+CHIP_ERROR ThreadStackManagerImpl::_SetThreadDeviceType(ConnectivityManager::ThreadDeviceType deviceType)
+{
+    LinkModeConfig linkMode{ true, true, true };
+    ClientError error = ClientError::ERROR_NONE;
+
+    if (deviceType == ConnectivityManager::ThreadDeviceType::kThreadDeviceType_MinimalEndDevice)
+    {
+        linkMode.mNetworkData = false;
+    }
+    else if (deviceType == ConnectivityManager::ThreadDeviceType::kThreadDeviceType_SleepyEndDevice)
+    {
+        linkMode.mRxOnWhenIdle = false;
+        linkMode.mNetworkData  = false;
+    }
+
+    if (!linkMode.mNetworkData)
+    {
+        error = mThreadApi->SetLinkMode(linkMode);
+    }
+
+    LogClientError(error);
+    return OTBR_TO_CHIP_ERROR(error);
+}
+
+void ThreadStackManagerImpl::_GetThreadPollingConfig(ConnectivityManager::ThreadPollingConfig & pollingConfig)
+{
+    (void) pollingConfig;
+
+    ChipLogError(DeviceLayer, "Polling config is not supported on linux");
+}
+
+CHIP_ERROR ThreadStackManagerImpl::_SetThreadPollingConfig(const ConnectivityManager::ThreadPollingConfig & pollingConfig)
+{
+    (void) pollingConfig;
+
+    ChipLogError(DeviceLayer, "Polling config is not supported on linux");
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+bool ThreadStackManagerImpl::_HaveMeshConnectivity()
+{
+    DeviceRole role;
+    ClientError error;
+    bool hasConnectivity = false;
+    std::vector<NeighborInfo> neighbors;
+
+    SuccessOrExit(error = mThreadApi->GetDeviceRole(role));
+    VerifyOrExit(role != DeviceRole::OTBR_DEVICE_ROLE_DETACHED && role != DeviceRole::OTBR_DEVICE_ROLE_DISABLED, );
+    if (role == DeviceRole::OTBR_DEVICE_ROLE_CHILD || role == DeviceRole::OTBR_DEVICE_ROLE_ROUTER)
+    {
+        hasConnectivity = true;
+    }
+
+    SuccessOrExit(error = mThreadApi->GetNeighborTable(neighbors));
+    for (const auto & neighbor : neighbors)
+    {
+        if (!neighbor.mIsChild)
+        {
+            hasConnectivity = true;
+            break;
+        }
+    }
+
+exit:
+    LogClientError(error);
+    return hasConnectivity;
+}
+
+void ThreadStackManagerImpl::_OnMessageLayerActivityChanged(bool messageLayerIsActive)
+{
+    (void) messageLayerIsActive;
+}
+
+void ThreadStackManagerImpl::_OnCHIPoBLEAdvertisingStart() {}
+
+void ThreadStackManagerImpl::_OnCHIPoBLEAdvertisingStop() {}
+
+CHIP_ERROR ThreadStackManagerImpl::_GetAndLogThreadStatsCounters()
+{
+    // TODO: implement after we decide on the profiling protocol
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+CHIP_ERROR ThreadStackManagerImpl::_GetAndLogThreadTopologyMinimal()
+{
+    // TODO: implement after we decide on the profiling protocol
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+CHIP_ERROR ThreadStackManagerImpl::_GetAndLogThreadTopologyFull()
+{
+    // TODO: implement after we decide on the profiling protocol
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+CHIP_ERROR ThreadStackManagerImpl::_GetPrimary802154MACAddress(uint8_t * buf)
+{
+    uint64_t extAddr;
+    ClientError error;
+    SuccessOrExit(error = mThreadApi->GetExtendedAddress(extAddr));
+
+    for (size_t i = 0; i < sizeof(extAddr); i++)
+    {
+        buf[sizeof(uint64_t) - i - 1] = (extAddr & UINT8_MAX);
+        extAddr >>= CHAR_BIT;
+    }
+
+exit:
+    LogClientError(error);
+    return OTBR_TO_CHIP_ERROR(error);
+}
+
+CHIP_ERROR ThreadStackManagerImpl::_GetFactoryAssignedEUI64(uint8_t (&buf)[8])
+{
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+CHIP_ERROR ThreadStackManagerImpl::_GetExternalIPv6Address(chip::Inet::IPAddress & addr)
+{
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+CHIP_ERROR ThreadStackManagerImpl::_JoinerStart()
+{
+    return CHIP_ERROR_NOT_IMPLEMENTED;
+}
+
+ThreadStackManager & ThreadStackMgr()
+{
+    return chip::DeviceLayer::ThreadStackManagerImpl::sInstance;
+}
+
+ThreadStackManagerImpl & ThreadStackMgrImpl()
+{
+    return chip::DeviceLayer::ThreadStackManagerImpl::sInstance;
+}
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/ThreadStackManagerImpl.h b/src/platform/Tizen/ThreadStackManagerImpl.h
new file mode 100644 (file)
index 0000000..0f286c3
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ *
+ *    Copyright (c) 2020 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 <memory>
+#include <thread>
+#include <vector>
+
+#include "platform/internal/CHIPDeviceLayerInternal.h"
+
+#include "dbus/client/thread_api_dbus.hpp"
+#include "platform/internal/DeviceNetworkInfo.h"
+
+namespace chip {
+namespace DeviceLayer {
+
+class ThreadStackManagerImpl : public ThreadStackManager
+{
+public:
+    ThreadStackManagerImpl();
+
+    CHIP_ERROR _InitThreadStack();
+    void _ProcessThreadActivity();
+
+    CHIP_ERROR _StartThreadTask() { return CHIP_NO_ERROR; } // Intentionally left blank
+    void _LockThreadStack() {}                              // Intentionally left blank
+    bool _TryLockThreadStack() { return false; }            // Intentionally left blank
+    void _UnlockThreadStack() {}                            // Intentionally left blank
+
+    bool _HaveRouteToAddress(const Inet::IPAddress & destAddr);
+
+    void _OnPlatformEvent(const ChipDeviceEvent * event);
+
+    CHIP_ERROR _GetThreadProvision(Internal::DeviceNetworkInfo & netInfo, bool includeCredentials);
+
+    CHIP_ERROR _SetThreadProvision(const Internal::DeviceNetworkInfo & netInfo);
+
+    CHIP_ERROR _SetThreadProvision(const uint8_t * operationalDataset, size_t operationalDatasetLen);
+
+    void _ErasePersistentInfo();
+
+    bool _IsThreadProvisioned();
+
+    bool _IsThreadEnabled();
+
+    bool _IsThreadAttached();
+
+    CHIP_ERROR _SetThreadEnabled(bool val);
+
+    ConnectivityManager::ThreadDeviceType _GetThreadDeviceType();
+
+    CHIP_ERROR _SetThreadDeviceType(ConnectivityManager::ThreadDeviceType deviceType);
+
+    void _GetThreadPollingConfig(ConnectivityManager::ThreadPollingConfig & pollingConfig);
+
+    CHIP_ERROR _SetThreadPollingConfig(const ConnectivityManager::ThreadPollingConfig & pollingConfig);
+
+    bool _HaveMeshConnectivity();
+
+    void _OnMessageLayerActivityChanged(bool messageLayerIsActive);
+
+    void _OnCHIPoBLEAdvertisingStart();
+
+    void _OnCHIPoBLEAdvertisingStop();
+
+    CHIP_ERROR _GetAndLogThreadStatsCounters();
+
+    CHIP_ERROR _GetAndLogThreadTopologyMinimal();
+
+    CHIP_ERROR _GetAndLogThreadTopologyFull();
+
+    CHIP_ERROR _GetPrimary802154MACAddress(uint8_t * buf);
+
+    CHIP_ERROR _GetFactoryAssignedEUI64(uint8_t (&buf)[8]);
+
+    CHIP_ERROR _GetExternalIPv6Address(chip::Inet::IPAddress & addr);
+
+    CHIP_ERROR _JoinerStart();
+
+    ~ThreadStackManagerImpl() = default;
+
+    static ThreadStackManagerImpl sInstance;
+
+private:
+    struct DBusConnectionDeleter
+    {
+        void operator()(DBusConnection * aConnection) { dbus_connection_unref(aConnection); }
+    };
+
+    using UniqueDBusConnection = std::unique_ptr<DBusConnection, DBusConnectionDeleter>;
+
+    void _ThreadDevcieRoleChangedHandler(otbr::DBus::DeviceRole role);
+
+    std::unique_ptr<otbr::DBus::ThreadApiDBus> mThreadApi;
+    UniqueDBusConnection mConnection;
+    std::vector<uint8_t> mOperationalDatasetTlv;
+    Internal::DeviceNetworkInfo mNetworkInfo;
+    bool mAttached;
+    std::thread mDBusEventLoop;
+};
+
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/args.gni b/src/platform/Tizen/args.gni
new file mode 100644 (file)
index 0000000..f9f97ee
--- /dev/null
@@ -0,0 +1,15 @@
+# Copyright (c) 2020 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.
+
+chip_device_platform = "linux"
diff --git a/src/platform/Tizen/bluez/AdapterIterator.cpp b/src/platform/Tizen/bluez/AdapterIterator.cpp
new file mode 100644 (file)
index 0000000..626b2f9
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ *
+ *    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 "AdapterIterator.h"
+
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+
+#include <support/CodeUtils.h>
+#include <support/logging/CHIPLogging.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+AdapterIterator::~AdapterIterator()
+{
+    if (mManager != nullptr)
+    {
+        g_object_unref(mManager);
+    }
+
+    if (mObjectList != nullptr)
+    {
+        g_list_free_full(mObjectList, g_object_unref);
+    }
+
+    if (mCurrent.adapter != nullptr)
+    {
+        g_object_unref(mCurrent.adapter);
+        mCurrent.adapter = nullptr;
+    }
+}
+
+void AdapterIterator::Initialize()
+{
+    GError * error = nullptr;
+
+    mManager = g_dbus_object_manager_client_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+                                                             BLUEZ_INTERFACE, "/", bluez_object_manager_client_get_proxy_type,
+                                                             nullptr /* unused user data in the Proxy Type Func */,
+                                                             nullptr /*destroy notify */, nullptr /* cancellable */, &error);
+
+    VerifyOrExit(mManager != nullptr, ChipLogError(DeviceLayer, "Failed to get DBUS object manager for listing adapters."));
+
+    mObjectList      = g_dbus_object_manager_get_objects(mManager);
+    mCurrentListItem = mObjectList;
+
+exit:
+    if (error != nullptr)
+    {
+        ChipLogError(DeviceLayer, "DBus error: %s", error->message);
+        g_error_free(error);
+    }
+}
+
+bool AdapterIterator::Advance()
+{
+    if (mCurrentListItem == nullptr)
+    {
+        return false;
+    }
+
+    while (mCurrentListItem != nullptr)
+    {
+        BluezAdapter1 * adapter = bluez_object_get_adapter1(BLUEZ_OBJECT(mCurrentListItem->data));
+        if (adapter == nullptr)
+        {
+            mCurrentListItem = mCurrentListItem->next;
+            continue;
+        }
+
+        // PATH is of the for  BLUEZ_PATH / hci<nr>, i.e. like
+        // '/org/bluez/hci0'
+        // Index represents the number after hci
+        const char * path = g_dbus_proxy_get_object_path(G_DBUS_PROXY(adapter));
+        unsigned index    = 0;
+
+        if (sscanf(path, BLUEZ_PATH "/hci%u", &index) != 1)
+        {
+            ChipLogError(DeviceLayer, "Failed to extract HCI index from '%s'", path);
+            index = 0;
+        }
+
+        if (mCurrent.adapter != nullptr)
+        {
+            g_object_unref(mCurrent.adapter);
+            mCurrent.adapter = nullptr;
+        }
+
+        mCurrent.index   = index;
+        mCurrent.address = bluez_adapter1_get_address(adapter);
+        mCurrent.alias   = bluez_adapter1_get_alias(adapter);
+        mCurrent.name    = bluez_adapter1_get_name(adapter);
+        mCurrent.powered = bluez_adapter1_get_powered(adapter);
+        mCurrent.adapter = adapter;
+
+        mCurrentListItem = mCurrentListItem->next;
+
+        return true;
+    }
+
+    return false;
+}
+
+bool AdapterIterator::Next()
+{
+    if (mManager == nullptr)
+    {
+        Initialize();
+    }
+
+    return Advance();
+}
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
+
+#endif
diff --git a/src/platform/Tizen/bluez/AdapterIterator.h b/src/platform/Tizen/bluez/AdapterIterator.h
new file mode 100644 (file)
index 0000000..be53995
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *
+ *    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 "Types.h"
+
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+/// Iterates over available BlueZ adapters
+///
+/// Usage example:
+///
+///  AdapterIterator iterator;
+///  while (iterator.Next()) {
+///      std::cout << iterator.GetAddress() << std::endl;
+///  }
+///
+/// Data is provided through the bluez dbus interface. You can view
+/// this data in the commandline using commands such as:
+///
+///    busctl introspect org.bluez /org/bluez/hci0
+class AdapterIterator
+{
+public:
+    ~AdapterIterator();
+
+    /// Moves to the next DBUS interface.
+    ///
+    /// MUST be called before any of the 'current value' methods are
+    /// used (iterator gets initialized on the first call of Next).
+    bool Next();
+
+    // Information about the current value. Safe to call only after
+    // "Next" has returned true.
+    uint32_t GetIndex() const { return mCurrent.index; }
+    const char * GetAddress() const { return mCurrent.address.c_str(); }
+    const char * GetAlias() const { return mCurrent.alias.c_str(); }
+    const char * GetName() const { return mCurrent.name.c_str(); }
+    bool IsPowered() const { return mCurrent.powered; }
+    BluezAdapter1 * GetAdapter() const { return mCurrent.adapter; }
+
+private:
+    /// Sets up the DBUS manager and loads the list
+    void Initialize();
+
+    /// Loads the next value in the list.
+    ///
+    /// Returns true if a value could be loaded, false if no more items to
+    /// iterate through.
+    bool Advance();
+
+    static constexpr size_t kMaxAddressLength = 19; // xx:xx:xx:xx:xx:xx
+    static constexpr size_t kMaxNameLength    = 64;
+
+    GDBusObjectManager * mManager = nullptr; // DBus connection
+    GList * mObjectList           = nullptr; // listing of objects on the bus
+    GList * mCurrentListItem      = nullptr; // current item viewed in the list
+
+    // data valid only if Next() returns true
+    struct
+    {
+        uint32_t index;
+        std::string address;
+        std::string alias;
+        std::string name;
+        bool powered;
+        BluezAdapter1 * adapter;
+    } mCurrent = { 0 };
+};
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
+
+#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
diff --git a/src/platform/Tizen/bluez/BluezObjectIterator.h b/src/platform/Tizen/bluez/BluezObjectIterator.h
new file mode 100644 (file)
index 0000000..ae5e01c
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *
+ *    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 <glib.h>
+
+#include <platform/CHIPDeviceConfig.h>
+#include <platform/Linux/dbus/bluez/DbusBluez.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+/**
+ *  Helper class to iterate over a list of Bluez objects.
+ */
+class BluezObjectIterator
+{
+public:
+    using iterator_category = std::forward_iterator_tag;
+    using difference_type   = std::ptrdiff_t;
+    using value_type        = BluezObject;
+    using pointer           = BluezObject *;
+    using reference         = BluezObject &;
+
+    BluezObjectIterator() = default;
+    explicit BluezObjectIterator(GList * position) : mPosition(position) {}
+
+    reference operator*() const { return *BLUEZ_OBJECT(mPosition->data); }
+    pointer operator->() const { return BLUEZ_OBJECT(mPosition->data); }
+    bool operator==(const BluezObjectIterator & other) const { return mPosition == other.mPosition; }
+    bool operator!=(const BluezObjectIterator & other) const { return mPosition != other.mPosition; }
+
+    BluezObjectIterator & operator++()
+    {
+        mPosition = mPosition->next;
+        return *this;
+    }
+
+    BluezObjectIterator operator++(int)
+    {
+        const auto currentPosition = mPosition;
+        mPosition                  = mPosition->next;
+        return BluezObjectIterator(currentPosition);
+    }
+
+private:
+    GList * mPosition = nullptr;
+};
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/bluez/BluezObjectList.h b/src/platform/Tizen/bluez/BluezObjectList.h
new file mode 100644 (file)
index 0000000..5913f1e
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *
+ *    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 <glib.h>
+
+#include <platform/CHIPDeviceConfig.h>
+#include <platform/Linux/dbus/bluez/DbusBluez.h>
+#include <support/logging/CHIPLogging.h>
+
+#include "BluezObjectIterator.h"
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+/**
+ *  C++ wrapper for a Bluez object list based on a object manager
+ */
+class BluezObjectList
+{
+public:
+    explicit BluezObjectList(GDBusObjectManager * manager) { Initialize(manager); }
+
+    ~BluezObjectList() { g_list_free_full(mObjectList, g_object_unref); }
+
+    BluezObjectIterator begin() const { return BluezObjectIterator(mObjectList); }
+    BluezObjectIterator end() const { return BluezObjectIterator(); }
+
+protected:
+    BluezObjectList() {}
+
+    void Initialize(GDBusObjectManager * manager)
+    {
+        if (manager == nullptr)
+        {
+            ChipLogError(DeviceLayer, "Manager is NULL in %s", __func__);
+            return;
+        }
+
+        mObjectList = g_dbus_object_manager_get_objects(manager);
+    }
+
+private:
+    GList * mObjectList = nullptr;
+};
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
diff --git a/src/platform/Tizen/bluez/ChipDeviceScanner.cpp b/src/platform/Tizen/bluez/ChipDeviceScanner.cpp
new file mode 100644 (file)
index 0000000..d960e1b
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ *
+ *    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 "ChipDeviceScanner.h"
+
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+
+#include "BluezObjectList.h"
+#include "MainLoop.h"
+#include "Types.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <support/logging/CHIPLogging.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+namespace {
+
+struct GObjectUnref
+{
+    template <typename T>
+    void operator()(T * value)
+    {
+        g_object_unref(value);
+    }
+};
+
+using GCancellableUniquePtr       = std::unique_ptr<GCancellable, GObjectUnref>;
+using GDBusObjectManagerUniquePtr = std::unique_ptr<GDBusObjectManager, GObjectUnref>;
+
+/// Retrieve CHIP device identification info from the device advertising data
+bool BluezGetChipDeviceInfo(BluezDevice1 & aDevice, chip::Ble::ChipBLEDeviceIdentificationInfo & aDeviceInfo)
+{
+    GVariant * serviceData = bluez_device1_get_service_data(&aDevice);
+    VerifyOrReturnError(serviceData != nullptr, false);
+
+    GVariant * dataValue = g_variant_lookup_value(serviceData, CHIP_BLE_UUID_SERVICE_STRING, nullptr);
+    VerifyOrReturnError(dataValue != nullptr, false);
+
+    size_t dataLen         = 0;
+    const void * dataBytes = g_variant_get_fixed_array(dataValue, &dataLen, sizeof(uint8_t));
+    VerifyOrReturnError(dataBytes != nullptr && dataLen >= sizeof(aDeviceInfo), false);
+
+    memcpy(&aDeviceInfo, dataBytes, sizeof(aDeviceInfo));
+    return true;
+}
+
+} // namespace
+
+ChipDeviceScanner::ChipDeviceScanner(GDBusObjectManager * manager, BluezAdapter1 * adapter, GCancellable * cancellable,
+                                     ChipDeviceScannerDelegate * delegate) :
+    mManager(manager),
+    mAdapter(adapter), mCancellable(cancellable), mDelegate(delegate)
+{
+    g_object_ref(mAdapter);
+    g_object_ref(mCancellable);
+    g_object_ref(mManager);
+}
+
+ChipDeviceScanner::~ChipDeviceScanner()
+{
+    StopScan();
+
+    // In case the timeout timer is still active
+    chip::DeviceLayer::SystemLayer.CancelTimer(TimerExpiredCallback, this);
+
+    g_object_unref(mManager);
+    g_object_unref(mCancellable);
+    g_object_unref(mAdapter);
+
+    mManager     = nullptr;
+    mAdapter     = nullptr;
+    mCancellable = nullptr;
+    mDelegate    = nullptr;
+}
+
+std::unique_ptr<ChipDeviceScanner> ChipDeviceScanner::Create(BluezAdapter1 * adapter, ChipDeviceScannerDelegate * delegate)
+{
+    GError * error = nullptr;
+
+    GCancellableUniquePtr cancellable(g_cancellable_new(), GObjectUnref());
+
+    if (!cancellable)
+    {
+        return std::unique_ptr<ChipDeviceScanner>();
+    }
+
+    GDBusObjectManagerUniquePtr manager(
+        g_dbus_object_manager_client_new_for_bus_sync(G_BUS_TYPE_SYSTEM, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, BLUEZ_INTERFACE,
+                                                      "/", bluez_object_manager_client_get_proxy_type,
+                                                      nullptr /* unused user data in the Proxy Type Func */,
+                                                      nullptr /*destroy notify */, cancellable.get(), &error),
+        GObjectUnref());
+    if (!manager)
+    {
+        ChipLogError(Ble, "Failed to get DBUS object manager for device scanning: %s", error->message);
+        g_error_free(error);
+        return std::unique_ptr<ChipDeviceScanner>();
+    }
+
+    return std::make_unique<ChipDeviceScanner>(manager.get(), adapter, cancellable.get(), delegate);
+}
+
+CHIP_ERROR ChipDeviceScanner::StartScan(unsigned timeoutMs)
+{
+    ReturnErrorCodeIf(mIsScanning, CHIP_ERROR_INCORRECT_STATE);
+
+    ReturnErrorOnFailure(MainLoop::Instance().EnsureStarted());
+
+    mIsScanning = true; // optimistic, to allow all callbacks to check this
+    if (!MainLoop::Instance().Schedule(MainLoopStartScan, this))
+    {
+        ChipLogError(Ble, "Failed to schedule BLE scan start.");
+        mIsScanning = false;
+        return CHIP_ERROR_INTERNAL;
+    }
+
+    CHIP_ERROR err = chip::DeviceLayer::SystemLayer.StartTimer(timeoutMs, TimerExpiredCallback, static_cast<void *>(this));
+
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(Ble, "Failed to schedule scan timeout.");
+        StopScan();
+        return err;
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+void ChipDeviceScanner::TimerExpiredCallback(chip::System::Layer * layer, void * appState, chip::System::Error error)
+{
+    static_cast<ChipDeviceScanner *>(appState)->StopScan();
+}
+
+CHIP_ERROR ChipDeviceScanner::StopScan()
+{
+    ReturnErrorCodeIf(!mIsScanning, CHIP_NO_ERROR);
+    ReturnErrorCodeIf(mIsStopping, CHIP_NO_ERROR);
+    mIsStopping = true;
+    g_cancellable_cancel(mCancellable); // in case we are currently running a scan
+
+    if (mObjectAddedSignal)
+    {
+        g_signal_handler_disconnect(mManager, mObjectAddedSignal);
+        mObjectAddedSignal = 0;
+    }
+
+    if (mInterfaceChangedSignal)
+    {
+        g_signal_handler_disconnect(mManager, mInterfaceChangedSignal);
+        mInterfaceChangedSignal = 0;
+    }
+
+    if (!MainLoop::Instance().ScheduleAndWait(MainLoopStopScan, this))
+    {
+        ChipLogError(Ble, "Failed to schedule BLE scan stop.");
+        return CHIP_ERROR_INTERNAL;
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+int ChipDeviceScanner::MainLoopStopScan(ChipDeviceScanner * self)
+{
+    GError * error = nullptr;
+
+    if (!bluez_adapter1_call_stop_discovery_sync(self->mAdapter, nullptr /* not cancellable */, &error))
+    {
+        ChipLogError(Ble, "Failed to stop discovery %s", error->message);
+        g_error_free(error);
+    }
+    ChipDeviceScannerDelegate * delegate = self->mDelegate;
+    self->mIsScanning                    = false;
+
+    // callback is explicitly allowed to delete the scanner (hence no more
+    // references to 'self' here)
+    delegate->OnScanComplete();
+
+    return 0;
+}
+
+void ChipDeviceScanner::SignalObjectAdded(GDBusObjectManager * manager, GDBusObject * object, ChipDeviceScanner * self)
+{
+    self->ReportDevice(bluez_object_get_device1(BLUEZ_OBJECT(object)));
+}
+
+void ChipDeviceScanner::SignalInterfaceChanged(GDBusObjectManagerClient * manager, GDBusObjectProxy * object,
+                                               GDBusProxy * aInterface, GVariant * aChangedProperties,
+                                               const gchar * const * aInvalidatedProps, ChipDeviceScanner * self)
+{
+    self->ReportDevice(bluez_object_get_device1(BLUEZ_OBJECT(object)));
+}
+
+void ChipDeviceScanner::ReportDevice(BluezDevice1 * device)
+{
+    if (device == nullptr)
+    {
+        return;
+    }
+
+    if (strcmp(bluez_device1_get_adapter(device), g_dbus_proxy_get_object_path(G_DBUS_PROXY(mAdapter))) != 0)
+    {
+        return;
+    }
+
+    chip::Ble::ChipBLEDeviceIdentificationInfo deviceInfo;
+
+    if (!BluezGetChipDeviceInfo(*device, deviceInfo))
+    {
+        ChipLogDetail(Ble, "Device %s does not look like a CHIP device.", bluez_device1_get_address(device));
+        return;
+    }
+
+    mDelegate->OnDeviceScanned(device, deviceInfo);
+}
+
+int ChipDeviceScanner::MainLoopStartScan(ChipDeviceScanner * self)
+{
+    GError * error = nullptr;
+
+    self->mObjectAddedSignal = g_signal_connect(self->mManager, "object-added", G_CALLBACK(SignalObjectAdded), self);
+    self->mInterfaceChangedSignal =
+        g_signal_connect(self->mManager, "interface-proxy-properties-changed", G_CALLBACK(SignalInterfaceChanged), self);
+
+    ChipLogProgress(Ble, "BLE scanning through known devices.");
+    for (BluezObject & object : BluezObjectList(self->mManager))
+    {
+        self->ReportDevice(bluez_object_get_device1(&object));
+    }
+
+    ChipLogProgress(Ble, "BLE initiating scan.");
+    if (!bluez_adapter1_call_start_discovery_sync(self->mAdapter, self->mCancellable, &error))
+    {
+        ChipLogError(Ble, "Failed to start discovery: %s", error->message);
+        g_error_free(error);
+
+        self->mIsScanning = false;
+        self->mDelegate->OnScanComplete();
+    }
+
+    return 0;
+}
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
+
+#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
diff --git a/src/platform/Tizen/bluez/ChipDeviceScanner.h b/src/platform/Tizen/bluez/ChipDeviceScanner.h
new file mode 100644 (file)
index 0000000..474d71c
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ *
+ *    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 <platform/CHIPDeviceConfig.h>
+
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+
+#include <glib.h>
+#include <memory>
+
+#include <ble/CHIPBleServiceData.h>
+#include <core/CHIPError.h>
+#include <platform/Linux/dbus/bluez/DbusBluez.h>
+#include <system/SystemLayer.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+/// Receives callbacks when chip devices are being scanned
+class ChipDeviceScannerDelegate
+{
+public:
+    virtual ~ChipDeviceScannerDelegate() {}
+
+    // Called when a CHIP device was found
+    virtual void OnDeviceScanned(BluezDevice1 * device, const chip::Ble::ChipBLEDeviceIdentificationInfo & info) = 0;
+
+    // Called when a scan was completed (stopped or timed out)
+    virtual void OnScanComplete() = 0;
+};
+
+/// Allows scanning for CHIP devices
+///
+/// Will perform scan operations and call back whenever a device is discovered.
+class ChipDeviceScanner
+{
+public:
+    /// NOTE: prefer to use the  ::Create method instead direct constructor calling.
+    ChipDeviceScanner(GDBusObjectManager * manager, BluezAdapter1 * adapter, GCancellable * cancellable,
+                      ChipDeviceScannerDelegate * delegate);
+
+    ChipDeviceScanner(ChipDeviceScanner &&)      = default;
+    ChipDeviceScanner(const ChipDeviceScanner &) = delete;
+    ChipDeviceScanner & operator=(const ChipDeviceScanner &) = delete;
+
+    ~ChipDeviceScanner();
+
+    /// Initiate a scan for devices, with the given timeout
+    CHIP_ERROR StartScan(unsigned timeoutMs);
+
+    /// Stop any currently running scan
+    CHIP_ERROR StopScan();
+
+    /// Create a new device scanner
+    ///
+    /// Convenience method to allocate any required variables.
+    /// On success, maintains a reference to the provided adapter.
+    static std::unique_ptr<ChipDeviceScanner> Create(BluezAdapter1 * adapter, ChipDeviceScannerDelegate * delegate);
+
+private:
+    static void TimerExpiredCallback(chip::System::Layer * layer, void * appState, chip::System::Error error);
+    static int MainLoopStartScan(ChipDeviceScanner * self);
+    static int MainLoopStopScan(ChipDeviceScanner * self);
+    static void SignalObjectAdded(GDBusObjectManager * manager, GDBusObject * object, ChipDeviceScanner * self);
+    static void SignalInterfaceChanged(GDBusObjectManagerClient * manager, GDBusObjectProxy * object, GDBusProxy * aInterface,
+                                       GVariant * aChangedProperties, const gchar * const * aInvalidatedProps,
+                                       ChipDeviceScanner * self);
+
+    /// Check if a given device is a CHIP device and if yes, report it as discovered
+    void ReportDevice(BluezDevice1 * device);
+
+    GDBusObjectManager * mManager         = nullptr;
+    BluezAdapter1 * mAdapter              = nullptr;
+    GCancellable * mCancellable           = nullptr;
+    ChipDeviceScannerDelegate * mDelegate = nullptr;
+    gulong mObjectAddedSignal             = 0;
+    gulong mInterfaceChangedSignal        = 0;
+    bool mIsScanning                      = false;
+    bool mIsStopping                      = false;
+};
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
+
+#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
diff --git a/src/platform/Tizen/bluez/Helper.cpp b/src/platform/Tizen/bluez/Helper.cpp
new file mode 100644 (file)
index 0000000..e2a2078
--- /dev/null
@@ -0,0 +1,1791 @@
+/*
+ *
+ *    Copyright (c) 2020-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.
+ */
+
+/*
+ *  Copyright (c) 2016-2019, The OpenThread Authors.
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the copyright holder nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ *    @file
+ *          Provides Bluez dbus implementatioon for BLE
+ */
+
+#include <ble/BleUUID.h>
+#include <ble/CHIPBleServiceData.h>
+#include <platform/CHIPDeviceLayer.h>
+#include <protocols/Protocols.h>
+#include <setup_payload/AdditionalDataPayloadGenerator.h>
+#include <support/BitFlags.h>
+#include <support/CHIPMem.h>
+#include <support/CHIPMemString.h>
+
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+#include <cassert>
+#include <errno.h>
+#include <gio/gunixfdlist.h>
+#include <limits>
+#include <stdarg.h>
+#include <strings.h>
+#include <unistd.h>
+#include <utility>
+
+#include <platform/Linux/BLEManagerImpl.h>
+#include <support/CodeUtils.h>
+#include <system/TLVPacketBufferBackingStore.h>
+
+#include "BluezObjectIterator.h"
+#include "BluezObjectList.h"
+#include "Helper.h"
+#include "MainLoop.h"
+
+using namespace ::nl;
+using namespace chip::Protocols;
+using chip::Platform::CopyString;
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+static BluezConnection * GetBluezConnectionViaDevice(BluezEndpoint * apEndpoint);
+
+namespace {
+
+class BluezEndpointObjectList : public BluezObjectList
+{
+public:
+    explicit BluezEndpointObjectList(BluezEndpoint * apEndpoint)
+    {
+        VerifyOrReturn(apEndpoint != nullptr, ChipLogError(DeviceLayer, "apEndpoint is NULL in %s", __func__));
+        Initialize(apEndpoint->mpObjMgr);
+    }
+};
+
+} // namespace
+
+static gboolean BluezAdvertisingRelease(BluezLEAdvertisement1 * aAdv, GDBusMethodInvocation * aInvocation, gpointer apClosure)
+{
+    bool isSuccess           = false;
+    BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+    VerifyOrExit(aAdv != nullptr, ChipLogError(DeviceLayer, "BluezLEAdvertisement1 is NULL in %s", __func__));
+    ChipLogDetail(DeviceLayer, "Release adv object in %s", __func__);
+
+    g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
+    endpoint->mIsAdvertising = false;
+    isSuccess                = true;
+exit:
+
+    return isSuccess ? TRUE : FALSE;
+}
+
+static BluezLEAdvertisement1 * BluezAdvertisingCreate(BluezEndpoint * apEndpoint)
+{
+    BluezLEAdvertisement1 * adv = nullptr;
+    BluezObjectSkeleton * object;
+    GVariant * serviceData;
+    GVariant * serviceUUID;
+    gchar * localName;
+    GVariantBuilder serviceDataBuilder;
+    GVariantBuilder serviceUUIDsBuilder;
+    char * debugStr;
+
+    VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+    if (apEndpoint->mpAdvPath == nullptr)
+        apEndpoint->mpAdvPath = g_strdup_printf("%s/advertising", apEndpoint->mpRootPath);
+
+    ChipLogDetail(DeviceLayer, "Create adv object at %s", apEndpoint->mpAdvPath);
+    object = bluez_object_skeleton_new(apEndpoint->mpAdvPath);
+
+    adv = bluez_leadvertisement1_skeleton_new();
+
+    g_variant_builder_init(&serviceDataBuilder, G_VARIANT_TYPE("a{sv}"));
+    g_variant_builder_init(&serviceUUIDsBuilder, G_VARIANT_TYPE("as"));
+
+    g_variant_builder_add(&serviceDataBuilder, "{sv}", apEndpoint->mpAdvertisingUUID,
+                          g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &apEndpoint->mDeviceIdInfo,
+                                                    sizeof(apEndpoint->mDeviceIdInfo), sizeof(uint8_t)));
+    g_variant_builder_add(&serviceUUIDsBuilder, "s", apEndpoint->mpAdvertisingUUID);
+
+    if (apEndpoint->mpAdapterName != nullptr)
+        localName = g_strdup_printf("%s", apEndpoint->mpAdapterName);
+    else
+        localName = g_strdup_printf("%s%04x", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, getpid() & 0xffff);
+
+    serviceData = g_variant_builder_end(&serviceDataBuilder);
+    serviceUUID = g_variant_builder_end(&serviceUUIDsBuilder);
+
+    debugStr = g_variant_print(serviceData, TRUE);
+    ChipLogDetail(DeviceLayer, "SET service data to %s", debugStr);
+    g_free(debugStr);
+
+    bluez_leadvertisement1_set_type_(adv, (apEndpoint->mType & BLUEZ_ADV_TYPE_CONNECTABLE) ? "peripheral" : "broadcast");
+    // empty manufacturer data
+    // empty solicit UUIDs
+    bluez_leadvertisement1_set_service_data(adv, serviceData);
+    // empty data
+
+    // Setting "Discoverable" to False on the adapter and to True on the advertisement convinces
+    // Bluez to set "BR/EDR Not Supported" flag. Bluez doesn't provide API to do that explicitly
+    // and the flag is necessary to force using LE transport.
+    bluez_leadvertisement1_set_discoverable(adv, (apEndpoint->mType & BLUEZ_ADV_TYPE_SCANNABLE) ? TRUE : FALSE);
+    if (apEndpoint->mType & BLUEZ_ADV_TYPE_SCANNABLE)
+        bluez_leadvertisement1_set_discoverable_timeout(adv, UINT16_MAX);
+
+    // advertising name corresponding to the PID and object path, for debug purposes
+    bluez_leadvertisement1_set_local_name(adv, localName);
+    bluez_leadvertisement1_set_service_uuids(adv, serviceUUID);
+
+    // 0xffff means no appearance
+    bluez_leadvertisement1_set_appearance(adv, 0xffff);
+
+    bluez_leadvertisement1_set_duration(adv, apEndpoint->mDuration);
+    // empty duration, we don't have a clear notion what it would mean to timeslice between toble and anyone else
+    bluez_leadvertisement1_set_timeout(adv, 0);
+    // empty secondary channel for now
+
+    bluez_object_skeleton_set_leadvertisement1(object, adv);
+    g_signal_connect(adv, "handle-release", G_CALLBACK(BluezAdvertisingRelease), apEndpoint);
+
+    g_dbus_object_manager_server_export(apEndpoint->mpRoot, G_DBUS_OBJECT_SKELETON(object));
+    g_object_unref(object);
+
+    BLEManagerImpl::NotifyBLEPeripheralAdvConfiguredComplete(true, nullptr);
+
+exit:
+    return adv;
+}
+
+static void BluezAdvStartDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
+{
+    BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject);
+    GError * error                      = nullptr;
+    BluezEndpoint * endpoint            = static_cast<BluezEndpoint *>(apClosure);
+    gboolean success                    = FALSE;
+
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+
+    success = bluez_leadvertising_manager1_call_register_advertisement_finish(advMgr, aResult, &error);
+    if (success == FALSE)
+    {
+        g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
+    }
+    VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: RegisterAdvertisement : %s", error->message));
+
+    endpoint->mIsAdvertising = true;
+
+    ChipLogDetail(DeviceLayer, "RegisterAdvertisement complete");
+
+exit:
+    BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(success == TRUE, nullptr);
+    if (error != nullptr)
+        g_error_free(error);
+}
+
+static void BluezAdvStopDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
+{
+    BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject);
+    BluezEndpoint * endpoint            = static_cast<BluezEndpoint *>(apClosure);
+    GError * error                      = nullptr;
+    gboolean success                    = FALSE;
+
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+
+    success = bluez_leadvertising_manager1_call_unregister_advertisement_finish(advMgr, aResult, &error);
+
+    if (success == FALSE)
+    {
+        g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
+    }
+    else
+    {
+        endpoint->mIsAdvertising = false;
+    }
+
+    VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: UnregisterAdvertisement : %s", error->message));
+
+    ChipLogDetail(DeviceLayer, "UnregisterAdvertisement complete");
+
+exit:
+    BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(success == TRUE, nullptr);
+    if (error != nullptr)
+        g_error_free(error);
+}
+
+static gboolean BluezAdvSetup(BluezEndpoint * endpoint)
+{
+    BluezLEAdvertisement1 * adv;
+
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+    VerifyOrExit(endpoint->mIsAdvertising == FALSE, ChipLogError(DeviceLayer, "FAIL: Advertising already enabled in %s", __func__));
+    VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
+
+    adv = BluezAdvertisingCreate(endpoint);
+    VerifyOrExit(adv != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adv in %s", __func__));
+
+exit:
+    return G_SOURCE_REMOVE;
+}
+
+static gboolean BluezAdvStart(BluezEndpoint * endpoint)
+{
+    GDBusObject * adapter;
+    BluezLEAdvertisingManager1 * advMgr = nullptr;
+    GVariantBuilder optionsBuilder;
+    GVariant * options;
+
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+    VerifyOrExit(!endpoint->mIsAdvertising,
+                 ChipLogError(DeviceLayer, "FAIL: Advertising has already been enabled in %s", __func__));
+    VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
+
+    adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
+    VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
+
+    advMgr = bluez_object_get_leadvertising_manager1(BLUEZ_OBJECT(adapter));
+    VerifyOrExit(advMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__));
+
+    g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}"));
+    options = g_variant_builder_end(&optionsBuilder);
+
+    bluez_leadvertising_manager1_call_register_advertisement(advMgr, endpoint->mpAdvPath, options, nullptr, BluezAdvStartDone,
+                                                             endpoint);
+
+exit:
+    return G_SOURCE_REMOVE;
+}
+
+static gboolean BluezAdvStop(BluezEndpoint * endpoint)
+{
+    GDBusObject * adapter;
+    BluezLEAdvertisingManager1 * advMgr = nullptr;
+
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+    VerifyOrExit(endpoint->mIsAdvertising,
+                 ChipLogError(DeviceLayer, "FAIL: Advertising has already been disabled in %s", __func__));
+    VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
+
+    adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
+    VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
+
+    advMgr = bluez_object_get_leadvertising_manager1(BLUEZ_OBJECT(adapter));
+    VerifyOrExit(advMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__));
+
+    bluez_leadvertising_manager1_call_unregister_advertisement(advMgr, endpoint->mpAdvPath, nullptr, BluezAdvStopDone, endpoint);
+
+exit:
+    return G_SOURCE_REMOVE;
+}
+
+static gboolean BluezCharacteristicReadValue(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
+                                             GVariant * aOptions)
+{
+    GVariant * val;
+    ChipLogDetail(DeviceLayer, "Received BluezCharacteristicReadValue");
+    val = bluez_gatt_characteristic1_get_value(aChar);
+    bluez_gatt_characteristic1_complete_read_value(aChar, aInvocation, val);
+    return TRUE;
+}
+
+#if CHIP_BLUEZ_CHAR_WRITE_VALUE
+static gboolean BluezCharacteristicWriteValue(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
+                                              GVariant * aValue, GVariant * aOptions, gpointer apEndpoint)
+{
+    const uint8_t * tmpBuf;
+    uint8_t * buf;
+    size_t len;
+    bool isSuccess         = false;
+    BluezConnection * conn = NULL;
+
+    BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
+    VerifyOrExit(endpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+
+    VerifyOrExit(aValue != NULL, ChipLogError(DeviceLayer, "aValue is NULL in %s", __func__));
+
+    conn = GetBluezConnectionViaDevice(endpoint);
+    VerifyOrExit(conn != NULL,
+                 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No CHIP Bluez connection"));
+
+    bluez_gatt_characteristic1_set_value(aChar, g_variant_ref(aValue));
+
+    tmpBuf = (uint8_t *) (g_variant_get_fixed_array(aValue, &len, sizeof(uint8_t)));
+    buf    = (uint8_t *) (g_memdup(tmpBuf, len));
+
+    BLEManagerImpl::HandleRXCharWrite(conn, buf, len);
+    bluez_gatt_characteristic1_complete_write_value(aChar, aInvocation);
+    isSuccess = true;
+
+exit:
+    return isSuccess ? TRUE : FALSE;
+}
+#endif
+
+static gboolean BluezCharacteristicWriteValueError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
+                                                   GVariant * aValue, GVariant * aOptions, gpointer apClosure)
+{
+    ChipLogDetail(DeviceLayer, "BluezCharacteristicWriteValueError");
+    g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
+                                               "Write for characteristic is unsupported");
+    return TRUE;
+}
+
+static gboolean BluezCharacteristicWriteFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apEndpoint)
+{
+    GVariant * newVal;
+    gchar * buf;
+    ssize_t len;
+    int fd;
+    bool isSuccess = false;
+
+    BluezConnection * conn = static_cast<BluezConnection *>(apEndpoint);
+
+    VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "No CHIP Bluez connection in %s", __func__));
+
+    VerifyOrExit(!(aCond & G_IO_HUP), ChipLogError(DeviceLayer, "INFO: socket disconnected in %s", __func__));
+    VerifyOrExit(!(aCond & (G_IO_ERR | G_IO_NVAL)), ChipLogError(DeviceLayer, "INFO: socket error in %s", __func__));
+    VerifyOrExit(aCond == G_IO_IN, ChipLogError(DeviceLayer, "FAIL: error in %s", __func__));
+
+    ChipLogDetail(DeviceLayer, "c1 %s mtu, %d", __func__, conn->mMtu);
+
+    buf = static_cast<gchar *>(g_malloc(conn->mMtu));
+    fd  = g_io_channel_unix_get_fd(aChannel);
+
+    len = read(fd, buf, conn->mMtu);
+
+    VerifyOrExit(len > 0, ChipLogError(DeviceLayer, "FAIL: short read in %s (%d)", __func__, len));
+
+    // Casting len to size_t is safe, since we ensured that it's not negative.
+    newVal = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, buf, static_cast<size_t>(len), sizeof(uint8_t));
+
+    bluez_gatt_characteristic1_set_value(conn->mpC1, newVal);
+    BLEManagerImpl::HandleRXCharWrite(conn, reinterpret_cast<uint8_t *>(buf), static_cast<size_t>(len));
+    isSuccess = true;
+
+exit:
+    return isSuccess ? TRUE : FALSE;
+}
+
+static void Bluez_gatt_characteristic1_complete_acquire_write_with_fd(GDBusMethodInvocation * invocation, int fd, guint16 mtu)
+{
+    GUnixFDList * fd_list = g_unix_fd_list_new();
+    int index;
+
+    index = g_unix_fd_list_append(fd_list, fd, nullptr);
+
+    g_dbus_method_invocation_return_value_with_unix_fd_list(invocation, g_variant_new("(@hq)", g_variant_new_handle(index), mtu),
+                                                            fd_list);
+}
+
+static gboolean bluezCharacteristicDestroyFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apClosure)
+{
+    return G_SOURCE_REMOVE;
+}
+
+static gboolean BluezCharacteristicAcquireWrite(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
+                                                GVariant * aOptions, gpointer apEndpoint)
+{
+    int fds[2] = { -1, -1 };
+    GIOChannel * channel;
+    char * errStr;
+    GVariantDict options;
+    bool isSuccess         = false;
+    BluezConnection * conn = nullptr;
+
+    BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+
+    conn = GetBluezConnectionViaDevice(endpoint);
+    VerifyOrExit(conn != nullptr,
+                 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
+
+    ChipLogDetail(DeviceLayer, "BluezCharacteristicAcquireWrite is called, conn: %p", conn);
+
+    if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0)
+    {
+        errStr = strerror(errno);
+        ChipLogError(DeviceLayer, "FAIL: socketpair: %s in %s", errStr, __func__);
+        g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "FD creation failed");
+        SuccessOrExit(false);
+    }
+
+    g_variant_dict_init(&options, aOptions);
+    if (g_variant_dict_contains(&options, "mtu") == TRUE)
+    {
+        GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
+        conn->mMtu   = g_variant_get_uint16(v);
+    }
+    else
+    {
+        ChipLogError(DeviceLayer, "FAIL: no MTU in options in %s", __func__);
+        g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.InvalidArguments", "MTU negotiation failed");
+        SuccessOrExit(false);
+    }
+
+    channel = g_io_channel_unix_new(fds[0]);
+    g_io_channel_set_encoding(channel, nullptr, nullptr);
+    g_io_channel_set_close_on_unref(channel, TRUE);
+    g_io_channel_set_buffered(channel, FALSE);
+
+    conn->mC1Channel.mpChannel = channel;
+    conn->mC1Channel.mWatch    = g_io_add_watch(channel, static_cast<GIOCondition>(G_IO_HUP | G_IO_IN | G_IO_ERR | G_IO_NVAL),
+                                             BluezCharacteristicWriteFD, conn);
+
+    bluez_gatt_characteristic1_set_write_acquired(aChar, TRUE);
+
+    Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu);
+    close(fds[1]);
+    isSuccess = true;
+
+exit:
+    return isSuccess ? TRUE : FALSE;
+}
+
+static gboolean BluezCharacteristicAcquireWriteError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
+                                                     GVariant * aOptions)
+{
+    ChipLogDetail(DeviceLayer, "BluezCharacteristicAcquireWriteError is called");
+    g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
+                                               "AcquireWrite for characteristic is unsupported");
+    return TRUE;
+}
+
+static gboolean BluezCharacteristicAcquireNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
+                                                 GVariant * aOptions, gpointer apEndpoint)
+{
+    int fds[2] = { -1, -1 };
+    GIOChannel * channel;
+    char * errStr;
+    GVariantDict options;
+    BluezConnection * conn = nullptr;
+    bool isSuccess         = false;
+
+    BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+
+    conn = GetBluezConnectionViaDevice(endpoint);
+    VerifyOrExit(conn != nullptr,
+                 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
+
+    g_variant_dict_init(&options, aOptions);
+    if ((g_variant_dict_contains(&options, "mtu") == TRUE))
+    {
+        GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
+        conn->mMtu   = g_variant_get_uint16(v);
+    }
+
+    if (bluez_gatt_characteristic1_get_notifying(aChar))
+    {
+        g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotPermitted", "Already notifying");
+    }
+    if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0)
+    {
+        errStr = strerror(errno);
+        ChipLogError(DeviceLayer, "FAIL: socketpair: %s in %s", errStr, __func__);
+        g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "FD creation failed");
+        SuccessOrExit(false);
+    }
+    channel = g_io_channel_unix_new(fds[0]);
+    g_io_channel_set_encoding(channel, nullptr, nullptr);
+    g_io_channel_set_close_on_unref(channel, TRUE);
+    g_io_channel_set_buffered(channel, FALSE);
+    conn->mC2Channel.mpChannel = channel;
+    conn->mC2Channel.mWatch =
+        g_io_add_watch_full(channel, G_PRIORITY_DEFAULT_IDLE, static_cast<GIOCondition>(G_IO_HUP | G_IO_ERR | G_IO_NVAL),
+                            bluezCharacteristicDestroyFD, conn, nullptr);
+
+    bluez_gatt_characteristic1_set_notify_acquired(aChar, TRUE);
+
+    // same reply as for AcquireWrite
+    Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu);
+    close(fds[1]);
+
+    conn->mIsNotify = true;
+    BLEManagerImpl::HandleTXCharCCCDWrite(conn);
+    isSuccess = true;
+
+exit:
+    return isSuccess ? TRUE : FALSE;
+}
+
+static gboolean BluezCharacteristicAcquireNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
+                                                      GVariant * aOptions)
+{
+    ChipLogDetail(DeviceLayer, "TRACE: AcquireNotify is called");
+    g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
+                                               "AcquireNotify for characteristic is unsupported");
+    return TRUE;
+}
+
+static gboolean BluezCharacteristicStartNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
+                                               gpointer apEndpoint)
+{
+    bool isSuccess         = false;
+    BluezConnection * conn = nullptr;
+
+    BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+
+    conn = GetBluezConnectionViaDevice(endpoint);
+    VerifyOrExit(conn != nullptr,
+                 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
+
+    if (bluez_gatt_characteristic1_get_notifying(aChar) == TRUE)
+    {
+        g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Characteristic is already subscribed");
+    }
+    else
+    {
+        bluez_gatt_characteristic1_complete_start_notify(aChar, aInvocation);
+        bluez_gatt_characteristic1_set_notifying(aChar, TRUE);
+        conn->mIsNotify = true;
+        BLEManagerImpl::HandleTXCharCCCDWrite(conn);
+    }
+    isSuccess = true;
+
+exit:
+    return isSuccess ? TRUE : FALSE;
+}
+
+static gboolean BluezCharacteristicStartNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
+{
+    g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
+                                               "Subscribing to characteristic is unsupported");
+    return TRUE;
+}
+
+static gboolean BluezCharacteristicStopNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
+                                              gpointer apEndpoint)
+{
+    bool isSuccess         = false;
+    BluezConnection * conn = nullptr;
+
+    BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+
+    conn = GetBluezConnectionViaDevice(endpoint);
+    VerifyOrExit(conn != nullptr,
+                 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
+
+    if (bluez_gatt_characteristic1_get_notifying(aChar) == FALSE)
+    {
+        g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Characteristic is already unsubscribed");
+    }
+    else
+    {
+        bluez_gatt_characteristic1_complete_start_notify(aChar, aInvocation);
+        bluez_gatt_characteristic1_set_notifying(aChar, FALSE);
+    }
+    conn->mIsNotify = false;
+
+    isSuccess = true;
+
+exit:
+    return isSuccess ? TRUE : FALSE;
+}
+
+static gboolean BluezCharacteristicConfirm(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
+                                           gpointer apClosure)
+{
+    BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
+    BluezConnection * conn   = GetBluezConnectionViaDevice(endpoint);
+
+    ChipLogDetail(Ble, "Indication confirmation, %p", conn);
+    BLEManagerImpl::HandleTXComplete(conn);
+
+    return TRUE;
+}
+
+static gboolean BluezCharacteristicStopNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
+{
+    g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed",
+                                               "Unsubscribing from characteristic is unsupported");
+    return TRUE;
+}
+
+static gboolean BluezCharacteristicConfirmError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
+{
+    g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Confirm from characteristic is unsupported");
+    return TRUE;
+}
+
+static gboolean BluezIsDeviceOnAdapter(BluezDevice1 * aDevice, BluezAdapter1 * aAdapter)
+{
+    return strcmp(bluez_device1_get_adapter(aDevice), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aAdapter))) == 0 ? TRUE : FALSE;
+}
+
+static gboolean BluezIsServiceOnDevice(BluezGattService1 * aService, BluezDevice1 * aDevice)
+{
+    return strcmp(bluez_gatt_service1_get_device(aService), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aDevice))) == 0 ? TRUE
+                                                                                                                      : FALSE;
+}
+
+static gboolean BluezIsCharOnService(BluezGattCharacteristic1 * aChar, BluezGattService1 * aService)
+{
+    ChipLogDetail(DeviceLayer, "Char1 %s", bluez_gatt_characteristic1_get_service(aChar));
+    ChipLogDetail(DeviceLayer, "Char1 %s", g_dbus_proxy_get_object_path(G_DBUS_PROXY(aService)));
+    return strcmp(bluez_gatt_characteristic1_get_service(aChar), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aService))) == 0 ? TRUE
+                                                                                                                            : FALSE;
+}
+
+static void BluezConnectionInit(BluezConnection * apConn)
+{
+    // populate the service and the characteristics
+    GList * objects = nullptr;
+    GList * l;
+    BluezEndpoint * endpoint = nullptr;
+
+    VerifyOrExit(apConn != nullptr, ChipLogError(DeviceLayer, "Bluez connection is NULL in %s", __func__));
+
+    endpoint = apConn->mpEndpoint;
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+
+    if (!endpoint->mIsCentral)
+    {
+        apConn->mpService = BLUEZ_GATT_SERVICE1(g_object_ref(apConn->mpEndpoint->mpService));
+        apConn->mpC1      = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(endpoint->mpC1));
+        apConn->mpC2      = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(endpoint->mpC2));
+    }
+    else
+    {
+        objects = g_dbus_object_manager_get_objects(endpoint->mpObjMgr);
+
+        for (l = objects; l != nullptr; l = l->next)
+        {
+            BluezObject * object        = BLUEZ_OBJECT(l->data);
+            BluezGattService1 * service = bluez_object_get_gatt_service1(object);
+
+            if (service != nullptr)
+            {
+                if ((BluezIsServiceOnDevice(service, apConn->mpDevice)) == TRUE &&
+                    (strcmp(bluez_gatt_service1_get_uuid(service), CHIP_BLE_UUID_SERVICE_STRING) == 0))
+                {
+                    apConn->mpService = service;
+                    break;
+                }
+                g_object_unref(service);
+            }
+        }
+
+        VerifyOrExit(apConn->mpService != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL service in %s", __func__));
+
+        for (l = objects; l != nullptr; l = l->next)
+        {
+            BluezObject * object             = BLUEZ_OBJECT(l->data);
+            BluezGattCharacteristic1 * char1 = bluez_object_get_gatt_characteristic1(object);
+
+            if (char1 != nullptr)
+            {
+                if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
+                    (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C1_STRING) == 0))
+                {
+                    apConn->mpC1 = char1;
+                }
+                else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
+                         (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C2_STRING) == 0))
+                {
+                    apConn->mpC2 = char1;
+                }
+                else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
+                         (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C3_STRING) == 0))
+                {
+                    apConn->mpC3 = char1;
+                }
+                else
+                {
+                    g_object_unref(char1);
+                }
+                if ((apConn->mpC1 != nullptr) && (apConn->mpC2 != nullptr))
+                {
+                    break;
+                }
+            }
+        }
+
+        VerifyOrExit(apConn->mpC1 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C1 in %s", __func__));
+        VerifyOrExit(apConn->mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C2 in %s", __func__));
+    }
+
+exit:
+    if (objects != nullptr)
+        g_list_free_full(objects, g_object_unref);
+}
+
+static void BluezOTConnectionDestroy(BluezConnection * aConn)
+{
+    if (aConn)
+    {
+        if (aConn->mpDevice)
+            g_object_unref(aConn->mpDevice);
+        if (aConn->mpService)
+            g_object_unref(aConn->mpService);
+        if (aConn->mpC1)
+            g_object_unref(aConn->mpC1);
+        if (aConn->mpC2)
+            g_object_unref(aConn->mpC2);
+        if (aConn->mpPeerAddress)
+            g_free(aConn->mpPeerAddress);
+        if (aConn->mC1Channel.mWatch > 0)
+            g_source_remove(aConn->mC1Channel.mWatch);
+        if (aConn->mC1Channel.mpChannel)
+            g_io_channel_unref(aConn->mC1Channel.mpChannel);
+        if (aConn->mC2Channel.mWatch > 0)
+            g_source_remove(aConn->mC2Channel.mWatch);
+        if (aConn->mC2Channel.mpChannel)
+            g_io_channel_unref(aConn->mC2Channel.mpChannel);
+
+        g_free(aConn);
+    }
+}
+
+static BluezGattCharacteristic1 * BluezCharacteristicCreate(BluezGattService1 * aService, const char * aCharName,
+                                                            const char * aUUID, GDBusObjectManagerServer * aRoot)
+{
+    char * servicePath = g_strdup(g_dbus_object_get_object_path(g_dbus_interface_get_object(G_DBUS_INTERFACE(aService))));
+    char * charPath    = g_strdup_printf("%s/%s", servicePath, aCharName);
+    BluezObjectSkeleton * object;
+    BluezGattCharacteristic1 * characteristic;
+
+    ChipLogDetail(DeviceLayer, "Create characteristic object at %s", charPath);
+    object = bluez_object_skeleton_new(charPath);
+
+    characteristic = bluez_gatt_characteristic1_skeleton_new();
+    bluez_gatt_characteristic1_set_uuid(characteristic, aUUID);
+    bluez_gatt_characteristic1_set_service(characteristic, servicePath);
+
+    bluez_object_skeleton_set_gatt_characteristic1(object, characteristic);
+    g_dbus_object_manager_server_export(aRoot, G_DBUS_OBJECT_SKELETON(object));
+    g_object_unref(object);
+
+    return characteristic;
+}
+
+static void BluezPeripheralRegisterAppDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
+{
+    GError * error              = nullptr;
+    BluezGattManager1 * gattMgr = BLUEZ_GATT_MANAGER1(aObject);
+
+    gboolean success = bluez_gatt_manager1_call_register_application_finish(gattMgr, aResult, &error);
+
+    VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: RegisterApplication : %s", error->message));
+
+    BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(true, nullptr);
+    ChipLogDetail(DeviceLayer, "BluezPeripheralRegisterAppDone done");
+
+exit:
+    if (error != nullptr)
+    {
+        BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(false, nullptr);
+        g_error_free(error);
+    }
+}
+
+gboolean BluezPeripheralRegisterApp(BluezEndpoint * endpoint)
+{
+    GDBusObject * adapter;
+    BluezGattManager1 * gattMgr;
+    GVariantBuilder optionsBuilder;
+    GVariant * options;
+
+    VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
+
+    adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
+    VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
+
+    gattMgr = bluez_object_get_gatt_manager1(BLUEZ_OBJECT(adapter));
+    VerifyOrExit(gattMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL gattMgr in %s", __func__));
+
+    g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}"));
+    options = g_variant_builder_end(&optionsBuilder);
+
+    bluez_gatt_manager1_call_register_application(gattMgr, endpoint->mpRootPath, options, nullptr, BluezPeripheralRegisterAppDone,
+                                                  nullptr);
+
+exit:
+    return G_SOURCE_REMOVE;
+}
+
+/// Update the table of open BLE connections whevener a new device is spotted or its attributes have changed.
+static void UpdateConnectionTable(BluezDevice1 * apDevice, BluezEndpoint & aEndpoint)
+{
+    const gchar * objectPath     = g_dbus_proxy_get_object_path(G_DBUS_PROXY(apDevice));
+    BluezConnection * connection = static_cast<BluezConnection *>(g_hash_table_lookup(aEndpoint.mpConnMap, objectPath));
+
+    if (connection != nullptr && !bluez_device1_get_connected(apDevice))
+    {
+        ChipLogDetail(DeviceLayer, "Bluez disconnected");
+        BLEManagerImpl::CHIPoBluez_ConnectionClosed(connection);
+        // TODO: the connection object should be released after BLEManagerImpl finishes cleaning up its resources
+        // after the disconnection. Releasing it here doesn't cause any issues, but it's error-prone.
+        BluezOTConnectionDestroy(connection);
+        g_hash_table_remove(aEndpoint.mpConnMap, objectPath);
+        return;
+    }
+
+    if (connection == nullptr && !bluez_device1_get_connected(apDevice) && aEndpoint.mIsCentral)
+    {
+        return;
+    }
+
+    if (connection == nullptr && bluez_device1_get_connected(apDevice) &&
+        (!aEndpoint.mIsCentral || bluez_device1_get_services_resolved(apDevice)))
+    {
+        connection                = g_new0(BluezConnection, 1);
+        connection->mpPeerAddress = g_strdup(bluez_device1_get_address(apDevice));
+        connection->mpDevice      = static_cast<BluezDevice1 *>(g_object_ref(apDevice));
+        connection->mpEndpoint    = &aEndpoint;
+        BluezConnectionInit(connection);
+        aEndpoint.mpPeerDevicePath = g_strdup(objectPath);
+        g_hash_table_insert(aEndpoint.mpConnMap, aEndpoint.mpPeerDevicePath, connection);
+
+        ChipLogDetail(DeviceLayer, "New BLE connection %p, device %s, path %s", connection, connection->mpPeerAddress,
+                      aEndpoint.mpPeerDevicePath);
+
+        BLEManagerImpl::HandleNewConnection(connection);
+    }
+}
+
+static void BluezSignalInterfacePropertiesChanged(GDBusObjectManagerClient * aManager, GDBusObjectProxy * aObject,
+                                                  GDBusProxy * aInterface, GVariant * aChangedProperties,
+                                                  const gchar * const * aInvalidatedProps, gpointer apClosure)
+{
+    BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
+    VerifyOrReturn(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+    VerifyOrReturn(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
+    VerifyOrReturn(strcmp(g_dbus_proxy_get_interface_name(aInterface), DEVICE_INTERFACE) == 0, );
+
+    BluezDevice1 * device = BLUEZ_DEVICE1(aInterface);
+    VerifyOrReturn(BluezIsDeviceOnAdapter(device, endpoint->mpAdapter));
+
+    UpdateConnectionTable(device, *endpoint);
+}
+
+static void BluezHandleNewDevice(BluezDevice1 * device, BluezEndpoint * apEndpoint)
+{
+    VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+    if (apEndpoint->mIsCentral)
+    {
+        return;
+    }
+
+    // We need to handle device connection both this function and BluezSignalInterfacePropertiesChanged
+    // When a device is connected for first time, this function will be triggerred.
+    // The future connections for the same device will trigger ``Connect'' property change.
+    // TODO: Factor common code in the two function.
+    BluezConnection * conn;
+    VerifyOrExit(bluez_device1_get_connected(device), ChipLogError(DeviceLayer, "FAIL: device is not connected"));
+
+    conn = static_cast<BluezConnection *>(
+        g_hash_table_lookup(apEndpoint->mpConnMap, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))));
+    VerifyOrExit(conn == nullptr,
+                 ChipLogError(DeviceLayer, "FAIL: connection already tracked: conn: %x new device: %s", conn,
+                              g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))));
+
+    conn                = g_new0(BluezConnection, 1);
+    conn->mpPeerAddress = g_strdup(bluez_device1_get_address(device));
+    conn->mpDevice      = static_cast<BluezDevice1 *>(g_object_ref(device));
+    conn->mpEndpoint    = apEndpoint;
+    BluezConnectionInit(conn);
+    apEndpoint->mpPeerDevicePath = g_strdup(g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)));
+    ChipLogDetail(DeviceLayer, "Device %s (Path: %s) Connected", conn->mpPeerAddress, apEndpoint->mpPeerDevicePath);
+    g_hash_table_insert(apEndpoint->mpConnMap, g_strdup(g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))), conn);
+
+exit:
+    return;
+}
+
+static void BluezSignalOnObjectAdded(GDBusObjectManager * aManager, GDBusObject * aObject, BluezEndpoint * endpoint)
+{
+    // TODO: right now we do not handle addition/removal of adapters
+    // Primary focus here is to handle addition of a device
+    BluezDevice1 * device = bluez_object_get_device1(BLUEZ_OBJECT(aObject));
+    if (device == nullptr)
+    {
+        return;
+    }
+
+    if (BluezIsDeviceOnAdapter(device, endpoint->mpAdapter) == TRUE)
+    {
+        BluezHandleNewDevice(device, endpoint);
+    }
+
+    g_object_unref(device);
+}
+
+static void BluezSignalOnObjectRemoved(GDBusObjectManager * aManager, GDBusObject * aObject, gpointer apClosure)
+{
+    // TODO: for Device1, lookup connection, and call otPlatTobleHandleDisconnected
+    // for Adapter1: unclear, crash if this pertains to our adapter? at least null out the endpoint->mpAdapter.
+    // for Characteristic1, or GattService -- handle here via calling otPlatTobleHandleDisconnected, or ignore.
+}
+
+static BluezGattService1 * BluezServiceCreate(gpointer apClosure)
+{
+    BluezObjectSkeleton * object;
+    BluezGattService1 * service;
+    BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
+
+    endpoint->mpServicePath = g_strdup_printf("%s/service", endpoint->mpRootPath);
+    ChipLogDetail(DeviceLayer, "CREATE service object at %s", endpoint->mpServicePath);
+    object = bluez_object_skeleton_new(endpoint->mpServicePath);
+
+    service = bluez_gatt_service1_skeleton_new();
+    bluez_gatt_service1_set_uuid(service, "0xFEAF");
+    // device is only valid for remote services
+    bluez_gatt_service1_set_primary(service, TRUE);
+
+    // includes -- unclear whether required.  Might be filled in later
+    bluez_object_skeleton_set_gatt_service1(object, service);
+    g_dbus_object_manager_server_export(endpoint->mpRoot, G_DBUS_OBJECT_SKELETON(object));
+    g_object_unref(object);
+
+    return service;
+}
+
+static void bluezObjectsSetup(BluezEndpoint * apEndpoint)
+{
+    GList * objects = nullptr;
+    GList * l;
+    char * expectedPath = nullptr;
+
+    VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+
+    expectedPath = g_strdup_printf("%s/hci%d", BLUEZ_PATH, apEndpoint->mAdapterId);
+    objects      = g_dbus_object_manager_get_objects(apEndpoint->mpObjMgr);
+
+    for (l = objects; l != nullptr && apEndpoint->mpAdapter == nullptr; l = l->next)
+    {
+        BluezObject * object = BLUEZ_OBJECT(l->data);
+        GList * interfaces;
+        GList * ll;
+        interfaces = g_dbus_object_get_interfaces(G_DBUS_OBJECT(object));
+
+        for (ll = interfaces; ll != nullptr; ll = ll->next)
+        {
+            if (BLUEZ_IS_ADAPTER1(ll->data))
+            { // we found the adapter
+                BluezAdapter1 * adapter = BLUEZ_ADAPTER1(ll->data);
+                char * addr             = const_cast<char *>(bluez_adapter1_get_address(adapter));
+                if (apEndpoint->mpAdapterAddr == nullptr) // no adapter address provided, bind to the hci indicated by nodeid
+                {
+                    if (strcmp(g_dbus_proxy_get_object_path(G_DBUS_PROXY(adapter)), expectedPath) == 0)
+                    {
+                        apEndpoint->mpAdapter = static_cast<BluezAdapter1 *>(g_object_ref(adapter));
+                    }
+                }
+                else
+                {
+                    if (strcmp(apEndpoint->mpAdapterAddr, addr) == 0)
+                    {
+                        apEndpoint->mpAdapter = static_cast<BluezAdapter1 *>(g_object_ref(adapter));
+                    }
+                }
+            }
+        }
+        g_list_free_full(interfaces, g_object_unref);
+    }
+    VerifyOrExit(apEndpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL apEndpoint->mpAdapter in %s", __func__));
+    bluez_adapter1_set_powered(apEndpoint->mpAdapter, TRUE);
+
+    // Setting "Discoverable" to False on the adapter and to True on the advertisement convinces
+    // Bluez to set "BR/EDR Not Supported" flag. Bluez doesn't provide API to do that explicitly
+    // and the flag is necessary to force using LE transport.
+    bluez_adapter1_set_discoverable(apEndpoint->mpAdapter, FALSE);
+
+exit:
+    g_list_free_full(objects, g_object_unref);
+    g_free(expectedPath);
+}
+
+static BluezConnection * GetBluezConnectionViaDevice(BluezEndpoint * apEndpoint)
+{
+    BluezConnection * retval =
+        static_cast<BluezConnection *>(g_hash_table_lookup(apEndpoint->mpConnMap, apEndpoint->mpPeerDevicePath));
+    // ChipLogError(DeviceLayer, "acquire connection object %p in (%s)", retval, __func__);
+    return retval;
+}
+
+#if CHIP_BLUEZ_CENTRAL_SUPPORT
+static BluezConnection * BluezCharacteristicGetBluezConnection(BluezGattCharacteristic1 * aChar, GVariant * aOptions,
+                                                               BluezEndpoint * apEndpoint)
+{
+    BluezConnection * retval = NULL;
+    const gchar * path       = NULL;
+    GVariantDict options;
+    GVariant * v;
+
+    VerifyOrExit(apEndpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+    VerifyOrExit(apEndpoint->mIsCentral, );
+
+    /* TODO Unfortunately StartNotify/StopNotify doesn't provide info about
+     * peer device in call params so we need look this up ourselves.
+     */
+    if (aOptions == NULL)
+    {
+        GList * objects;
+        GList * l;
+        GList * ll;
+
+        objects = g_dbus_object_manager_get_objects(apEndpoint->mpObjMgr);
+        for (l = objects; l != NULL; l = l->next)
+        {
+            BluezDevice1 * device = bluez_object_get_device1(BLUEZ_OBJECT(l->data));
+            if (device != NULL)
+            {
+                if (BluezIsDeviceOnAdapter(device, apEndpoint->mpAdapter))
+                {
+                    for (ll = objects; ll != NULL; ll = ll->next)
+                    {
+                        BluezGattService1 * service = bluez_object_get_gatt_service1(BLUEZ_OBJECT(ll->data));
+                        if (service != NULL)
+                        {
+                            if (BluezIsServiceOnDevice(service, device))
+                            {
+                                if (BluezIsCharOnService(aChar, service))
+                                {
+                                    retval = (BluezConnection *) g_hash_table_lookup(
+                                        apEndpoint->mpConnMap, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)));
+                                }
+                            }
+                            g_object_unref(service);
+                            if (retval != NULL)
+                                break;
+                        }
+                    }
+                }
+                g_object_unref(device);
+                if (retval != NULL)
+                    break;
+            }
+        }
+
+        g_list_free_full(objects, g_object_unref);
+    }
+    else
+    {
+        g_variant_dict_init(&options, aOptions);
+
+        v = g_variant_dict_lookup_value(&options, "device", G_VARIANT_TYPE_OBJECT_PATH);
+
+        VerifyOrExit(v != NULL, ChipLogError(DeviceLayer, "FAIL: No device option in dictionary (%s)", __func__));
+
+        path = g_variant_get_string(v, NULL);
+
+        retval = (BluezConnection *) g_hash_table_lookup(apEndpoint->mpConnMap, path);
+    }
+
+exit:
+    return retval;
+}
+#endif // CHIP_BLUEZ_CENTRAL_SUPPORT
+
+void EndpointCleanup(BluezEndpoint * apEndpoint)
+{
+    if (apEndpoint != nullptr)
+    {
+        if (apEndpoint->mpOwningName != nullptr)
+        {
+            g_free(apEndpoint->mpOwningName);
+            apEndpoint->mpOwningName = nullptr;
+        }
+        if (apEndpoint->mpAdapterName != nullptr)
+        {
+            g_free(apEndpoint->mpAdapterName);
+            apEndpoint->mpAdapterName = nullptr;
+        }
+        if (apEndpoint->mpAdapterAddr != nullptr)
+        {
+            g_free(apEndpoint->mpAdapterAddr);
+            apEndpoint->mpAdapterAddr = nullptr;
+        }
+        if (apEndpoint->mpRootPath != nullptr)
+        {
+            g_free(apEndpoint->mpRootPath);
+            apEndpoint->mpRootPath = nullptr;
+        }
+        if (apEndpoint->mpAdvPath != nullptr)
+        {
+            g_free(apEndpoint->mpAdvPath);
+            apEndpoint->mpAdvPath = nullptr;
+        }
+        if (apEndpoint->mpServicePath != nullptr)
+        {
+            g_free(apEndpoint->mpServicePath);
+            apEndpoint->mpServicePath = nullptr;
+        }
+        if (apEndpoint->mpConnMap != nullptr)
+        {
+            g_hash_table_destroy(apEndpoint->mpConnMap);
+            apEndpoint->mpConnMap = nullptr;
+        }
+        if (apEndpoint->mpAdvertisingUUID != nullptr)
+        {
+            g_free(apEndpoint->mpAdvertisingUUID);
+            apEndpoint->mpAdvertisingUUID = nullptr;
+        }
+        if (apEndpoint->mpPeerDevicePath != nullptr)
+        {
+            g_free(apEndpoint->mpPeerDevicePath);
+            apEndpoint->mpPeerDevicePath = nullptr;
+        }
+        g_free(apEndpoint->mpConnectCancellable);
+        g_free(apEndpoint);
+    }
+}
+
+int BluezObjectsCleanup(BluezEndpoint * apEndpoint)
+{
+    g_object_unref(apEndpoint->mpAdapter);
+    EndpointCleanup(apEndpoint);
+    return 0;
+}
+
+#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
+static void UpdateAdditionalDataCharacteristic(BluezGattCharacteristic1 * characteristic)
+{
+    if (characteristic == nullptr)
+    {
+        return;
+    }
+
+    // Construct the TLV for the additional data
+    GVariant * cValue = nullptr;
+    gpointer data;
+    CHIP_ERROR err = CHIP_NO_ERROR;
+    chip::System::PacketBufferHandle bufferHandle;
+
+    char serialNumber[ConfigurationManager::kMaxSerialNumberLength + 1];
+    size_t serialNumberSize  = 0;
+    uint16_t lifetimeCounter = 0;
+    BitFlags<AdditionalDataFields> additionalDataFields;
+
+#if CHIP_ENABLE_ROTATING_DEVICE_ID
+    err = ConfigurationMgr().GetSerialNumber(serialNumber, sizeof(serialNumber), serialNumberSize);
+    SuccessOrExit(err);
+    err = ConfigurationMgr().GetLifetimeCounter(lifetimeCounter);
+    SuccessOrExit(err);
+
+    additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId);
+#endif
+
+    err = AdditionalDataPayloadGenerator().generateAdditionalDataPayload(lifetimeCounter, serialNumber, serialNumberSize,
+                                                                         bufferHandle, additionalDataFields);
+    SuccessOrExit(err);
+
+    data = g_memdup(bufferHandle->Start(), bufferHandle->DataLength());
+
+    cValue = g_variant_new_from_data(G_VARIANT_TYPE("ay"), data, bufferHandle->DataLength(), TRUE, g_free, data);
+    bluez_gatt_characteristic1_set_value(characteristic, cValue);
+
+    return;
+
+exit:
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(DeviceLayer, "Failed to generate TLV encoded Additional Data", __func__);
+    }
+    return;
+}
+#endif
+
+static void BluezPeripheralObjectsSetup(gpointer apClosure)
+{
+
+    static const char * const c1_flags[] = { "write", nullptr };
+    static const char * const c2_flags[] = { "read", "indicate", nullptr };
+    static const char * const c3_flags[] = { "read", nullptr };
+
+    BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+
+    endpoint->mpService = BluezServiceCreate(apClosure);
+    // C1 characteristic
+    endpoint->mpC1 =
+        BluezCharacteristicCreate(endpoint->mpService, g_strdup("c1"), g_strdup(CHIP_PLAT_BLE_UUID_C1_STRING), endpoint->mpRoot);
+    bluez_gatt_characteristic1_set_flags(endpoint->mpC1, c1_flags);
+
+    g_signal_connect(endpoint->mpC1, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
+    g_signal_connect(endpoint->mpC1, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
+    g_signal_connect(endpoint->mpC1, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWrite), apClosure);
+    g_signal_connect(endpoint->mpC1, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotifyError), NULL);
+    g_signal_connect(endpoint->mpC1, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotifyError), NULL);
+    g_signal_connect(endpoint->mpC1, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotifyError), NULL);
+    g_signal_connect(endpoint->mpC1, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirmError), NULL);
+
+    endpoint->mpC2 =
+        BluezCharacteristicCreate(endpoint->mpService, g_strdup("c2"), g_strdup(CHIP_PLAT_BLE_UUID_C2_STRING), endpoint->mpRoot);
+    bluez_gatt_characteristic1_set_flags(endpoint->mpC2, c2_flags);
+    g_signal_connect(endpoint->mpC2, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
+    g_signal_connect(endpoint->mpC2, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
+    g_signal_connect(endpoint->mpC2, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), NULL);
+    g_signal_connect(endpoint->mpC2, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotify), apClosure);
+    g_signal_connect(endpoint->mpC2, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotify), apClosure);
+    g_signal_connect(endpoint->mpC2, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotify), apClosure);
+    g_signal_connect(endpoint->mpC2, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirm), apClosure);
+
+    ChipLogDetail(DeviceLayer, "CHIP BTP C1 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC1));
+    ChipLogDetail(DeviceLayer, "CHIP BTP C2 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC2));
+
+#if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
+    ChipLogDetail(DeviceLayer, "CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING is TRUE");
+    // Additional data characteristics
+    endpoint->mpC3 =
+        BluezCharacteristicCreate(endpoint->mpService, g_strdup("c3"), g_strdup(CHIP_PLAT_BLE_UUID_C3_STRING), endpoint->mpRoot);
+    bluez_gatt_characteristic1_set_flags(endpoint->mpC3, c3_flags);
+    g_signal_connect(endpoint->mpC3, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
+    g_signal_connect(endpoint->mpC3, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
+    g_signal_connect(endpoint->mpC3, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), NULL);
+    g_signal_connect(endpoint->mpC3, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotify), apClosure);
+    g_signal_connect(endpoint->mpC3, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotify), apClosure);
+    g_signal_connect(endpoint->mpC3, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotify), apClosure);
+    g_signal_connect(endpoint->mpC3, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirm), apClosure);
+    // update the characteristic value
+    UpdateAdditionalDataCharacteristic(endpoint->mpC3);
+    ChipLogDetail(DeviceLayer, "CHIP BTP C3 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC3));
+#else
+    ChipLogDetail(DeviceLayer, "CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING is FALSE");
+    (void) c3_flags;
+#endif
+
+exit:
+    return;
+}
+
+static void BluezOnBusAcquired(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
+{
+    BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+
+    ChipLogDetail(DeviceLayer, "TRACE: Bus acquired for name %s", aName);
+
+    if (!endpoint->mIsCentral)
+    {
+        endpoint->mpRootPath = g_strdup_printf("/chipoble/%04x", getpid() & 0xffff);
+        endpoint->mpRoot     = g_dbus_object_manager_server_new(endpoint->mpRootPath);
+        g_dbus_object_manager_server_set_connection(endpoint->mpRoot, aConn);
+
+        BluezPeripheralObjectsSetup(apClosure);
+    }
+
+exit:
+    return;
+}
+
+#if CHIP_BLUEZ_NAME_MONITOR
+static void BluezOnNameAcquired(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
+{
+    ChipLogDetail(DeviceLayer, "TRACE: Owning name: Acquired %s", aName);
+}
+
+static void BluezOnNameLost(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
+{
+    ChipLogDetail(DeviceLayer, "TRACE: Owning name: lost %s", aName);
+}
+#endif
+
+static int StartupEndpointBindings(BluezEndpoint * endpoint)
+{
+    GDBusObjectManager * manager;
+    GError * error         = nullptr;
+    GDBusConnection * conn = nullptr;
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
+
+    conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
+    VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "FAIL: get bus sync in %s, error: %s", __func__, error->message));
+
+    if (endpoint->mpAdapterName != nullptr)
+        endpoint->mpOwningName = g_strdup_printf("%s", endpoint->mpAdapterName);
+    else
+        endpoint->mpOwningName = g_strdup_printf("C-%04x", getpid() & 0xffff);
+
+    BluezOnBusAcquired(conn, endpoint->mpOwningName, endpoint);
+
+    manager = g_dbus_object_manager_client_new_sync(
+        conn, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, BLUEZ_INTERFACE, "/", bluez_object_manager_client_get_proxy_type,
+        nullptr /* unused user data in the Proxy Type Func */, nullptr /*destroy notify */, nullptr /* cancellable */, &error);
+
+    VerifyOrExit(manager != nullptr, ChipLogError(DeviceLayer, "FAIL: Error getting object manager client: %s", error->message));
+
+    endpoint->mpObjMgr = manager;
+
+    bluezObjectsSetup(endpoint);
+
+    g_signal_connect(manager, "object-added", G_CALLBACK(BluezSignalOnObjectAdded), endpoint);
+    g_signal_connect(manager, "object-removed", G_CALLBACK(BluezSignalOnObjectRemoved), endpoint);
+    g_signal_connect(manager, "interface-proxy-properties-changed", G_CALLBACK(BluezSignalInterfacePropertiesChanged), endpoint);
+
+    if (!MainLoop::Instance().SetCleanupFunction(BluezObjectsCleanup, endpoint))
+    {
+        ChipLogError(DeviceLayer, "Failed to schedule cleanup function");
+    }
+
+exit:
+    if (error != nullptr)
+        g_error_free(error);
+
+    return 0;
+}
+
+static gboolean BluezC2Indicate(ConnectionDataBundle * closure)
+{
+    BluezConnection * conn = nullptr;
+    GError * error         = nullptr;
+    GIOStatus status;
+    const char * buf;
+    size_t len, written;
+
+    VerifyOrExit(closure != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__));
+
+    conn = closure->mpConn;
+    VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
+    VerifyOrExit(conn->mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", "NULL C2"));
+
+    if (bluez_gatt_characteristic1_get_notify_acquired(conn->mpC2) == TRUE)
+    {
+        buf = (char *) g_variant_get_fixed_array(closure->mpVal, &len, sizeof(uint8_t));
+        VerifyOrExit(len <= static_cast<size_t>(std::numeric_limits<gssize>::max()),
+                     ChipLogError(DeviceLayer, "FAIL: buffer too large in %s", __func__));
+        status = g_io_channel_write_chars(conn->mC2Channel.mpChannel, buf, static_cast<gssize>(len), &written, &error);
+        g_variant_unref(closure->mpVal);
+        closure->mpVal = nullptr;
+
+        VerifyOrExit(status == G_IO_STATUS_NORMAL, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", error->message));
+    }
+    else
+    {
+        bluez_gatt_characteristic1_set_value(conn->mpC2, closure->mpVal);
+        closure->mpVal = nullptr;
+    }
+
+exit:
+    if (closure != nullptr)
+    {
+        if (closure->mpVal)
+        {
+            g_variant_unref(closure->mpVal);
+        }
+        g_free(closure);
+    }
+
+    if (error != nullptr)
+        g_error_free(error);
+    return G_SOURCE_REMOVE;
+}
+
+static ConnectionDataBundle * MakeConnectionDataBundle(BLE_CONNECTION_OBJECT apConn, const chip::System::PacketBufferHandle & apBuf)
+{
+    ConnectionDataBundle * bundle = g_new(ConnectionDataBundle, 1);
+    bundle->mpConn                = static_cast<BluezConnection *>(apConn);
+    bundle->mpVal =
+        g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, apBuf->Start(), apBuf->DataLength() * sizeof(uint8_t), sizeof(uint8_t));
+    return bundle;
+}
+
+bool SendBluezIndication(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
+{
+    bool success = false;
+
+    VerifyOrExit(!apBuf.IsNull(), ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
+
+    success = MainLoop::Instance().Schedule(BluezC2Indicate, MakeConnectionDataBundle(apConn, apBuf));
+
+exit:
+    return success;
+}
+
+static gboolean BluezDisconnect(void * apClosure)
+{
+    BluezConnection * conn = static_cast<BluezConnection *>(apClosure);
+    GError * error         = nullptr;
+    gboolean success;
+
+    VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "conn is NULL in %s", __func__));
+    VerifyOrExit(conn->mpDevice != nullptr, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", "NULL Device"));
+
+    ChipLogDetail(DeviceLayer, "%s peer=%s", __func__, bluez_device1_get_address(conn->mpDevice));
+
+    success = bluez_device1_call_disconnect_sync(conn->mpDevice, nullptr, &error);
+    VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", error->message));
+
+exit:
+    if (error != nullptr)
+        g_error_free(error);
+    return G_SOURCE_REMOVE;
+}
+
+static int CloseBleconnectionCB(void * apAppState)
+{
+    BluezDisconnect(apAppState);
+    return G_SOURCE_REMOVE;
+}
+
+bool CloseBluezConnection(BLE_CONNECTION_OBJECT apConn)
+{
+    return MainLoop::Instance().RunOnBluezThread(CloseBleconnectionCB, apConn);
+}
+
+CHIP_ERROR StartBluezAdv(BluezEndpoint * apEndpoint)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+    if (!MainLoop::Instance().Schedule(BluezAdvStart, apEndpoint))
+    {
+        err = CHIP_ERROR_INCORRECT_STATE;
+        ChipLogError(Ble, "Failed to schedule BluezAdvStart() on CHIPoBluez thread");
+    }
+    return err;
+}
+
+CHIP_ERROR StopBluezAdv(BluezEndpoint * apEndpoint)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+    if (!MainLoop::Instance().Schedule(BluezAdvStop, apEndpoint))
+    {
+        err = CHIP_ERROR_INCORRECT_STATE;
+        ChipLogError(Ble, "Failed to schedule BluezAdvStop() on CHIPoBluez thread");
+    }
+    return err;
+}
+
+CHIP_ERROR BluezAdvertisementSetup(BluezEndpoint * apEndpoint)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+    if (!MainLoop::Instance().Schedule(BluezAdvSetup, apEndpoint))
+    {
+        err = CHIP_ERROR_INCORRECT_STATE;
+        ChipLogError(Ble, "Failed to schedule BluezAdvertisementSetup() on CHIPoBluez thread");
+    }
+    return err;
+}
+
+CHIP_ERROR BluezGattsAppRegister(BluezEndpoint * apEndpoint)
+{
+    CHIP_ERROR err = CHIP_NO_ERROR;
+    if (!MainLoop::Instance().Schedule(BluezPeripheralRegisterApp, apEndpoint))
+    {
+        err = CHIP_ERROR_INCORRECT_STATE;
+        ChipLogError(Ble, "Failed to schedule BluezPeripheralRegisterApp() on CHIPoBluez thread");
+    }
+    return err;
+}
+
+CHIP_ERROR ConfigureBluezAdv(BLEAdvConfig & aBleAdvConfig, BluezEndpoint * apEndpoint)
+{
+    const char * msg = nullptr;
+    CHIP_ERROR err   = CHIP_NO_ERROR;
+    VerifyOrExit(aBleAdvConfig.mpBleName != nullptr, msg = "FAIL: BLE name is NULL");
+    VerifyOrExit(aBleAdvConfig.mpAdvertisingUUID != nullptr, msg = "FAIL: BLE mpAdvertisingUUID is NULL in %s");
+
+    apEndpoint->mpAdapterName     = g_strdup(aBleAdvConfig.mpBleName);
+    apEndpoint->mpAdvertisingUUID = g_strdup(aBleAdvConfig.mpAdvertisingUUID);
+    apEndpoint->mAdapterId        = aBleAdvConfig.mAdapterId;
+    apEndpoint->mType             = aBleAdvConfig.mType;
+    apEndpoint->mDuration         = aBleAdvConfig.mDuration;
+    apEndpoint->mDuration         = aBleAdvConfig.mDuration;
+
+    err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(apEndpoint->mDeviceIdInfo);
+    SuccessOrExit(err);
+
+exit:
+    if (nullptr != msg)
+    {
+        ChipLogDetail(DeviceLayer, "%s in %s", msg, __func__);
+        err = CHIP_ERROR_INCORRECT_STATE;
+    }
+    return err;
+}
+
+CHIP_ERROR InitBluezBleLayer(bool aIsCentral, char * apBleAddr, BLEAdvConfig & aBleAdvConfig, BluezEndpoint *& apEndpoint)
+{
+    CHIP_ERROR err           = CHIP_NO_ERROR;
+    bool retval              = false;
+    BluezEndpoint * endpoint = nullptr;
+
+    // initialize server endpoint
+    endpoint = g_new0(BluezEndpoint, 1);
+    VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "FAIL: memory allocation in %s", __func__));
+
+    if (apBleAddr != nullptr)
+        endpoint->mpAdapterAddr = g_strdup(apBleAddr);
+    else
+        endpoint->mpAdapterAddr = nullptr;
+
+    endpoint->mpConnMap  = g_hash_table_new(g_str_hash, g_str_equal);
+    endpoint->mIsCentral = aIsCentral;
+
+    if (!aIsCentral)
+    {
+        err = ConfigureBluezAdv(aBleAdvConfig, endpoint);
+        SuccessOrExit(err);
+    }
+    else
+    {
+        endpoint->mAdapterId           = aBleAdvConfig.mAdapterId;
+        endpoint->mpConnectCancellable = g_cancellable_new();
+    }
+
+    err = MainLoop::Instance().EnsureStarted();
+    VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "Failed to start BLE main loop"));
+
+    if (!MainLoop::Instance().ScheduleAndWait(StartupEndpointBindings, endpoint))
+    {
+        ChipLogError(DeviceLayer, "Failed to schedule endpoint initialization");
+        ExitNow();
+    }
+
+    retval = TRUE;
+
+exit:
+    if (retval)
+    {
+        apEndpoint = endpoint;
+        ChipLogDetail(DeviceLayer, "PlatformBlueZInit init success");
+    }
+    else
+    {
+        EndpointCleanup(endpoint);
+    }
+
+    return err;
+}
+
+// BluezSendWriteRequest callbacks
+
+static void SendWriteRequestDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
+{
+    BluezGattCharacteristic1 * c1 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
+    GError * error                = nullptr;
+    gboolean success              = bluez_gatt_characteristic1_call_write_value_finish(c1, aResult, &error);
+
+    VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSendWriteRequest : %s", error->message));
+    BLEManagerImpl::HandleWriteComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection));
+
+exit:
+    if (error != nullptr)
+        g_error_free(error);
+}
+
+static gboolean SendWriteRequestImpl(void * apConnectionData)
+{
+    ConnectionDataBundle * data = static_cast<ConnectionDataBundle *>(apConnectionData);
+    GVariant * options          = nullptr;
+    GVariantBuilder optionsBuilder;
+
+    VerifyOrExit(data != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__));
+    VerifyOrExit(data->mpConn != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
+    VerifyOrExit(data->mpConn->mpC1 != nullptr, ChipLogError(DeviceLayer, "C1 is NULL in %s", __func__));
+
+    g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE_ARRAY);
+    g_variant_builder_add(&optionsBuilder, "{sv}", "type", g_variant_new_string("request"));
+    options = g_variant_builder_end(&optionsBuilder);
+
+    bluez_gatt_characteristic1_call_write_value(data->mpConn->mpC1, data->mpVal, options, nullptr, SendWriteRequestDone,
+                                                data->mpConn);
+
+exit:
+    g_free(data);
+    return G_SOURCE_REMOVE;
+}
+
+bool BluezSendWriteRequest(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
+{
+    bool success = false;
+
+    VerifyOrExit(!apBuf.IsNull(), ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
+
+    success = MainLoop::Instance().RunOnBluezThread(SendWriteRequestImpl, MakeConnectionDataBundle(apConn, apBuf));
+
+exit:
+    return success;
+}
+
+// BluezSubscribeCharacteristic callbacks
+
+static void OnCharacteristicChanged(GDBusProxy * aInterface, GVariant * aChangedProperties, const gchar * const * aInvalidatedProps,
+                                    gpointer apConnection)
+{
+    BLE_CONNECTION_OBJECT connection = static_cast<BLE_CONNECTION_OBJECT>(apConnection);
+    GVariant * value                 = g_variant_lookup_value(aChangedProperties, "Value", G_VARIANT_TYPE_BYTESTRING);
+    VerifyOrReturn(value != nullptr);
+
+    size_t bufferLen;
+    auto buffer = g_variant_get_fixed_array(value, &bufferLen, sizeof(uint8_t));
+    VerifyOrReturn(value != nullptr, ChipLogError(DeviceLayer, "Characteristic value has unexpected type"));
+
+    BLEManagerImpl::HandleTXCharChanged(connection, static_cast<const uint8_t *>(buffer), bufferLen);
+}
+
+static void SubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
+{
+    BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
+    GError * error                = nullptr;
+    gboolean success              = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &error);
+
+    VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSubscribeCharacteristic : %s", error->message));
+
+    // Get notifications on the TX characteristic change (e.g. indication is received)
+    g_signal_connect(c2, "g-properties-changed", G_CALLBACK(OnCharacteristicChanged), apConnection);
+    BLEManagerImpl::HandleSubscribeOpComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection), true);
+
+exit:
+    if (error != nullptr)
+        g_error_free(error);
+}
+
+static gboolean SubscribeCharacteristicImpl(BluezConnection * connection)
+{
+    VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
+    VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__));
+
+    bluez_gatt_characteristic1_call_start_notify(connection->mpC2, nullptr, SubscribeCharacteristicDone, connection);
+
+exit:
+    return G_SOURCE_REMOVE;
+}
+
+bool BluezSubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn)
+{
+    return MainLoop::Instance().Schedule(SubscribeCharacteristicImpl, static_cast<BluezConnection *>(apConn));
+}
+
+// BluezUnsubscribeCharacteristic callbacks
+
+static void UnsubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
+{
+    BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
+    GError * error                = nullptr;
+    gboolean success              = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &error);
+
+    VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezUnsubscribeCharacteristic : %s", error->message));
+
+    // Stop listening to the TX characteristic changes
+    g_signal_handlers_disconnect_by_data(c2, apConnection);
+    BLEManagerImpl::HandleSubscribeOpComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection), false);
+
+exit:
+    if (error != nullptr)
+        g_error_free(error);
+}
+
+static gboolean UnsubscribeCharacteristicImpl(BluezConnection * connection)
+{
+    VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
+    VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__));
+
+    bluez_gatt_characteristic1_call_stop_notify(connection->mpC2, nullptr, UnsubscribeCharacteristicDone, connection);
+
+exit:
+    return G_SOURCE_REMOVE;
+}
+
+bool BluezUnsubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn)
+{
+    return MainLoop::Instance().Schedule(UnsubscribeCharacteristicImpl, static_cast<BluezConnection *>(apConn));
+}
+
+// ConnectDevice callbacks
+
+struct ConnectParams
+{
+    ConnectParams(BluezDevice1 * device, BluezEndpoint * endpoint) : mDevice(device), mEndpoint(endpoint) {}
+    BluezDevice1 * mDevice;
+    BluezEndpoint * mEndpoint;
+};
+
+static void ConnectDeviceDone(GObject * aObject, GAsyncResult * aResult, gpointer)
+{
+    BluezDevice1 * device = BLUEZ_DEVICE1(aObject);
+    GError * error        = nullptr;
+    gboolean success      = bluez_device1_call_connect_finish(device, aResult, &error);
+
+    if (!success)
+    {
+        ChipLogError(DeviceLayer, "FAIL: ConnectDevice : %s", error->message);
+        BLEManagerImpl::HandleConnectFailed(CHIP_ERROR_INTERNAL);
+        ExitNow();
+    }
+
+    ChipLogDetail(DeviceLayer, "ConnectDevice complete");
+
+exit:
+    if (error != nullptr)
+        g_error_free(error);
+}
+
+static gboolean ConnectDeviceImpl(ConnectParams * apParams)
+{
+    BluezDevice1 * device    = apParams->mDevice;
+    BluezEndpoint * endpoint = apParams->mEndpoint;
+
+    assert(device != nullptr);
+    assert(endpoint != nullptr);
+
+    g_cancellable_reset(endpoint->mpConnectCancellable);
+    bluez_device1_call_connect(device, endpoint->mpConnectCancellable, ConnectDeviceDone, nullptr);
+    g_object_unref(device);
+    chip::Platform::Delete(apParams);
+
+    return G_SOURCE_REMOVE;
+}
+
+CHIP_ERROR ConnectDevice(BluezDevice1 * apDevice, BluezEndpoint * apEndpoint)
+{
+    auto params = chip::Platform::New<ConnectParams>(apDevice, apEndpoint);
+    g_object_ref(apDevice);
+
+    if (!MainLoop::Instance().Schedule(ConnectDeviceImpl, params))
+    {
+        ChipLogError(Ble, "Failed to schedule ConnectDeviceImpl() on CHIPoBluez thread");
+        g_object_unref(apDevice);
+        chip::Platform::Delete(params);
+        return CHIP_ERROR_INCORRECT_STATE;
+    }
+
+    return CHIP_NO_ERROR;
+}
+
+void CancelConnect(BluezEndpoint * apEndpoint)
+{
+    assert(apEndpoint->mpConnectCancellable != nullptr);
+    g_cancellable_cancel(apEndpoint->mpConnectCancellable);
+}
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
+#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
diff --git a/src/platform/Tizen/bluez/Helper.h b/src/platform/Tizen/bluez/Helper.h
new file mode 100644 (file)
index 0000000..e77ffc9
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ *
+ *    Copyright (c) 2020 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.
+ */
+
+/*
+ *  Copyright (c) 2016-2019, The OpenThread Authors.
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the copyright holder nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ *    @file
+ *          Provides Bluez dbus implementation for BLE
+ */
+
+#pragma once
+
+#include "Types.h"
+
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+CHIP_ERROR InitBluezBleLayer(bool aIsCentral, char * apBleAddr, BLEAdvConfig & aBleAdvConfig, BluezEndpoint *& apEndpoint);
+bool BluezRunOnBluezThread(int (*aCallback)(void *), void * apClosure);
+bool SendBluezIndication(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf);
+bool CloseBluezConnection(BLE_CONNECTION_OBJECT apConn);
+CHIP_ERROR StartBluezAdv(BluezEndpoint * apEndpoint);
+CHIP_ERROR StopBluezAdv(BluezEndpoint * apEndpoint);
+CHIP_ERROR BluezGattsAppRegister(BluezEndpoint * apEndpoint);
+CHIP_ERROR BluezAdvertisementSetup(BluezEndpoint * apEndpoint);
+
+/// Write to the CHIP RX characteristic on the remote peripheral device
+bool BluezSendWriteRequest(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf);
+/// Subscribe to the CHIP TX characteristic on the remote peripheral device
+bool BluezSubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn);
+/// Unsubscribe from the CHIP TX characteristic on the remote peripheral device
+bool BluezUnsubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn);
+
+CHIP_ERROR ConnectDevice(BluezDevice1 * apDevice, BluezEndpoint * apEndpoint);
+void CancelConnect(BluezEndpoint * apEndpoint);
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
+
+#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
diff --git a/src/platform/Tizen/bluez/MainLoop.cpp b/src/platform/Tizen/bluez/MainLoop.cpp
new file mode 100644 (file)
index 0000000..5ddc7b5
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ *    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 "MainLoop.h"
+
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+
+#include <errno.h>
+#include <pthread.h>
+#include <support/CodeUtils.h>
+#include <support/logging/CHIPLogging.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+namespace {
+
+class Semaphore
+{
+public:
+    Semaphore()
+    {
+        if (sem_init(&mSemaphore, 0 /* shared */, 0 /*value*/) != 0)
+        {
+            ChipLogError(DeviceLayer, "Failed to initialize semaphore.");
+        }
+    }
+
+    ~Semaphore()
+    {
+        if (sem_destroy(&mSemaphore) != 0)
+        {
+            ChipLogError(DeviceLayer, "Failed to destroy semaphore.");
+        }
+    }
+
+    void Post() { sem_post(&mSemaphore); }
+
+    void Wait() { sem_wait(&mSemaphore); }
+
+private:
+    sem_t mSemaphore;
+};
+
+int PostSemaphore(Semaphore * semaphore)
+{
+    semaphore->Post();
+    return 0;
+}
+
+class CallbackIndirection
+{
+public:
+    CallbackIndirection(GSourceFunc f, void * a) : mCallback(f), mArgument(a) {}
+
+    void Wait() { mDoneSemaphore.Wait(); }
+
+    static int Callback(CallbackIndirection * self)
+    {
+        int result = self->mCallback(self->mArgument);
+        self->mDoneSemaphore.Post();
+        return result;
+    }
+
+private:
+    Semaphore mDoneSemaphore;
+    GSourceFunc mCallback;
+    void * mArgument;
+};
+
+} // namespace
+
+MainLoop & MainLoop::Instance()
+{
+    static MainLoop sMainLoop;
+    return sMainLoop;
+}
+
+void * MainLoop::Thread(void * self)
+{
+    MainLoop * loop = reinterpret_cast<MainLoop *>(self);
+
+    ChipLogDetail(DeviceLayer, "TRACE: Bluez mainloop starting %s", __func__);
+    g_main_loop_run(loop->mBluezMainLoop);
+    ChipLogDetail(DeviceLayer, "TRACE: Bluez mainloop stopping %s", __func__);
+
+    if (loop->mCleanup != nullptr)
+    {
+        ChipLogDetail(DeviceLayer, "TRACE: Executing cleanup %s", __func__);
+        loop->mCleanup(loop->mCleanupArgument);
+    }
+
+    return nullptr;
+}
+
+CHIP_ERROR MainLoop::EnsureStarted()
+{
+    if (mBluezMainLoop != nullptr)
+    {
+        return CHIP_NO_ERROR;
+    }
+
+    mBluezMainLoop = g_main_loop_new(nullptr, TRUE);
+    if (mBluezMainLoop == nullptr)
+    {
+        ChipLogError(DeviceLayer, "FAIL: memory alloc in %s", __func__);
+        return CHIP_ERROR_NO_MEMORY;
+    }
+
+    int pthreadErr = pthread_create(&mThread, nullptr, &MainLoop::Thread, reinterpret_cast<void *>(this));
+    int tmpErrno   = errno;
+    if (pthreadErr != 0)
+    {
+        ChipLogError(DeviceLayer, "FAIL: pthread_create (%s) in %s", strerror(tmpErrno), __func__);
+        g_free(mBluezMainLoop);
+        mBluezMainLoop = nullptr;
+        return CHIP_ERROR_INTERNAL;
+    }
+
+    Semaphore semaphore;
+
+    GMainContext * context = g_main_loop_get_context(mBluezMainLoop);
+    VerifyOrDie(context != nullptr);
+
+    g_main_context_invoke(context, GSourceFunc(PostSemaphore), &semaphore);
+
+    semaphore.Wait();
+
+    return CHIP_NO_ERROR;
+}
+
+bool MainLoop::RunOnBluezThread(GSourceFunc callback, void * argument)
+{
+    GMainContext * context = nullptr;
+    const char * msg       = nullptr;
+
+    VerifyOrExit(mBluezMainLoop != nullptr, msg = "FAIL: NULL sBluezMainLoop");
+    VerifyOrExit(g_main_loop_is_running(mBluezMainLoop), msg = "FAIL: sBluezMainLoop not running");
+
+    context = g_main_loop_get_context(mBluezMainLoop);
+    VerifyOrExit(context != nullptr, msg = "FAIL: NULL main context");
+    g_main_context_invoke(context, callback, argument);
+
+exit:
+    if (msg != nullptr)
+    {
+        ChipLogDetail(DeviceLayer, "%s in %s", msg, __func__);
+    }
+
+    return msg == nullptr;
+}
+
+bool MainLoop::RunOnBluezThreadAndWait(GSourceFunc closure, void * argument)
+{
+    CallbackIndirection indirection(closure, argument);
+
+    if (!Schedule(&CallbackIndirection::Callback, &indirection))
+    {
+        return false;
+    }
+
+    indirection.Wait();
+
+    return true;
+}
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
+
+#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
diff --git a/src/platform/Tizen/bluez/MainLoop.h b/src/platform/Tizen/bluez/MainLoop.h
new file mode 100644 (file)
index 0000000..1128f42
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *    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 <core/CHIPError.h>
+#include <platform/CHIPDeviceLayer.h>
+
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+
+#include <glib.h>
+#include <semaphore.h>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+/// The main loop provides a thread-based implementation that runs
+/// the GLib main loop.
+///
+/// The main loop is used execute callbacks (e.g. dbus notifications).
+class MainLoop
+{
+public:
+    /// Ensure that a thread with g_main_loop_run is executing.
+    CHIP_ERROR EnsureStarted();
+
+    /// Executes a callback on the underlying main loop.
+    ///
+    /// The main loop MUST have been started already.
+    bool RunOnBluezThread(GSourceFunc closure, void * arg);
+
+    /// Executes a callback on the underlying main loop and waits for
+    /// the method to complete.
+    ///
+    /// The main loop MUST have been started already.
+    bool RunOnBluezThreadAndWait(GSourceFunc closure, void * arg);
+
+    /// Convenience method to require less casts to void*
+    template <class T>
+    bool Schedule(int (*callback)(T *), T * value)
+    {
+        return RunOnBluezThread(G_SOURCE_FUNC(callback), value);
+    }
+
+    /// Convenience method to require less casts to void*
+    template <class T>
+    bool ScheduleAndWait(int (*callback)(T *), T * value)
+    {
+        return RunOnBluezThreadAndWait(G_SOURCE_FUNC(callback), value);
+    }
+
+    /// Schedules a method to be executed after the main loop has finished
+    ///
+    /// A single cleanup method can exist and the main loop has to be running
+    /// to set a cleanup method.
+    template <class T>
+    bool SetCleanupFunction(int (*callback)(T *), T * value)
+    {
+        if (mCleanup != nullptr)
+        {
+            return false;
+        }
+
+        if ((mBluezMainLoop == nullptr) || !g_main_loop_is_running(mBluezMainLoop))
+        {
+            return false;
+        }
+
+        mCleanup         = G_SOURCE_FUNC(callback);
+        mCleanupArgument = static_cast<void *>(value);
+
+        return true;
+    }
+
+    static MainLoop & Instance();
+
+private:
+    MainLoop() {}
+
+    static void * Thread(void * self);
+
+    GMainLoop * mBluezMainLoop = nullptr;
+    pthread_t mThread          = 0;
+
+    // allow a single cleanup method
+    GSourceFunc mCleanup    = nullptr;
+    void * mCleanupArgument = nullptr;
+};
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
+
+#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
diff --git a/src/platform/Tizen/bluez/Types.h b/src/platform/Tizen/bluez/Types.h
new file mode 100644 (file)
index 0000000..50cb1f8
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ *
+ *    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.
+ */
+
+/*
+ *  Copyright (c) 2016-2019, The OpenThread Authors.
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of the copyright holder nor the
+ *     names of its contributors may be used to endorse or promote products
+ *     derived from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <platform/CHIPDeviceConfig.h>
+
+#if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
+
+#include <ble/CHIPBleServiceData.h>
+#include <platform/Linux/dbus/bluez/DbusBluez.h>
+
+#include <cstdint>
+#include <string>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+enum ChipAdvType
+{
+    BLUEZ_ADV_TYPE_CONNECTABLE = 0x01,
+    BLUEZ_ADV_TYPE_SCANNABLE   = 0x02,
+    BLUEZ_ADV_TYPE_DIRECTED    = 0x04,
+
+    BLUEZ_ADV_TYPE_UNDIRECTED_NONCONNECTABLE_NONSCANNABLE = 0,
+    BLUEZ_ADV_TYPE_UNDIRECTED_CONNECTABLE_NONSCANNABLE    = BLUEZ_ADV_TYPE_CONNECTABLE,
+    BLUEZ_ADV_TYPE_UNDIRECTED_NONCONNECTABLE_SCANNABLE    = BLUEZ_ADV_TYPE_SCANNABLE,
+    BLUEZ_ADV_TYPE_UNDIRECTED_CONNECTABLE_SCANNABLE       = BLUEZ_ADV_TYPE_CONNECTABLE | BLUEZ_ADV_TYPE_SCANNABLE,
+
+    BLUEZ_ADV_TYPE_DIRECTED_NONCONNECTABLE_NONSCANNABLE = BLUEZ_ADV_TYPE_DIRECTED,
+    BLUEZ_ADV_TYPE_DIRECTED_CONNECTABLE_NONSCANNABLE    = BLUEZ_ADV_TYPE_DIRECTED | BLUEZ_ADV_TYPE_CONNECTABLE,
+    BLUEZ_ADV_TYPE_DIRECTED_NONCONNECTABLE_SCANNABLE    = BLUEZ_ADV_TYPE_DIRECTED | BLUEZ_ADV_TYPE_SCANNABLE,
+    BLUEZ_ADV_TYPE_DIRECTED_CONNECTABLE_SCANNABLE = BLUEZ_ADV_TYPE_DIRECTED | BLUEZ_ADV_TYPE_CONNECTABLE | BLUEZ_ADV_TYPE_SCANNABLE,
+};
+
+#define BLUEZ_ADDRESS_SIZE 6 ///< BLE address size (in bytes)
+#define BLUEZ_PATH "/org/bluez"
+#define BLUEZ_INTERFACE "org.bluez"
+#define ADAPTER_INTERFACE BLUEZ_INTERFACE ".Adapter1"
+#define PROFILE_INTERFACE BLUEZ_INTERFACE ".GattManager1"
+#define ADVERTISING_MANAGER_INTERFACE BLUEZ_INTERFACE ".LEAdvertisingManager1"
+#define SERVICE_INTERFACE BLUEZ_INTERFACE ".GattService1"
+#define CHARACTERISTIC_INTERFACE BLUEZ_INTERFACE ".GattCharacteristic1"
+#define ADVERTISING_INTERFACE BLUEZ_INTERFACE ".LEAdvertisement1"
+#define DEVICE_INTERFACE BLUEZ_INTERFACE ".Device1"
+
+#define CHIP_PLAT_BLE_UUID_C1_STRING "18ee2ef5-263d-4559-959f-4f9c429f9d11"
+#define CHIP_PLAT_BLE_UUID_C2_STRING "18ee2ef5-263d-4559-959f-4f9c429f9d12"
+#define CHIP_PLAT_BLE_UUID_C3_STRING "64630238-8772-45F2-B87D-748A83218F04"
+
+#define CHIP_BLE_BASE_SERVICE_UUID_STRING "-0000-1000-8000-00805f9b34fb"
+#define CHIP_BLE_SERVICE_PREFIX_LENGTH 8
+#define CHIP_BLE_BASE_SERVICE_PREFIX "0000"
+#define CHIP_BLE_UUID_SERVICE_SHORT_STRING "feaf"
+
+#define CHIP_BLE_UUID_SERVICE_STRING                                                                                               \
+    CHIP_BLE_BASE_SERVICE_PREFIX CHIP_BLE_UUID_SERVICE_SHORT_STRING CHIP_BLE_BASE_SERVICE_UUID_STRING
+
+#define BLUEZ_ADV_TYPE_FLAGS 0x01
+#define BLUEZ_ADV_TYPE_SERVICE_DATA 0x16
+
+#define BLUEZ_ADV_FLAGS_LE_LIMITED (1 << 0)
+#define BLUEZ_ADV_FLAGS_LE_DISCOVERABLE (1 << 1)
+#define BLUEZ_ADV_FLAGS_EDR_UNSUPPORTED (1 << 2)
+#define BLUEZ_ADV_FLAGS_LE_EDR_CONTROLLER (1 << 3)
+#define BLUEZ_ADV_FLAGS_LE_EDR_HOST (1 << 4)
+
+enum BluezAddressType
+{
+    BLUEZ_ADDRESS_TYPE_PUBLIC                        = 0, ///< Bluetooth public device address.
+    BLUEZ_ADDRESS_TYPE_RANDOM_STATIC                 = 1, ///< Bluetooth random static address.
+    BLUEZ_ADDRESS_TYPE_RANDOM_PRIVATE_RESOLVABLE     = 2, ///< Bluetooth random private resolvable address.
+    BLUEZ_ADDRESS_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE = 3, ///< Bluetooth random private non-resolvable address.
+};
+
+struct BluezAddress
+{
+    BluezAddressType mType;               ///< Bluetooth device address type.
+    uint8_t mAddress[BLUEZ_ADDRESS_SIZE]; ///< A 48-bit address of Bluetooth device in LSB format.
+};
+
+struct IOChannel
+{
+    GIOChannel * mpChannel;
+    guint mWatch;
+};
+
+struct BluezEndpoint
+{
+    char * mpOwningName; // Bus owning name
+
+    // Adapter properties
+    char * mpAdapterName;
+    char * mpAdapterAddr;
+
+    // Paths for objects published by this service
+    char * mpRootPath;
+    char * mpAdvPath;
+    char * mpServicePath;
+
+    // Objects (interfaces) subscibed to by this service
+    GDBusObjectManager * mpObjMgr = nullptr;
+    BluezAdapter1 * mpAdapter     = nullptr;
+    BluezDevice1 * mpDevice       = nullptr;
+
+    // Objects (interfaces) published by this service
+    GDBusObjectManagerServer * mpRoot;
+    BluezGattService1 * mpService;
+    BluezGattCharacteristic1 * mpC1;
+    BluezGattCharacteristic1 * mpC2;
+    // additional data characteristics
+    BluezGattCharacteristic1 * mpC3;
+
+    // map device path to the connection
+    GHashTable * mpConnMap;
+    uint32_t mAdapterId;
+    bool mIsCentral;
+    char * mpAdvertisingUUID;
+    chip::Ble::ChipBLEDeviceIdentificationInfo mDeviceIdInfo;
+    ChipAdvType mType;  ///< Advertisement type.
+    uint16_t mDuration; ///< Advertisement interval (in ms).
+    bool mIsAdvertising;
+    char * mpPeerDevicePath;
+    GCancellable * mpConnectCancellable = nullptr;
+};
+
+struct BluezConnection
+{
+    char * mpPeerAddress;
+    BluezDevice1 * mpDevice;
+    BluezGattService1 * mpService;
+    BluezGattCharacteristic1 * mpC1;
+    BluezGattCharacteristic1 * mpC2;
+    // additional data characteristics
+    BluezGattCharacteristic1 * mpC3;
+
+    bool mIsNotify;
+    uint16_t mMtu;
+    struct IOChannel mC1Channel;
+    struct IOChannel mC2Channel;
+    BluezEndpoint * mpEndpoint;
+};
+
+struct ConnectionDataBundle
+{
+    BluezConnection * mpConn;
+    GVariant * mpVal;
+};
+
+} // namespace Internal
+} // namespace DeviceLayer
+} // namespace chip
+
+#endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
diff --git a/src/platform/Tizen/dbus/bluez/BUILD.gn b/src/platform/Tizen/dbus/bluez/BUILD.gn
new file mode 100644 (file)
index 0000000..308fecc
--- /dev/null
@@ -0,0 +1,26 @@
+# Copyright (c) 2020 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.
+
+import("//build_overrides/chip.gni")
+
+import("${chip_root}/build/chip/linux/gdbus_library.gni")
+
+gdbus_library("bluez") {
+  sources = [ "DbusBluez.xml" ]
+
+  c_namespace = "Bluez"
+  interface_prefix = "org.bluez"
+  c_generate_object_manager = true
+  dbus_out_dir = "platform/Linux/dbus/bluez"
+}
diff --git a/src/platform/Tizen/dbus/bluez/DbusBluez.xml b/src/platform/Tizen/dbus/bluez/DbusBluez.xml
new file mode 100644 (file)
index 0000000..ac0952b
--- /dev/null
@@ -0,0 +1,255 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+# Copyright (c) 2020 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.
+
+# This file is constructed using the below method.
+# 1. running bluetoothd
+# 2. running two Bluetooth adapter with LE capability and create ble connection with Gatt servie and Gatt Char.
+#    For the purposes of XML generation we use btvirt emulator with the LE only capability.
+# Assume the LE chip is on hci 0
+# we get the bluez XML via:
+# sudo gdbus introspect -s -d org.bluez -r -o /org/bluez -x
+# sudo gdbus introspect -s -d org.bluez -r -o /org/bluez/hci0 -x
+# sudo gdbus introspect -s -d org.bluez -r -o /org/bluez/hci0/dev_00_AA_01_01_00_24 -x
+# sudo gdbus introspect -s -d org.bluez -r -o /org/bluez/hci0/dev_00_AA_01_01_00_24/service0006 -x
+# sudo gdbus introspect -s -d org.bluez -r -o /org/bluez/hci0/dev_00_AA_01_01_00_24/service0006/char0007 -x
+# sudo gdbus introspect -s -d org.bluez -r -o /org/bluez/hci0/dev_00_AA_01_01_00_24/service0006/char0007/desc0009 -x
+# sudo gdbus introspect -s -d org.bluez -r -o / -x
+-->
+
+<node>
+  <interface name="org.bluez.Adapter1">
+    <method name="StartDiscovery" />
+    <method name="SetDiscoveryFilter">
+      <arg name="properties" type="a{sv}" direction="in" />
+    </method>
+    <method name="StopDiscovery" />
+    <method name="RemoveDevice">
+      <arg name="device" type="o" direction="in" />
+    </method>
+    <method name="GetDiscoveryFilters">
+      <arg name="filters" type="as" direction="out" />
+    </method>
+    <method name="ConnectDevice">
+      <arg name="properties" type="a{sv}" direction="in" />
+    </method>
+
+    <property name="Address" type="s" access="read" />
+    <property name="AddressType" type="s" access="read" />
+    <property name="Name" type="s" access="read" />
+    <property name="Alias" type="s" access="readwrite" />
+    <property name="Class" type="u" access="read" />
+    <property name="Powered" type="b" access="readwrite" />
+    <property name="Discoverable" type="b" access="readwrite" />
+    <property name="DiscoverableTimeout" type="u" access="readwrite" />
+    <property name="Pairable" type="b" access="readwrite" />
+    <property name="PairableTimeout" type="u" access="readwrite" />
+    <property name="Discovering" type="b" access="read" />
+    <property name="UUIDs" type="as" access="read" />
+    <property name="Modalias" type="s" access="read" />
+    <property name="Roles" type="as" access="read" />
+  </interface>
+
+  <interface name="org.bluez.Device1">
+    <method name="Disconnect" />
+    <method name="Connect" />
+    <method name="ConnectProfile">
+      <arg name="UUID" type="s" direction="in" />
+    </method>
+    <method name="DisconnectProfile">
+      <arg name="UUID" type="s" direction="in" />
+    </method>
+    <method name="Pair" />
+    <method name="CancelPairing" />
+    <property name="Address" type="s" access="read" />
+    <property name="AddressType" type="s" access="read" />
+    <property name="Name" type="s" access="read" />
+    <property name="Alias" type="s" access="readwrite" />
+    <property name="Class" type="u" access="read" />
+    <property name="Appearance" type="q" access="read" />
+    <property name="Icon" type="s" access="read" />
+    <property name="Paired" type="b" access="read" />
+    <property name="Trusted" type="b" access="readwrite" />
+    <property name="Blocked" type="b" access="readwrite" />
+    <property name="LegacyPairing" type="b" access="read" />
+    <property name="RSSI" type="n" access="read" />
+    <property name="Connected" type="b" access="read" />
+    <property name="UUIDs" type="as" access="read" />
+    <property name="Modalias" type="s" access="read" />
+    <property name="Adapter" type="o" access="read" />
+    <property name="ManufacturerData" type="a{qv}" access="read" />
+    <property name="ServiceData" type="a{sv}" access="read" />
+    <property name="TxPower" type="n" access="read" />
+    <property name="ServicesResolved" type="b" access="read" />
+    <property name="AdvertisingFlags" type="ay" access="read" />
+    <property name="AdvertisingData" type="a{yv}" access="read" />
+    <property name="WakeAllowed" type="b" access="readwrite" />
+  </interface>
+
+  <interface name="org.bluez.GattManager1">
+    <method name="RegisterApplication">
+      <arg name="application" type="o" direction="in" />
+      <arg name="options" type="a{sv}" direction="in" />
+    </method>
+    <method name="UnregisterApplication">
+      <arg name="application" type="o" direction="in" />
+    </method>
+  </interface>
+
+  <interface name="org.bluez.GattService1">
+    <property name="UUID" type="s" access="read" />
+    <property name="Device" type="o" access="read" />
+    <property name="Primary" type="b" access="read" />
+    <!-- <property name="Includes" type="ao" access="read" /> -->
+  </interface>
+
+  <interface name="org.bluez.GattCharacteristic1">
+    <method name="ReadValue">
+      <arg name="options" type="a{sv}" direction="in"/>
+      <arg name="value" type="ay" direction="out">
+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+      </arg>
+    </method>
+    <method name="WriteValue">
+      <arg name="value" type="ay" direction="in">
+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+      </arg>
+      <arg name="options" type="a{sv}" direction="in"/>
+    </method>
+    <method name="AcquireWrite">
+      <arg name="options" type="a{sv}" direction="in" />
+      <arg name="fd" type="h" direction="out" />
+      <arg name="mtu" type="q" direction="out" />
+    </method>
+    <method name="AcquireNotify">
+      <arg name="options" type="a{sv}" direction="in" />
+      <arg name="fd" type="h" direction="out" />
+      <arg name="mtu" type="q" direction="out" />
+    </method>
+    <method name="StartNotify" />
+    <method name="StopNotify" />
+    <method name="Confirm" />
+    <property name="UUID" type="s" access="read" />
+    <property name="Service" type="o" access="read" />
+    <property name="Value" type="ay" access="read">
+      <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+    </property>
+    <property name="Notifying" type="b" access="read" />
+    <property name="Flags" type="as" access="read" />
+    <property name="WriteAcquired" type="b" access="read" />
+    <property name="NotifyAcquired" type="b" access="read" />
+  </interface>
+
+  <interface name="org.bluez.GattDescriptor1">
+    <method name="ReadValue">
+      <arg name="options" type="a{sv}" direction="in"/>
+      <arg name="value" type="ay" direction="out">
+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+      </arg>
+    </method>
+    <method name="WriteValue">
+      <arg name="value" type="ay" direction="in">
+        <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+      </arg>
+      <arg name="options" type="a{sv}" direction="in"/>
+    </method>
+    <property name="UUID" type="s" access="read" />
+    <property name="Characteristic" type="o" access="read" />
+    <property name="Value" type="ay" access="read">
+      <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+    </property>
+  </interface>
+
+  <interface name="org.bluez.LEAdvertisement1">
+    <method name="Release"/>
+    <property name="Type" type="s" access="read"/>
+    <property name="ServiceUUIDs" type="as" access="read">
+      <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
+    </property>
+    <property name="ManufacturerData" type="a{qv}" access="read"/>
+    <property name="SolicitUUIDs" type="as" access="read"/>
+    <property name="ServiceData" type="a{sv}" access="read"/>
+    <property name="Data" type="a{yay}" access="read"/>
+    <property name="Discoverable" type="b" access="read"/>
+    <property name="DiscoverableTimeout" type="q" access="read"/>
+    <property name="Includes" type="as" access="read"/>
+    <property name="LocalName" type="s" access="read"/>
+    <property name="Appearance" type="q" access="read"/>
+    <property name="Duration" type="q" access="read"/>
+    <property name="Timeout" type="q" access="read"/>
+    <!-- <property name="SecondaryChannel" type="s" access="read"/> -->
+  </interface>
+
+  <interface name="org.bluez.LEAdvertisingManager1">
+    <method name="RegisterAdvertisement">
+      <arg name="advertisement" type="o" direction="in" />
+      <arg name="options" type="a{sv}" direction="in" />
+    </method>
+    <method name="UnregisterAdvertisement">
+      <arg name="service" type="o" direction="in" />
+    </method>
+    <property name="ActiveInstances" type="y" access="read" />
+    <property name="SupportedInstances" type="y" access="read" />
+    <property name="SupportedIncludes" type="as" access="read" />
+    <property name="SupportedSecondaryChannels" type="as" access="read" />
+  </interface>
+
+  <interface name="org.freedesktop.DBus.Properties">
+    <method name="Get">
+      <arg name="interface" type="s" direction="in" />
+      <arg name="name" type="s" direction="in" />
+      <arg name="value" type="v" direction="out" />
+    </method>
+    <method name="Set">
+      <arg name="interface" type="s" direction="in" />
+      <arg name="name" type="s" direction="in" />
+      <arg name="value" type="v" direction="in" />
+    </method>
+    <method name="GetAll">
+      <arg name="interface" type="s" direction="in" />
+      <arg name="properties" type="a{sv}" direction="out" />
+    </method>
+    <signal name="PropertiesChanged">
+      <arg name="interface" type="s" />
+      <arg name="changed_properties" type="a{sv}" />
+      <arg name="invalidated_properties" type="as" />
+    </signal>
+  </interface>
+
+  <interface name="org.bluez.ProfileManager1">
+    <method name="RegisterProfile">
+      <arg name="profile" type="o" direction="in" />
+      <arg name="UUID" type="s" direction="in" />
+      <arg name="options" type="a{sv}" direction="in" />
+    </method>
+    <method name="UnregisterProfile">
+      <arg name="profile" type="o" direction="in" />
+    </method>
+  </interface>
+
+  <interface name="org.freedesktop.DBus.ObjectManager">
+    <method name="GetManagedObjects">
+      <arg name="objects" type="a{oa{sa{sv}}}" direction="out" />
+    </method>
+    <signal name="InterfacesAdded">
+      <arg name="object" type="o" />
+      <arg name="interfaces" type="a{sa{sv}}" />
+    </signal>
+    <signal name="InterfacesRemoved">
+      <arg name="object" type="o" />
+      <arg name="interfaces" type="as" />
+    </signal>
+  </interface>
+</node>
diff --git a/src/platform/Tizen/dbus/wpa/BUILD.gn b/src/platform/Tizen/dbus/wpa/BUILD.gn
new file mode 100644 (file)
index 0000000..9fdd7e5
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright (c) 2020 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.
+
+import("//build_overrides/chip.gni")
+
+import("${chip_root}/build/chip/linux/gdbus_library.gni")
+
+gdbus_library("wpa") {
+  sources = [
+    "DBusWpa.xml",
+    "DBusWpaInterface.xml",
+    "DBusWpaNetwork.xml",
+  ]
+
+  c_namespace = "Wpa"
+  c_generate_object_manager = false
+  dbus_out_dir = "platform/Linux/dbus/wpa"
+}
diff --git a/src/platform/Tizen/dbus/wpa/DBusWpa.xml b/src/platform/Tizen/dbus/wpa/DBusWpa.xml
new file mode 100644 (file)
index 0000000..f43d691
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" ?>
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "https://raw.githubusercontent.com/freedesktop/dbus/master/doc/introspect.dtd">
+<node>
+    <interface name="fi.w1.wpa_supplicant1">
+        <method name="CreateInterface">
+            <arg name="args" type="a{sv}" direction="in" />
+            <arg name="path" type="o" direction="out" />
+        </method>
+        <method name="RemoveInterface">
+            <arg name="path" type="o" direction="in" />
+        </method>
+        <method name="GetInterface">
+            <arg name="ifname" type="s" direction="in" />
+            <arg name="path" type="o" direction="out" />
+        </method>
+        <method name="ExpectDisconnect" />
+        <signal name="InterfaceAdded">
+            <arg name="path" type="o" />
+            <arg name="properties" type="a{sv}" />
+        </signal>
+        <signal name="InterfaceRemoved">
+            <arg name="path" type="o" />
+        </signal>
+        <signal name="PropertiesChanged">
+            <arg name="properties" type="a{sv}" />
+        </signal>
+        <property name="DebugLevel" type="s" access="readwrite" />
+        <property name="DebugTimestamp" type="b" access="readwrite" />
+        <property name="DebugShowKeys" type="b" access="readwrite" />
+        <property name="Interfaces" type="ao" access="read" />
+        <property name="EapMethods" type="as" access="read" />
+        <property name="Capabilities" type="as" access="read" />
+        <property name="WFDIEs" type="ay" access="readwrite" />
+    </interface>
+    <node name="Interfaces" />
+</node>
diff --git a/src/platform/Tizen/dbus/wpa/DBusWpaInterface.xml b/src/platform/Tizen/dbus/wpa/DBusWpaInterface.xml
new file mode 100644 (file)
index 0000000..61b4f56
--- /dev/null
@@ -0,0 +1,265 @@
+<?xml version="1.0" ?>
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "https://raw.githubusercontent.com/freedesktop/dbus/master/doc/introspect.dtd">
+<node>
+    <interface name="fi.w1.wpa_supplicant1.Interface">
+        <method name="Scan">
+            <arg name="args" type="a{sv}" direction="in" />
+        </method>
+        <method name="SignalPoll">
+            <arg name="args" type="a{sv}" direction="out" />
+        </method>
+        <method name="Disconnect" />
+        <method name="AddNetwork">
+            <arg name="args" type="a{sv}" direction="in" />
+            <arg name="path" type="o" direction="out" />
+        </method>
+        <method name="Reassociate" />
+        <method name="Reattach" />
+        <method name="Reconnect" />
+        <method name="RemoveNetwork">
+            <arg name="path" type="o" direction="in" />
+        </method>
+        <method name="RemoveAllNetworks" />
+        <method name="SelectNetwork">
+            <arg name="path" type="o" direction="in" />
+        </method>
+        <method name="NetworkReply">
+            <arg name="path" type="o" direction="in" />
+            <arg name="field" type="s" direction="in" />
+            <arg name="value" type="s" direction="in" />
+        </method>
+        <method name="AddBlob">
+            <arg name="name" type="s" direction="in" />
+            <arg name="data" type="ay" direction="in" />
+        </method>
+        <method name="GetBlob">
+            <arg name="name" type="s" direction="in" />
+            <arg name="data" type="ay" direction="out" />
+        </method>
+        <method name="RemoveBlob">
+            <arg name="name" type="s" direction="in" />
+        </method>
+        <method name="SetPKCS11EngineAndModulePath">
+            <arg name="pkcs11_engine_path" type="s" direction="in" />
+            <arg name="pkcs11_module_path" type="s" direction="in" />
+        </method>
+        <method name="FlushBSS">
+            <arg name="age" type="u" direction="in" />
+        </method>
+        <method name="SubscribeProbeReq" />
+        <method name="UnsubscribeProbeReq" />
+        <method name="EAPLogoff" />
+        <method name="EAPLogon" />
+        <method name="AutoScan">
+            <arg name="arg" type="s" direction="in" />
+        </method>
+        <method name="TDLSDiscover">
+            <arg name="peer_address" type="s" direction="in" />
+        </method>
+        <method name="TDLSSetup">
+            <arg name="peer_address" type="s" direction="in" />
+        </method>
+        <method name="TDLSStatus">
+            <arg name="peer_address" type="s" direction="in" />
+            <arg name="status" type="s" direction="out" />
+        </method>
+        <method name="TDLSTeardown">
+            <arg name="peer_address" type="s" direction="in" />
+        </method>
+        <method name="TDLSChannelSwitch">
+            <arg name="args" type="a{sv}" direction="in" />
+        </method>
+        <method name="TDLSCancelChannelSwitch">
+            <arg name="peer_address" type="s" direction="in" />
+        </method>
+        <method name="VendorElemAdd">
+            <arg name="frame_id" type="i" direction="in" />
+            <arg name="ielems" type="ay" direction="in" />
+        </method>
+        <method name="VendorElemGet">
+            <arg name="frame_id" type="i" direction="in" />
+            <arg name="ielems" type="ay" direction="out" />
+        </method>
+        <method name="VendorElemRem">
+            <arg name="frame_id" type="i" direction="in" />
+            <arg name="ielems" type="ay" direction="in" />
+        </method>
+        <method name="SaveConfig" />
+        <method name="AbortScan" />
+        <signal name="ScanDone">
+            <arg name="success" type="b" />
+        </signal>
+        <signal name="BSSAdded">
+            <arg name="path" type="o" />
+            <arg name="properties" type="a{sv}" />
+        </signal>
+        <signal name="BSSRemoved">
+            <arg name="path" type="o" />
+        </signal>
+        <signal name="BlobAdded">
+            <arg name="name" type="s" />
+        </signal>
+        <signal name="BlobRemoved">
+            <arg name="name" type="s" />
+        </signal>
+        <signal name="NetworkAdded">
+            <arg name="path" type="o" />
+            <arg name="properties" type="a{sv}" />
+        </signal>
+        <signal name="NetworkRemoved">
+            <arg name="path" type="o" />
+        </signal>
+        <signal name="NetworkSelected">
+            <arg name="path" type="o" />
+        </signal>
+        <signal name="PropertiesChanged">
+            <arg name="properties" type="a{sv}" />
+        </signal>
+        <signal name="ProbeRequest">
+            <arg name="args" type="a{sv}" />
+        </signal>
+        <signal name="Certification">
+            <arg name="certification" type="a{sv}" />
+        </signal>
+        <signal name="EAP">
+            <arg name="status" type="s" />
+            <arg name="parameter" type="s" />
+        </signal>
+        <signal name="StaAuthorized">
+            <arg name="name" type="s" />
+        </signal>
+        <signal name="StaDeauthorized">
+            <arg name="name" type="s" />
+        </signal>
+        <signal name="StationAdded">
+            <arg name="path" type="o" />
+            <arg name="properties" type="a{sv}" />
+        </signal>
+        <signal name="StationRemoved">
+            <arg name="path" type="o" />
+        </signal>
+        <signal name="NetworkRequest">
+            <arg name="path" type="o" />
+            <arg name="field" type="s" />
+            <arg name="text" type="s" />
+        </signal>
+        <property name="Capabilities" type="a{sv}" access="read" />
+        <property name="State" type="s" access="read" />
+        <property name="Scanning" type="b" access="read" />
+        <property name="ApScan" type="u" access="readwrite" />
+        <property name="BSSExpireAge" type="u" access="readwrite" />
+        <property name="BSSExpireCount" type="u" access="readwrite" />
+        <property name="Country" type="s" access="readwrite" />
+        <property name="Ifname" type="s" access="read" />
+        <property name="Driver" type="s" access="read" />
+        <property name="BridgeIfname" type="s" access="read" />
+        <property name="ConfigFile" type="s" access="read" />
+        <property name="CurrentBSS" type="o" access="read" />
+        <property name="CurrentNetwork" type="o" access="read" />
+        <property name="CurrentAuthMode" type="s" access="read" />
+        <property name="Blobs" type="a{say}" access="read" />
+        <property name="BSSs" type="ao" access="read" />
+        <property name="Networks" type="ao" access="read" />
+        <property name="FastReauth" type="b" access="readwrite" />
+        <property name="ScanInterval" type="i" access="readwrite" />
+        <property name="PKCS11EnginePath" type="s" access="read" />
+        <property name="PKCS11ModulePath" type="s" access="read" />
+        <property name="DisconnectReason" type="i" access="read" />
+        <property name="AuthStatusCode" type="i" access="read" />
+        <property name="AssocStatusCode" type="i" access="read" />
+        <property name="RoamTime" type="u" access="read" />
+        <property name="RoamComplete" type="b" access="read" />
+        <property name="SessionLength" type="u" access="read" />
+        <property name="BSSTMStatus" type="u" access="read" />
+        <property name="Stations" type="ao" access="read" />
+        <property name="MACAddressRandomizationMask" type="a{say}" access="readwrite" />
+        <property name="CtrlInterface" type="s" access="readwrite" />
+        <property name="CtrlInterfaceGroup" type="s" access="readwrite" />
+        <property name="EapolVersion" type="s" access="readwrite" />
+        <property name="Bgscan" type="s" access="readwrite" />
+        <property name="DisableScanOffload" type="s" access="readwrite" />
+        <property name="OpenscEnginePath" type="s" access="readwrite" />
+        <property name="OpensslCiphers" type="s" access="readwrite" />
+        <property name="PcscReader" type="s" access="readwrite" />
+        <property name="PcscPin" type="s" access="readwrite" />
+        <property name="ExternalSim" type="s" access="readwrite" />
+        <property name="DriverParam" type="s" access="readwrite" />
+        <property name="Dot11RSNAConfigPMKLifetime" type="s" access="readwrite" />
+        <property name="Dot11RSNAConfigPMKReauthThreshold" type="s" access="readwrite" />
+        <property name="Dot11RSNAConfigSATimeout" type="s" access="readwrite" />
+        <property name="UpdateConfig" type="s" access="readwrite" />
+        <property name="Uuid" type="s" access="readwrite" />
+        <property name="AutoUuid" type="s" access="readwrite" />
+        <property name="DeviceName" type="s" access="readwrite" />
+        <property name="Manufacturer" type="s" access="readwrite" />
+        <property name="ModelName" type="s" access="readwrite" />
+        <property name="ModelNumber" type="s" access="readwrite" />
+        <property name="SerialNumber" type="s" access="readwrite" />
+        <property name="DeviceType" type="s" access="readwrite" />
+        <property name="OsVersion" type="s" access="readwrite" />
+        <property name="ConfigMethods" type="s" access="readwrite" />
+        <property name="SecDeviceType" type="s" access="readwrite" />
+        <property name="IpAddrGo" type="s" access="readwrite" />
+        <property name="IpAddrMask" type="s" access="readwrite" />
+        <property name="IpAddrStart" type="s" access="readwrite" />
+        <property name="IpAddrEnd" type="s" access="readwrite" />
+        <property name="BssMaxCount" type="s" access="readwrite" />
+        <property name="FilterSsids" type="s" access="readwrite" />
+        <property name="FilterRssi" type="s" access="readwrite" />
+        <property name="MaxNumSta" type="s" access="readwrite" />
+        <property name="ApIsolate" type="s" access="readwrite" />
+        <property name="DisassocLowAck" type="s" access="readwrite" />
+        <property name="Hs20" type="s" access="readwrite" />
+        <property name="Interworking" type="s" access="readwrite" />
+        <property name="Hessid" type="s" access="readwrite" />
+        <property name="AccessNetworkType" type="s" access="readwrite" />
+        <property name="GoInterworking" type="s" access="readwrite" />
+        <property name="GoAccessNetworkType" type="s" access="readwrite" />
+        <property name="GoInternet" type="s" access="readwrite" />
+        <property name="GoVenueGroup" type="s" access="readwrite" />
+        <property name="GoVenueType" type="s" access="readwrite" />
+        <property name="PbcInM1" type="s" access="readwrite" />
+        <property name="Autoscan" type="s" access="readwrite" />
+        <property name="ExtPasswordBackend" type="s" access="readwrite" />
+        <property name="AutoInterworking" type="s" access="readwrite" />
+        <property name="Okc" type="s" access="readwrite" />
+        <property name="Pmf" type="s" access="readwrite" />
+        <property name="SaeGroups" type="s" access="readwrite" />
+        <property name="SaePwe" type="s" access="readwrite" />
+        <property name="SaePmkidInAssoc" type="s" access="readwrite" />
+        <property name="DtimPeriod" type="s" access="readwrite" />
+        <property name="BeaconInt" type="s" access="readwrite" />
+        <property name="ApVendorElements" type="s" access="readwrite" />
+        <property name="IgnoreOldScanRes" type="s" access="readwrite" />
+        <property name="FreqList" type="s" access="readwrite" />
+        <property name="ScanCurFreq" type="s" access="readwrite" />
+        <property name="SchedScanInterval" type="s" access="readwrite" />
+        <property name="SchedScanStartDelay" type="s" access="readwrite" />
+        <property name="TdlsExternalControl" type="s" access="readwrite" />
+        <property name="OsuDir" type="s" access="readwrite" />
+        <property name="WowlanTriggers" type="s" access="readwrite" />
+        <property name="MacAddr" type="s" access="readwrite" />
+        <property name="RandAddrLifetime" type="s" access="readwrite" />
+        <property name="PreassocMacAddr" type="s" access="readwrite" />
+        <property name="KeyMgmtOffload" type="s" access="readwrite" />
+        <property name="PassiveScan" type="s" access="readwrite" />
+        <property name="ReassocSameBssOptim" type="s" access="readwrite" />
+        <property name="FstGroupId" type="s" access="readwrite" />
+        <property name="FstPriority" type="s" access="readwrite" />
+        <property name="FstLlt" type="s" access="readwrite" />
+        <property name="CertInCb" type="s" access="readwrite" />
+        <property name="WpaRscRelaxation" type="s" access="readwrite" />
+        <property name="SchedScanPlans" type="s" access="readwrite" />
+        <property name="GasAddress3" type="s" access="readwrite" />
+        <property name="FtmResponder" type="s" access="readwrite" />
+        <property name="FtmInitiator" type="s" access="readwrite" />
+        <property name="GasRandAddrLifetime" type="s" access="readwrite" />
+        <property name="GasRandMacAddr" type="s" access="readwrite" />
+        <property name="DppConfigProcessing" type="s" access="readwrite" />
+        <property name="DppName" type="s" access="readwrite" />
+        <property name="DppMudUrl" type="s" access="readwrite" />
+        <property name="ColocIntfReporting" type="s" access="readwrite" />
+    </interface>
+    <node name="BSSs" />
+    <node name="Networks" />
+</node>
diff --git a/src/platform/Tizen/dbus/wpa/DBusWpaNetwork.xml b/src/platform/Tizen/dbus/wpa/DBusWpaNetwork.xml
new file mode 100644 (file)
index 0000000..1b0ea70
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" ?>
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "https://raw.githubusercontent.com/freedesktop/dbus/master/doc/introspect.dtd">
+<node>
+    <interface name="fi.w1.wpa_supplicant1.Network">
+        <signal name="PropertiesChanged">
+            <arg name="properties" type="a{sv}" />
+        </signal>
+        <property name="Properties" type="a{sv}" access="readwrite" />
+        <property name="Enabled" type="b" access="readwrite" />
+    </interface>
+</node>
index 775e205..860f0db 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# TIZEN_CHIP_MODIFY
+
 import("//build_overrides/chip.gni")
 import("${chip_root}/src/ble/ble.gni")
 
 declare_args() {
-  # Device platform layer: cc13x2_26x2, darwin, efr32, esp32, external, freertos, linux, nrfconnect, k32w, qpg6100, none.
-  chip_device_platform = "auto"
+  # Device platform layer: cc13x2_26x2, darwin, efr32, esp32, external, freertos, linux, nrfconnect, k32w, qpg6100, tizen, none.
+  chip_device_platform = "tizen"
   chip_platform_target = ""
 }
 
@@ -35,20 +37,20 @@ declare_args() {
   # Enable openthread support.
   chip_enable_openthread =
       chip_device_platform == "linux" || chip_device_platform == "qpg6100" ||
-      chip_device_platform == "cc13x2_26x2" || chip_device_platform == "k32w"
+      chip_device_platform == "cc13x2_26x2" || chip_device_platform == "k32w" || chip_device_platform == "tizen"
 
   # Enable wifi support.
-  chip_enable_wifi = chip_device_platform == "linux"
+  chip_enable_wifi = chip_device_platform == "linux" || chip_device_platform == "tizen"
 
   # Enable ble support.
   chip_enable_ble =
       chip_config_network_layer_ble &&
       (chip_device_platform == "linux" || chip_device_platform == "darwin" ||
-       chip_device_platform == "cc13x2_26x2")
+       chip_device_platform == "cc13x2_26x2" || chip_device_platform == "tizen")
 
   if (chip_device_platform == "linux" || chip_device_platform == "esp32") {
     chip_mdns = "minimal"
-  } else if (chip_device_platform == "darwin") {
+  } else if (chip_device_platform == "darwin" || chip_device_platform == "tizen") {
     chip_mdns = "platform"
   } else {
     chip_mdns = "none"
@@ -66,6 +68,8 @@ if (chip_device_platform == "cc13x2_26x2") {
   _chip_device_layer = "ESP32"
 } else if (chip_device_platform == "linux") {
   _chip_device_layer = "Linux"
+} else if (chip_device_platform == "tizen") {
+  _chip_device_layer = "Tizen"
 } else if (chip_device_platform == "nrfconnect") {
   _chip_device_layer = "nrfconnect"
 } else if (chip_device_platform == "qpg6100") {
@@ -108,7 +112,7 @@ assert(
         chip_device_platform == "cc13x2_26x2" ||
         chip_device_platform == "darwin" || chip_device_platform == "efr32" ||
         chip_device_platform == "esp32" || chip_device_platform == "external" ||
-        chip_device_platform == "linux" ||
+        chip_device_platform == "linux" || chip_device_platform == "tizen" ||
         chip_device_platform == "nrfconnect" ||
         chip_device_platform == "k32w" || chip_device_platform == "qpg6100",
     "Please select a valid value for chip_device_platform")
index eb66767..beded34 100644 (file)
@@ -15,6 +15,8 @@
  *    limitations under the License.
  */
 
+/* TIZEN_CHIP_MODIFY */
+
 #include <assert.h>
 #include <dbus/dbus.h>
 #include <memory>
@@ -27,7 +29,7 @@
 #include "platform/PlatformManager.h"
 #include "platform/ThreadStackManager.h"
 
-#if CHIP_DEVICE_LAYER_TARGET == LINUX
+#if CHIP_DEVICE_LAYER_TARGET == LINUX || CHIP_DEVICE_LAYER_TARGET == TIZEN
 #include <thread>
 
 struct DBusConnectionDeleter