text: /*
   *
   *    Copyright (c) 2020-2022 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/DBusWpaBss.h>
  #include <platform/Linux/dbus/wpa/DBusWpaInterface.h>
  #include <platform/Linux/dbus/wpa/DBusWpaNetwork.h>
  
  #include <mutex>
  #endif
  
  #include <platform/webos/NetworkCommissioningDriver.h>
  #include <platform/NetworkCommissioning.h>
  #include <vector>
  
  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;
      WpaFiW1Wpa_supplicant1BSS * bss;
      gchar * interfacePath;
      gchar * networkPath;
  };
  #endif
  
  /**
   * Concrete implementation of the ConnectivityManager singleton object for webOS 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:
  #if CHIP_DEVICE_CONFIG_ENABLE_WPA
      CHIP_ERROR ProvisionWiFiNetwork(const char * ssid, const char * key);
      CHIP_ERROR ConnectWiFiNetworkAsync(ByteSpan ssid, ByteSpan credentials,
                                         NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * connectCallback);
      void PostNetworkConnect();
      static void _ConnectWiFiNetworkAsyncCallback(GObject * source_object, GAsyncResult * res, gpointer user_data);
      CHIP_ERROR CommitConfig();
  
      void StartWiFiManagement();
      bool IsWiFiManagementStarted();
      CHIP_ERROR GetWiFiBssId(ByteSpan & value);
      CHIP_ERROR GetWiFiSecurityType(uint8_t & securityType);
      CHIP_ERROR GetWiFiVersion(uint8_t & wiFiVersion);
      CHIP_ERROR GetConnectedNetwork(NetworkCommissioning::Network & network);
      CHIP_ERROR StartWiFiScan(ByteSpan ssid, NetworkCommissioning::WiFiDriver::ScanCallback * callback);
  #endif
  
      const char * GetEthernetIfName() { return (mEthIfName[0] == '\0') ? nullptr : mEthIfName; }
  
  #if CHIP_DEVICE_CONFIG_ENABLE_WIFI
      static const char * GetWiFiIfName() { return (sWiFiIfName[0] == '\0') ? nullptr : sWiFiIfName; }
  #endif
  
  private:
      // ===== Members that implement the ConnectivityManager abstract interface.
  
      struct WiFiNetworkScanned
      {
          // The fields matches WiFiInterfaceScanResult::Type.
          uint8_t ssid[Internal::kMaxWiFiSSIDLength];
          uint8_t ssidLen;
          uint8_t bssid[6];
          int8_t rssi;
          uint16_t frequencyBand;
          uint8_t channel;
          uint8_t security;
      };
  
      CHIP_ERROR _Init();
      void _OnPlatformEvent(const ChipDeviceEvent * event);
  
  #if CHIP_DEVICE_CONFIG_ENABLE_WPA
      WiFiStationMode _GetWiFiStationMode();
      CHIP_ERROR _SetWiFiStationMode(ConnectivityManager::WiFiStationMode val);
      System::Clock::Timeout _GetWiFiStationReconnectInterval();
      CHIP_ERROR _SetWiFiStationReconnectInterval(System::Clock::Timeout 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();
      System::Clock::Timeout _GetWiFiAPIdleTimeout();
      void _SetWiFiAPIdleTimeout(System::Clock::Timeout val);
      static CHIP_ERROR StopAutoScan();
  
      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 _OnWpaPropertiesChanged(WpaFiW1Wpa_supplicant1Interface * proxy, GVariant * changed_properties,
                                          const gchar * const * invalidated_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 void _OnWpaBssProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data);
      static void _OnWpaInterfaceScanDone(GObject * source_object, GAsyncResult * res, gpointer user_data);
  
      static bool _GetBssInfo(const gchar * bssPath, NetworkCommissioning::WiFiScanResponse & result);
  
      static bool mAssociattionStarted;
      static BitFlags<ConnectivityFlags> mConnectivityFlag;
      static struct GDBusWpaSupplicant mWpaSupplicant;
      static std::mutex mWpaSupplicantMutex;
  #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);
  #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.
  
      char mEthIfName[IFNAMSIZ];
  
  #if CHIP_DEVICE_CONFIG_ENABLE_WPA
      ConnectivityManager::WiFiStationMode mWiFiStationMode;
      ConnectivityManager::WiFiAPMode mWiFiAPMode;
      WiFiAPState mWiFiAPState;
      System::Clock::Timestamp mLastAPDemandTime;
      System::Clock::Timeout mWiFiStationReconnectInterval;
      System::Clock::Timeout mWiFiAPIdleTimeout;
  #endif
  
  #if CHIP_DEVICE_CONFIG_ENABLE_WIFI
      static char sWiFiIfName[IFNAMSIZ];
  #endif
  
      static NetworkCommissioning::WiFiDriver::ScanCallback * mpScanCallback;
      static NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * mpConnectCallback;
  };
  
  #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 System::Clock::Timeout ConnectivityManagerImpl::_GetWiFiAPIdleTimeout()
  {
      return mWiFiAPIdleTimeout;
  }
  
  #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
  