| /* |
| * |
| * 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. |
| */ |
| |
| #include <Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h> |
| #include <Weave/DeviceLayer/ConnectivityManager.h> |
| #include <Weave/DeviceLayer/internal/NetworkProvisioningServer.h> |
| #include <Weave/DeviceLayer/internal/DeviceNetworkInfo.h> |
| #include <Weave/DeviceLayer/internal/ServiceTunnelAgent.h> |
| #include <Weave/DeviceLayer/internal/BLEManager.h> |
| #include <Weave/Profiles/WeaveProfiles.h> |
| #include <Weave/Profiles/common/CommonProfile.h> |
| #include <Warm/Warm.h> |
| |
| #include <Weave/DeviceLayer/ESP32/ESP32Utils.h> |
| |
| #include "esp_event.h" |
| #include "esp_wifi.h" |
| |
| #include <lwip/ip_addr.h> |
| #include <lwip/netif.h> |
| #include <lwip/nd6.h> |
| #include <lwip/dns.h> |
| |
| #include <new> |
| |
| #if WEAVE_DEVICE_CONFIG_ENABLE_WOBLE |
| #include <Weave/DeviceLayer/internal/GenericConnectivityManagerImpl_BLE.ipp> |
| #endif |
| |
| #if !WEAVE_DEVICE_CONFIG_ENABLE_WIFI_STATION |
| #error "WiFi Station support must be enabled when building for ESP32" |
| #endif |
| |
| #if !WEAVE_DEVICE_CONFIG_ENABLE_WIFI_AP |
| #error "WiFi AP support must be enabled when building for ESP32" |
| #endif |
| |
| #if WEAVE_DEVICE_CONFIG_ENABLE_WIFI_TELEMETRY |
| #include <Weave/Support/TraitEventUtils.h> |
| #include <nest/trait/network/TelemetryNetworkTrait.h> |
| #include <nest/trait/network/TelemetryNetworkWifiTrait.h> |
| #endif |
| |
| using namespace ::nl; |
| using namespace ::nl::Weave; |
| using namespace ::nl::Weave::TLV; |
| using namespace ::nl::Weave::Profiles::Common; |
| using namespace ::nl::Weave::Profiles::NetworkProvisioning; |
| using namespace ::nl::Weave::Profiles::WeaveTunnel; |
| using namespace ::nl::Weave::DeviceLayer::Internal; |
| |
| using Profiles::kWeaveProfile_Common; |
| using Profiles::kWeaveProfile_NetworkProvisioning; |
| |
| namespace nl { |
| namespace Weave { |
| namespace DeviceLayer { |
| |
| ConnectivityManagerImpl ConnectivityManagerImpl::sInstance; |
| |
| ConnectivityManager::WiFiStationMode ConnectivityManagerImpl::_GetWiFiStationMode(void) |
| { |
| if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled) |
| { |
| bool autoConnect; |
| mWiFiStationMode = (esp_wifi_get_auto_connect(&autoConnect) == ESP_OK && autoConnect) |
| ? kWiFiStationMode_Enabled |
| : kWiFiStationMode_Disabled; |
| } |
| return mWiFiStationMode; |
| } |
| |
| bool ConnectivityManagerImpl::_IsWiFiStationEnabled(void) |
| { |
| return GetWiFiStationMode() == kWiFiStationMode_Enabled; |
| } |
| |
| WEAVE_ERROR ConnectivityManagerImpl::_SetWiFiStationMode(WiFiStationMode val) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| VerifyOrExit(val != kWiFiStationMode_NotSupported, err = WEAVE_ERROR_INVALID_ARGUMENT); |
| |
| if (val != kWiFiStationMode_ApplicationControlled) |
| { |
| bool autoConnect = (val == kWiFiStationMode_Enabled); |
| err = esp_wifi_set_auto_connect(autoConnect); |
| SuccessOrExit(err); |
| |
| SystemLayer.ScheduleWork(DriveStationState, NULL); |
| } |
| |
| if (mWiFiStationMode != val) |
| { |
| WeaveLogProgress(DeviceLayer, "WiFi station mode change: %s -> %s", WiFiStationModeToStr(mWiFiStationMode), WiFiStationModeToStr(val)); |
| } |
| |
| mWiFiStationMode = val; |
| |
| exit: |
| return err; |
| } |
| |
| bool ConnectivityManagerImpl::_IsWiFiStationProvisioned(void) |
| { |
| return ESP32Utils::IsStationProvisioned(); |
| } |
| |
| void ConnectivityManagerImpl::_ClearWiFiStationProvision(void) |
| { |
| if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled) |
| { |
| wifi_config_t stationConfig; |
| |
| memset(&stationConfig, 0, sizeof(stationConfig)); |
| esp_wifi_set_config(ESP_IF_WIFI_STA, &stationConfig); |
| |
| SystemLayer.ScheduleWork(DriveStationState, NULL); |
| SystemLayer.ScheduleWork(DriveAPState, NULL); |
| } |
| } |
| |
| WEAVE_ERROR ConnectivityManagerImpl::_SetWiFiAPMode(WiFiAPMode val) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| VerifyOrExit(val != kWiFiAPMode_NotSupported, err = WEAVE_ERROR_INVALID_ARGUMENT); |
| |
| if (mWiFiAPMode != val) |
| { |
| WeaveLogProgress(DeviceLayer, "WiFi AP mode change: %s -> %s", WiFiAPModeToStr(mWiFiAPMode), WiFiAPModeToStr(val)); |
| } |
| |
| mWiFiAPMode = val; |
| |
| SystemLayer.ScheduleWork(DriveAPState, NULL); |
| |
| exit: |
| return err; |
| } |
| |
| void ConnectivityManagerImpl::_DemandStartWiFiAP(void) |
| { |
| if (mWiFiAPMode == kWiFiAPMode_OnDemand || |
| mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision) |
| { |
| mLastAPDemandTime = System::Layer::GetClock_MonotonicMS(); |
| SystemLayer.ScheduleWork(DriveAPState, NULL); |
| } |
| } |
| |
| void ConnectivityManagerImpl::_StopOnDemandWiFiAP(void) |
| { |
| if (mWiFiAPMode == kWiFiAPMode_OnDemand || |
| mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision) |
| { |
| mLastAPDemandTime = 0; |
| SystemLayer.ScheduleWork(DriveAPState, NULL); |
| } |
| } |
| |
| void ConnectivityManagerImpl::_MaintainOnDemandWiFiAP(void) |
| { |
| if (mWiFiAPMode == kWiFiAPMode_OnDemand || |
| mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision) |
| { |
| if (mWiFiAPState == kWiFiAPState_Activating || mWiFiAPState == kWiFiAPState_Active) |
| { |
| mLastAPDemandTime = System::Layer::GetClock_MonotonicMS(); |
| } |
| } |
| } |
| |
| void ConnectivityManagerImpl::_SetWiFiAPIdleTimeoutMS(uint32_t val) |
| { |
| mWiFiAPIdleTimeoutMS = val; |
| SystemLayer.ScheduleWork(DriveAPState, NULL); |
| } |
| |
| #define WIFI_BAND_2_4GHZ 2400 |
| #define WIFI_BAND_5_0GHZ 5000 |
| |
| static uint16_t Map2400MHz(const uint8_t inChannel) |
| { |
| uint16_t frequency = 0; |
| |
| if (inChannel >= 1 && inChannel <= 13) { |
| frequency = 2412 + ((inChannel - 1) * 5); |
| |
| } else if (inChannel == 14) { |
| frequency = 2484; |
| |
| } |
| |
| return frequency; |
| } |
| |
| static 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 == WIFI_BAND_2_4GHZ) { |
| frequency = Map2400MHz(inChannel); |
| |
| } else if (inBand == WIFI_BAND_5_0GHZ) { |
| frequency = Map5000MHz(inChannel); |
| |
| } |
| |
| return frequency; |
| } |
| |
| WEAVE_ERROR ConnectivityManagerImpl::_GetAndLogWifiStatsCounters(void) |
| { |
| WEAVE_ERROR err; |
| nl::Weave::Profiles::DataManagement_Current::event_id_t eventId; |
| Schema::Nest::Trait::Network::TelemetryNetworkWifiTrait::NetworkWiFiStatsEvent statsEvent; |
| wifi_config_t wifiConfig; |
| uint8_t primaryChannel; |
| wifi_second_chan_t secondChannel; |
| |
| VerifyOrExit(_IsWiFiStationConnected() && _IsWiFiStationConnected(), err = WEAVE_NO_ERROR); |
| |
| err = esp_wifi_get_config(ESP_IF_WIFI_STA, &wifiConfig); |
| if (err != ESP_OK) |
| { |
| WeaveLogError(DeviceLayer, "esp_wifi_get_config() failed: %s", nl::ErrorStr(err)); |
| } |
| SuccessOrExit(err); |
| |
| err = esp_wifi_get_channel(&primaryChannel, &secondChannel); |
| if (err != ESP_OK) |
| { |
| WeaveLogError(DeviceLayer, "esp_wifi_get_channel() failed: %s", nl::ErrorStr(err)); |
| } |
| SuccessOrExit(err); |
| |
| statsEvent.bssid = (wifiConfig.sta.bssid[4] << 8) | wifiConfig.sta.bssid[5]; |
| statsEvent.freq = MapFrequency(WIFI_BAND_2_4GHZ, primaryChannel); |
| statsEvent.rssi = 0; |
| statsEvent.bcnRecvd = 0; |
| statsEvent.bcnLost = 0; |
| statsEvent.pktMcastRx = 0; |
| statsEvent.pktUcastRx = 0; |
| statsEvent.currTxRate = 0; |
| statsEvent.currRxRate = 0; |
| statsEvent.sleepTimePercent = 0; |
| statsEvent.numOfAp = 0; |
| |
| WeaveLogProgress(DeviceLayer, |
| "WiFi-Telemtry\n" |
| "BSSID: %x\n" |
| "freq: %d\n" |
| "rssi: %d\n" |
| "bcn recvd: %d\n" |
| "bcn lost: %d\n" |
| "mcast: %d\n" |
| "ucast: %d\n" |
| "rx rate: %d\n" |
| "tx rate: %d\n" |
| "sleep percent: %d\n" |
| "Num of AP: %d\n", |
| statsEvent.bssid, statsEvent.freq, statsEvent.rssi, statsEvent.bcnRecvd, statsEvent.bcnLost, |
| statsEvent.pktMcastRx, statsEvent.pktUcastRx, statsEvent.currRxRate, statsEvent.currTxRate, |
| statsEvent.sleepTimePercent, statsEvent.numOfAp); |
| |
| eventId = nl::LogEvent(&statsEvent); |
| WeaveLogProgress(DeviceLayer, "WiFi Telemetry Stats Event Id: %u\n", eventId); |
| |
| exit: |
| return err; |
| } |
| |
| WEAVE_ERROR ConnectivityManagerImpl::_SetServiceTunnelMode(ServiceTunnelMode val) |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| |
| VerifyOrExit(val != kServiceTunnelMode_NotSupported, err = WEAVE_ERROR_INVALID_ARGUMENT); |
| |
| mServiceTunnelMode = val; |
| |
| SystemLayer.ScheduleWork(DriveServiceTunnelState, NULL); |
| |
| exit: |
| return err; |
| } |
| |
| bool ConnectivityManagerImpl::_IsServiceTunnelConnected(void) |
| { |
| WeaveTunnelAgent::AgentState tunnelState = ServiceTunnelAgent.GetWeaveTunnelAgentState(); |
| return (tunnelState == WeaveTunnelAgent::kState_PrimaryTunModeEstablished || |
| tunnelState == WeaveTunnelAgent::kState_PrimaryAndBkupTunModeEstablished || |
| tunnelState == WeaveTunnelAgent::kState_BkupOnlyTunModeEstablished); |
| } |
| |
| bool ConnectivityManagerImpl::_IsServiceTunnelRestricted(void) |
| { |
| return ServiceTunnelAgent.IsTunnelRoutingRestricted(); |
| } |
| |
| bool ConnectivityManagerImpl::_HaveServiceConnectivityViaTunnel(void) |
| { |
| return IsServiceTunnelConnected() && !IsServiceTunnelRestricted(); |
| } |
| |
| |
| // ==================== ConnectivityManager Platform Internal Methods ==================== |
| |
| WEAVE_ERROR ConnectivityManagerImpl::_Init() |
| { |
| WEAVE_ERROR err; |
| |
| mLastStationConnectFailTime = 0; |
| mLastAPDemandTime = 0; |
| mWiFiStationMode = kWiFiStationMode_Disabled; |
| mWiFiStationState = kWiFiStationState_NotConnected; |
| mWiFiAPMode = kWiFiAPMode_Disabled; |
| mWiFiAPState = kWiFiAPState_NotActive; |
| mServiceTunnelMode = kServiceTunnelMode_Enabled; |
| mWiFiStationReconnectIntervalMS = WEAVE_DEVICE_CONFIG_WIFI_STATION_RECONNECT_INTERVAL; |
| mWiFiAPIdleTimeoutMS = WEAVE_DEVICE_CONFIG_WIFI_AP_IDLE_TIMEOUT; |
| mFlags = 0; |
| |
| // Initialize the Weave Addressing and Routing Module. |
| err = Warm::Init(FabricState); |
| SuccessOrExit(err); |
| |
| // Initialize the service tunnel agent. |
| err = InitServiceTunnelAgent(); |
| SuccessOrExit(err); |
| ServiceTunnelAgent.OnServiceTunStatusNotify = HandleServiceTunnelNotification; |
| |
| // Ensure that ESP station mode is enabled. |
| err = ESP32Utils::EnableStationMode(); |
| SuccessOrExit(err); |
| |
| // If there is no persistent station provision... |
| if (!IsWiFiStationProvisioned()) |
| { |
| // If the code has been compiled with a default WiFi station provision, configure that now. |
| if (CONFIG_DEFAULT_WIFI_SSID[0] != 0) |
| { |
| WeaveLogProgress(DeviceLayer, "Setting default WiFi station configuration (SSID: %s)", CONFIG_DEFAULT_WIFI_SSID); |
| |
| // Set a default station configuration. |
| wifi_config_t wifiConfig; |
| memset(&wifiConfig, 0, sizeof(wifiConfig)); |
| memcpy(wifiConfig.sta.ssid, CONFIG_DEFAULT_WIFI_SSID, strlen(CONFIG_DEFAULT_WIFI_SSID) + 1); |
| memcpy(wifiConfig.sta.password, CONFIG_DEFAULT_WIFI_PASSWORD, strlen(CONFIG_DEFAULT_WIFI_PASSWORD) + 1); |
| wifiConfig.sta.scan_method = WIFI_ALL_CHANNEL_SCAN; |
| wifiConfig.sta.sort_method = WIFI_CONNECT_AP_BY_SIGNAL; |
| err = esp_wifi_set_config(ESP_IF_WIFI_STA, &wifiConfig); |
| if (err != ESP_OK) |
| { |
| WeaveLogError(DeviceLayer, "esp_wifi_set_config() failed: %s", nl::ErrorStr(err)); |
| } |
| err = WEAVE_NO_ERROR; |
| |
| // Enable WiFi station mode. |
| err = SetWiFiStationMode(kWiFiStationMode_Enabled); |
| SuccessOrExit(err); |
| } |
| |
| // Otherwise, ensure WiFi station mode is disabled. |
| else |
| { |
| err = SetWiFiStationMode(kWiFiStationMode_Disabled); |
| SuccessOrExit(err); |
| } |
| } |
| |
| // Force AP mode off for now. |
| err = ESP32Utils::SetAPMode(false); |
| SuccessOrExit(err); |
| |
| // Queue work items to bootstrap the AP and station state machines once the Weave event loop is running. |
| err = SystemLayer.ScheduleWork(DriveStationState, NULL); |
| SuccessOrExit(err); |
| err = SystemLayer.ScheduleWork(DriveAPState, NULL); |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| void ConnectivityManagerImpl::_OnPlatformEvent(const WeaveDeviceEvent * event) |
| { |
| // Handle ESP system events... |
| if (event->Type == DeviceEventType::kESPSystemEvent) |
| { |
| switch(event->Platform.ESPSystemEvent.event_id) { |
| case SYSTEM_EVENT_STA_START: |
| WeaveLogProgress(DeviceLayer, "SYSTEM_EVENT_STA_START"); |
| DriveStationState(); |
| break; |
| case SYSTEM_EVENT_STA_CONNECTED: |
| WeaveLogProgress(DeviceLayer, "SYSTEM_EVENT_STA_CONNECTED"); |
| if (mWiFiStationState == kWiFiStationState_Connecting) |
| { |
| ChangeWiFiStationState(kWiFiStationState_Connecting_Succeeded); |
| } |
| DriveStationState(); |
| break; |
| case SYSTEM_EVENT_STA_DISCONNECTED: |
| WeaveLogProgress(DeviceLayer, "SYSTEM_EVENT_STA_DISCONNECTED"); |
| if (mWiFiStationState == kWiFiStationState_Connecting) |
| { |
| ChangeWiFiStationState(kWiFiStationState_Connecting_Failed); |
| } |
| DriveStationState(); |
| break; |
| case SYSTEM_EVENT_STA_STOP: |
| WeaveLogProgress(DeviceLayer, "SYSTEM_EVENT_STA_STOP"); |
| DriveStationState(); |
| break; |
| case SYSTEM_EVENT_STA_GOT_IP: |
| WeaveLogProgress(DeviceLayer, "SYSTEM_EVENT_STA_GOT_IP"); |
| OnStationIPv4AddressAvailable(event->Platform.ESPSystemEvent.event_info.got_ip); |
| break; |
| case SYSTEM_EVENT_STA_LOST_IP: |
| WeaveLogProgress(DeviceLayer, "SYSTEM_EVENT_STA_LOST_IP"); |
| OnStationIPv4AddressLost(); |
| break; |
| case SYSTEM_EVENT_GOT_IP6: |
| WeaveLogProgress(DeviceLayer, "SYSTEM_EVENT_GOT_IP6"); |
| OnIPv6AddressAvailable(event->Platform.ESPSystemEvent.event_info.got_ip6); |
| break; |
| case SYSTEM_EVENT_AP_START: |
| WeaveLogProgress(DeviceLayer, "SYSTEM_EVENT_AP_START"); |
| ChangeWiFiAPState(kWiFiAPState_Active); |
| DriveAPState(); |
| break; |
| case SYSTEM_EVENT_AP_STOP: |
| WeaveLogProgress(DeviceLayer, "SYSTEM_EVENT_AP_STOP"); |
| ChangeWiFiAPState(kWiFiAPState_NotActive); |
| DriveAPState(); |
| break; |
| case SYSTEM_EVENT_AP_STACONNECTED: |
| WeaveLogProgress(DeviceLayer, "SYSTEM_EVENT_AP_STACONNECTED"); |
| MaintainOnDemandWiFiAP(); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| // Handle fabric membership changes. |
| else if (event->Type == DeviceEventType::kFabricMembershipChange) |
| { |
| DriveServiceTunnelState(); |
| } |
| |
| // Handle service provisioning changes. |
| else if (event->Type == DeviceEventType::kServiceProvisioningChange) |
| { |
| DriveServiceTunnelState(); |
| } |
| |
| #if !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING || WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS |
| |
| // Handle account pairing and device credentials changes. |
| else if (((event->Type == DeviceEventType::kAccountPairingChange) && event->AccountPairingChange.IsPairedToAccount) || |
| ((event->Type == DeviceEventType::kDeviceCredentialsChange) && event->DeviceCredentialsChange.AreCredentialsProvisioned)) |
| { |
| // When account pairing successfully completes or new device credentials |
| // provisioned, if the tunnel to the service is subject to routing restrictions |
| // (imposed because at the time the tunnel was established the device was |
| // not paired to an account or the device only had initial self-signed certificate) |
| // then force the tunnel to close. This will result in the tunnel being |
| // re-established, which should lift the service-side restrictions. |
| if (GetFlag(mFlags, kFlag_ServiceTunnelStarted) && |
| ServiceTunnelAgent.IsTunnelRoutingRestricted()) |
| { |
| WeaveLogProgress(DeviceLayer, "Restarting service tunnel to lift routing restrictions"); |
| ClearFlag(mFlags, kFlag_ServiceTunnelStarted); |
| ServiceTunnelAgent.StopServiceTunnel(WEAVE_ERROR_TUNNEL_FORCE_ABORT); |
| DriveServiceTunnelState(); |
| } |
| } |
| |
| #endif // !WEAVE_DEVICE_CONFIG_DISABLE_ACCOUNT_PAIRING || WEAVE_DEVICE_CONFIG_ENABLE_OPERATIONAL_DEVICE_CREDENTIALS |
| } |
| |
| void ConnectivityManagerImpl::_OnWiFiScanDone() |
| { |
| // Schedule a call to DriveStationState method in case a station connect attempt was |
| // deferred because the scan was in progress. |
| SystemLayer.ScheduleWork(DriveStationState, NULL); |
| } |
| |
| void ConnectivityManagerImpl::_OnWiFiStationProvisionChange() |
| { |
| // Schedule a call to the DriveStationState method to adjust the station state as needed. |
| SystemLayer.ScheduleWork(DriveStationState, NULL); |
| } |
| |
| // ==================== ConnectivityManager Private Methods ==================== |
| |
| void ConnectivityManagerImpl::DriveStationState() |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| bool stationConnected; |
| |
| // Refresh the current station mode. Specifically, this reads the ESP auto_connect flag, |
| // which determine whether the WiFi station mode is kWiFiStationMode_Enabled or |
| // kWiFiStationMode_Disabled. |
| GetWiFiStationMode(); |
| |
| // If the station interface is NOT under application control... |
| if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled) |
| { |
| // Ensure that the ESP WiFi layer is started. |
| err = ESP32Utils::StartWiFiLayer(); |
| SuccessOrExit(err); |
| |
| // Ensure that station mode is enabled in the ESP WiFi layer. |
| err = ESP32Utils::EnableStationMode(); |
| SuccessOrExit(err); |
| } |
| |
| // Determine if the ESP WiFi layer thinks the station interface is currently connected. |
| err = ESP32Utils::IsStationConnected(stationConnected); |
| SuccessOrExit(err); |
| |
| // If the station interface is currently connected ... |
| if (stationConnected) |
| { |
| // Advance the station state to Connected if it was previously NotConnected or |
| // a previously initiated connect attempt succeeded. |
| if (mWiFiStationState == kWiFiStationState_NotConnected || |
| mWiFiStationState == kWiFiStationState_Connecting_Succeeded) |
| { |
| ChangeWiFiStationState(kWiFiStationState_Connected); |
| WeaveLogProgress(DeviceLayer, "WiFi station interface connected"); |
| mLastStationConnectFailTime = 0; |
| OnStationConnected(); |
| } |
| |
| // If the WiFi station interface is no longer enabled, or no longer provisioned, |
| // disconnect the station from the AP, unless the WiFi station mode is currently |
| // under application control. |
| if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled && |
| (mWiFiStationMode != kWiFiStationMode_Enabled || !IsWiFiStationProvisioned())) |
| { |
| WeaveLogProgress(DeviceLayer, "Disconnecting WiFi station interface"); |
| err = esp_wifi_disconnect(); |
| if (err != ESP_OK) |
| { |
| WeaveLogError(DeviceLayer, "esp_wifi_disconnect() failed: %s", nl::ErrorStr(err)); |
| } |
| SuccessOrExit(err); |
| |
| ChangeWiFiStationState(kWiFiStationState_Disconnecting); |
| } |
| } |
| |
| // Otherwise the station interface is NOT connected to an AP, so... |
| else |
| { |
| uint64_t now = System::Layer::GetClock_MonotonicMS(); |
| |
| // Advance the station state to NotConnected if it was previously Connected or Disconnecting, |
| // or if a previous initiated connect attempt failed. |
| if (mWiFiStationState == kWiFiStationState_Connected || |
| mWiFiStationState == kWiFiStationState_Disconnecting || |
| mWiFiStationState == kWiFiStationState_Connecting_Failed) |
| { |
| WiFiStationState prevState = mWiFiStationState; |
| ChangeWiFiStationState(kWiFiStationState_NotConnected); |
| if (prevState != kWiFiStationState_Connecting_Failed) |
| { |
| WeaveLogProgress(DeviceLayer, "WiFi station interface disconnected"); |
| mLastStationConnectFailTime = 0; |
| OnStationDisconnected(); |
| } |
| else |
| { |
| mLastStationConnectFailTime = now; |
| } |
| } |
| |
| // If the WiFi station interface is now enabled and provisioned (and by implication, |
| // not presently under application control), AND the system is not in the process of |
| // scanning, then... |
| if (mWiFiStationMode == kWiFiStationMode_Enabled && IsWiFiStationProvisioned() && !NetworkProvisioningSvr().ScanInProgress()) |
| { |
| // Initiate a connection to the AP if we haven't done so before, or if enough |
| // time has passed since the last attempt. |
| if (mLastStationConnectFailTime == 0 || now >= mLastStationConnectFailTime + mWiFiStationReconnectIntervalMS) |
| { |
| WeaveLogProgress(DeviceLayer, "Attempting to connect WiFi station interface"); |
| err = esp_wifi_connect(); |
| if (err != ESP_OK) |
| { |
| WeaveLogError(DeviceLayer, "esp_wifi_connect() failed: %s", nl::ErrorStr(err)); |
| } |
| SuccessOrExit(err); |
| |
| ChangeWiFiStationState(kWiFiStationState_Connecting); |
| } |
| |
| // Otherwise arrange another connection attempt at a suitable point in the future. |
| else |
| { |
| uint32_t timeToNextConnect = (uint32_t)((mLastStationConnectFailTime + mWiFiStationReconnectIntervalMS) - now); |
| |
| WeaveLogProgress(DeviceLayer, "Next WiFi station reconnect in %" PRIu32 " ms", timeToNextConnect); |
| |
| err = SystemLayer.StartTimer(timeToNextConnect, DriveStationState, NULL); |
| SuccessOrExit(err); |
| } |
| } |
| } |
| |
| exit: |
| |
| // Kick-off any pending network scan that might have been deferred due to the activity |
| // of the WiFi station. |
| NetworkProvisioningSvr().StartPendingScan(); |
| } |
| |
| void ConnectivityManagerImpl::OnStationConnected() |
| { |
| WEAVE_ERROR err; |
| |
| // Assign an IPv6 link local address to the station interface. |
| err = tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA); |
| if (err != ESP_OK) |
| { |
| WeaveLogError(DeviceLayer, "tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA) failed: %s", nl::ErrorStr(err)); |
| } |
| |
| // Invoke WARM to perform actions that occur when the WiFi station interface comes up. |
| Warm::WiFiInterfaceStateChange(Warm::kInterfaceStateUp); |
| |
| // Alert other components of the new state. |
| WeaveDeviceEvent event; |
| event.Type = DeviceEventType::kWiFiConnectivityChange; |
| event.WiFiConnectivityChange.Result = kConnectivity_Established; |
| PlatformMgr().PostEvent(&event); |
| |
| UpdateInternetConnectivityState(); |
| } |
| |
| void ConnectivityManagerImpl::OnStationDisconnected() |
| { |
| // Invoke WARM to perform actions that occur when the WiFi station interface goes down. |
| Warm::WiFiInterfaceStateChange(Warm::kInterfaceStateDown); |
| |
| // Alert other components of the new state. |
| WeaveDeviceEvent event; |
| event.Type = DeviceEventType::kWiFiConnectivityChange; |
| event.WiFiConnectivityChange.Result = kConnectivity_Lost; |
| PlatformMgr().PostEvent(&event); |
| |
| UpdateInternetConnectivityState(); |
| } |
| |
| void ConnectivityManagerImpl::ChangeWiFiStationState(WiFiStationState newState) |
| { |
| if (mWiFiStationState != newState) |
| { |
| WeaveLogProgress(DeviceLayer, "WiFi station state change: %s -> %s", WiFiStationStateToStr(mWiFiStationState), WiFiStationStateToStr(newState)); |
| mWiFiStationState = newState; |
| } |
| } |
| |
| void ConnectivityManagerImpl::DriveStationState(nl::Weave::System::Layer * aLayer, void * aAppState, nl::Weave::System::Error aError) |
| { |
| sInstance.DriveStationState(); |
| } |
| |
| void ConnectivityManagerImpl::DriveAPState() |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| WiFiAPState targetState; |
| uint64_t now; |
| uint32_t apTimeout; |
| bool espAPModeEnabled; |
| |
| // Determine if AP mode is currently enabled in the ESP WiFi layer. |
| err = ESP32Utils::IsAPEnabled(espAPModeEnabled); |
| SuccessOrExit(err); |
| |
| // Adjust the Connectivity Manager's AP state to match the state in the WiFi layer. |
| if (espAPModeEnabled && (mWiFiAPState == kWiFiAPState_NotActive || mWiFiAPState == kWiFiAPState_Deactivating)) |
| { |
| ChangeWiFiAPState(kWiFiAPState_Activating); |
| } |
| if (!espAPModeEnabled && (mWiFiAPState == kWiFiAPState_Active || mWiFiAPState == kWiFiAPState_Activating)) |
| { |
| ChangeWiFiAPState(kWiFiAPState_Deactivating); |
| } |
| |
| // If the AP interface is not under application control... |
| if (mWiFiAPMode != kWiFiAPMode_ApplicationControlled) |
| { |
| // Ensure the ESP WiFi layer is started. |
| err = ESP32Utils::StartWiFiLayer(); |
| SuccessOrExit(err); |
| |
| // 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); |
| WeaveLogProgress(DeviceLayer, "Next WiFi AP timeout in %" PRIu32 " ms", apTimeout); |
| } |
| 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 the target state is 'Active' and the current state is NOT 'Activating', enable |
| // and configure the AP interface, and then enter the 'Activating' state. Eventually |
| // a SYSTEM_EVENT_AP_START event will be received from the ESP WiFi layer which will |
| // cause the state to transition to 'Active'. |
| if (targetState == kWiFiAPState_Active) |
| { |
| if (mWiFiAPState != kWiFiAPState_Activating) |
| { |
| err = ESP32Utils::SetAPMode(true); |
| SuccessOrExit(err); |
| |
| err = ConfigureWiFiAP(); |
| SuccessOrExit(err); |
| |
| ChangeWiFiAPState(kWiFiAPState_Activating); |
| } |
| } |
| |
| // Otherwise, if the target state is 'NotActive' and the current state is not 'Deactivating', |
| // disable the AP interface and enter the 'Deactivating' state. Later a SYSTEM_EVENT_AP_STOP |
| // event will move the AP state to 'NotActive'. |
| else |
| { |
| if (mWiFiAPState != kWiFiAPState_Deactivating) |
| { |
| err = ESP32Utils::SetAPMode(false); |
| SuccessOrExit(err); |
| |
| ChangeWiFiAPState(kWiFiAPState_Deactivating); |
| } |
| } |
| } |
| } |
| |
| // If AP is active, but the interface doesn't have an IPv6 link-local |
| // address, assign one now. |
| if (mWiFiAPState == kWiFiAPState_Active && |
| ESP32Utils::IsInterfaceUp(TCPIP_ADAPTER_IF_AP) && |
| !ESP32Utils::HasIPv6LinkLocalAddress(TCPIP_ADAPTER_IF_AP)) |
| { |
| err = tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_AP); |
| if (err != ESP_OK) |
| { |
| WeaveLogError(DeviceLayer, "tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_AP) failed: %s", nl::ErrorStr(err)); |
| } |
| SuccessOrExit(err); |
| } |
| |
| exit: |
| if (err != WEAVE_NO_ERROR && mWiFiAPMode != kWiFiAPMode_ApplicationControlled) |
| { |
| SetWiFiAPMode(kWiFiAPMode_Disabled); |
| ESP32Utils::SetAPMode(false); |
| } |
| } |
| |
| WEAVE_ERROR ConnectivityManagerImpl::ConfigureWiFiAP() |
| { |
| WEAVE_ERROR err = WEAVE_NO_ERROR; |
| wifi_config_t wifiConfig; |
| |
| memset(&wifiConfig, 0, sizeof(wifiConfig)); |
| err = ConfigurationMgr().GetWiFiAPSSID((char *)wifiConfig.ap.ssid, sizeof(wifiConfig.ap.ssid)); |
| SuccessOrExit(err); |
| wifiConfig.ap.channel = WEAVE_DEVICE_CONFIG_WIFI_AP_CHANNEL; |
| wifiConfig.ap.authmode = WIFI_AUTH_OPEN; |
| wifiConfig.ap.max_connection = WEAVE_DEVICE_CONFIG_WIFI_AP_MAX_STATIONS; |
| wifiConfig.ap.beacon_interval = WEAVE_DEVICE_CONFIG_WIFI_AP_BEACON_INTERVAL; |
| WeaveLogProgress(DeviceLayer, "Configuring WiFi AP: SSID %s, channel %u", wifiConfig.ap.ssid, wifiConfig.ap.channel); |
| err = esp_wifi_set_config(ESP_IF_WIFI_AP, &wifiConfig); |
| if (err != ESP_OK) |
| { |
| WeaveLogError(DeviceLayer, "esp_wifi_set_config(ESP_IF_WIFI_AP) failed: %s", nl::ErrorStr(err)); |
| } |
| SuccessOrExit(err); |
| |
| exit: |
| return err; |
| } |
| |
| void ConnectivityManagerImpl::ChangeWiFiAPState(WiFiAPState newState) |
| { |
| if (mWiFiAPState != newState) |
| { |
| WeaveLogProgress(DeviceLayer, "WiFi AP state change: %s -> %s", WiFiAPStateToStr(mWiFiAPState), WiFiAPStateToStr(newState)); |
| mWiFiAPState = newState; |
| } |
| } |
| |
| void ConnectivityManagerImpl::DriveAPState(nl::Weave::System::Layer * aLayer, void * aAppState, nl::Weave::System::Error aError) |
| { |
| sInstance.DriveAPState(); |
| } |
| |
| void ConnectivityManagerImpl::UpdateInternetConnectivityState(void) |
| { |
| bool haveIPv4Conn = false; |
| bool haveIPv6Conn = false; |
| bool hadIPv4Conn = GetFlag(mFlags, kFlag_HaveIPv4InternetConnectivity); |
| bool hadIPv6Conn = GetFlag(mFlags, kFlag_HaveIPv6InternetConnectivity); |
| |
| // If the WiFi station is currently in the connected state... |
| if (mWiFiStationState == kWiFiStationState_Connected) |
| { |
| // Get the LwIP netif for the WiFi station interface. |
| struct netif * netif = ESP32Utils::GetStationNetif(); |
| |
| // If the WiFi station interface is up... |
| if (netif != NULL && netif_is_up(netif) && netif_is_link_up(netif)) |
| { |
| // Check if a DNS server is currently configured. If so... |
| ip_addr_t dnsServerAddr = dns_getserver(0); |
| if (!ip_addr_isany_val(dnsServerAddr)) |
| { |
| // If the station interface has been assigned an IPv4 address, and has |
| // an IPv4 gateway, then presume that the device has IPv4 Internet |
| // connectivity. |
| if (!ip4_addr_isany_val(*netif_ip4_addr(netif)) && |
| !ip4_addr_isany_val(*netif_ip4_gw(netif))) |
| { |
| haveIPv4Conn = true; |
| } |
| |
| // Search among the IPv6 addresses assigned to the interface for a Global Unicast |
| // address (2000::/3) that is in the valid state. If such an address is found... |
| for (uint8_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) |
| { |
| if (ip6_addr_isglobal(netif_ip6_addr(netif, i)) && |
| ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) |
| { |
| // Determine if there is a default IPv6 router that is currently reachable |
| // via the station interface. If so, presume for now that the device has |
| // IPv6 connectivity. |
| if (nd6_select_router(IP6_ADDR_ANY6, netif) >= 0) |
| { |
| haveIPv6Conn = true; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| // If the internet connectivity state has changed... |
| if (haveIPv4Conn != hadIPv4Conn || haveIPv6Conn != hadIPv6Conn) |
| { |
| // Update the current state. |
| SetFlag(mFlags, kFlag_HaveIPv4InternetConnectivity, haveIPv4Conn); |
| SetFlag(mFlags, kFlag_HaveIPv6InternetConnectivity, haveIPv6Conn); |
| |
| // Alert other components of the state change. |
| WeaveDeviceEvent event; |
| event.Type = DeviceEventType::kInternetConnectivityChange; |
| event.InternetConnectivityChange.IPv4 = GetConnectivityChange(hadIPv4Conn, haveIPv4Conn); |
| event.InternetConnectivityChange.IPv6 = GetConnectivityChange(hadIPv6Conn, haveIPv6Conn); |
| PlatformMgr().PostEvent(&event); |
| |
| if (haveIPv4Conn != hadIPv4Conn) |
| { |
| WeaveLogProgress(DeviceLayer, "%s Internet connectivity %s", "IPv4", (haveIPv4Conn) ? "ESTABLISHED" : "LOST"); |
| } |
| |
| if (haveIPv6Conn != hadIPv6Conn) |
| { |
| WeaveLogProgress(DeviceLayer, "%s Internet connectivity %s", "IPv6", (haveIPv6Conn) ? "ESTABLISHED" : "LOST"); |
| } |
| |
| DriveServiceTunnelState(); |
| } |
| } |
| |
| void ConnectivityManagerImpl::OnStationIPv4AddressAvailable(const system_event_sta_got_ip_t & got_ip) |
| { |
| #if WEAVE_PROGRESS_LOGGING |
| { |
| char ipAddrStr[INET_ADDRSTRLEN], netMaskStr[INET_ADDRSTRLEN], gatewayStr[INET_ADDRSTRLEN]; |
| IPAddress::FromIPv4(got_ip.ip_info.ip).ToString(ipAddrStr, sizeof(ipAddrStr)); |
| IPAddress::FromIPv4(got_ip.ip_info.netmask).ToString(netMaskStr, sizeof(netMaskStr)); |
| IPAddress::FromIPv4(got_ip.ip_info.gw).ToString(gatewayStr, sizeof(gatewayStr)); |
| WeaveLogProgress(DeviceLayer, "IPv4 address %s on WiFi station interface: %s/%s gateway %s", |
| (got_ip.ip_changed) ? "changed" : "ready", |
| ipAddrStr, netMaskStr, gatewayStr); |
| } |
| #endif // WEAVE_PROGRESS_LOGGING |
| |
| RefreshMessageLayer(); |
| |
| UpdateInternetConnectivityState(); |
| } |
| |
| void ConnectivityManagerImpl::OnStationIPv4AddressLost(void) |
| { |
| WeaveLogProgress(DeviceLayer, "IPv4 address lost on WiFi station interface"); |
| |
| RefreshMessageLayer(); |
| |
| UpdateInternetConnectivityState(); |
| } |
| |
| void ConnectivityManagerImpl::OnIPv6AddressAvailable(const system_event_got_ip6_t & got_ip) |
| { |
| #if WEAVE_PROGRESS_LOGGING |
| { |
| IPAddress ipAddr = IPAddress::FromIPv6(got_ip.ip6_info.ip); |
| char ipAddrStr[INET6_ADDRSTRLEN]; |
| ipAddr.ToString(ipAddrStr, sizeof(ipAddrStr)); |
| WeaveLogProgress(DeviceLayer, "%s ready on %s interface: %s", |
| CharacterizeIPv6Address(ipAddr), |
| ESP32Utils::InterfaceIdToName(got_ip.if_index), |
| ipAddrStr); |
| } |
| #endif // WEAVE_PROGRESS_LOGGING |
| |
| RefreshMessageLayer(); |
| |
| UpdateInternetConnectivityState(); |
| } |
| |
| void ConnectivityManagerImpl::DriveServiceTunnelState(void) |
| { |
| WEAVE_ERROR err; |
| bool startServiceTunnel; |
| |
| // Determine if the tunnel to the service should be started. |
| startServiceTunnel = (mServiceTunnelMode == kServiceTunnelMode_Enabled |
| && GetFlag(mFlags, kFlag_HaveIPv4InternetConnectivity) |
| && ConfigurationMgr().IsMemberOfFabric() |
| #if !WEAVE_DEVICE_CONFIG_ENABLE_FIXED_TUNNEL_SERVER |
| && ConfigurationMgr().IsServiceProvisioned() |
| #endif |
| ); |
| |
| // If the tunnel should be started but isn't, or vice versa, ... |
| if (startServiceTunnel != GetFlag(mFlags, kFlag_ServiceTunnelStarted)) |
| { |
| // Update the tunnel started state. |
| SetFlag(mFlags, kFlag_ServiceTunnelStarted, startServiceTunnel); |
| |
| // Start or stop the tunnel as necessary. |
| if (startServiceTunnel) |
| { |
| WeaveLogProgress(DeviceLayer, "Starting service tunnel"); |
| |
| err = ServiceTunnelAgent.StartServiceTunnel(); |
| if (err != WEAVE_NO_ERROR) |
| { |
| WeaveLogError(DeviceLayer, "StartServiceTunnel() failed: %s", nl::ErrorStr(err)); |
| ClearFlag(mFlags, kFlag_ServiceTunnelStarted); |
| } |
| } |
| |
| else |
| { |
| WeaveLogProgress(DeviceLayer, "Stopping service tunnel"); |
| ServiceTunnelAgent.StopServiceTunnel(); |
| } |
| } |
| } |
| |
| void ConnectivityManagerImpl::DriveServiceTunnelState(nl::Weave::System::Layer * aLayer, void * aAppState, nl::Weave::System::Error aError) |
| { |
| sInstance.DriveServiceTunnelState(); |
| } |
| |
| const char * ConnectivityManagerImpl::_WiFiStationModeToStr(WiFiStationMode mode) |
| { |
| switch (mode) |
| { |
| case kWiFiStationMode_NotSupported: |
| return "NotSupported"; |
| case kWiFiStationMode_ApplicationControlled: |
| return "AppControlled"; |
| case kWiFiStationMode_Enabled: |
| return "Enabled"; |
| case kWiFiStationMode_Disabled: |
| return "Disabled"; |
| default: |
| return "(unknown)"; |
| } |
| } |
| |
| const char * ConnectivityManagerImpl::_WiFiAPModeToStr(WiFiAPMode mode) |
| { |
| switch (mode) |
| { |
| case kWiFiAPMode_NotSupported: |
| return "NotSupported"; |
| case kWiFiAPMode_ApplicationControlled: |
| return "AppControlled"; |
| case kWiFiAPMode_Disabled: |
| return "Disabled"; |
| case kWiFiAPMode_Enabled: |
| return "Enabled"; |
| case kWiFiAPMode_OnDemand: |
| return "OnDemand"; |
| case kWiFiAPMode_OnDemand_NoStationProvision: |
| return "OnDemand_NoStationProvision"; |
| default: |
| return "(unknown)"; |
| } |
| } |
| |
| const char * ConnectivityManagerImpl::_ServiceTunnelModeToStr(ServiceTunnelMode mode) |
| { |
| switch (mode) |
| { |
| case kServiceTunnelMode_NotSupported: |
| return "NotSupported"; |
| case kServiceTunnelMode_Disabled: |
| return "Disabled"; |
| case kServiceTunnelMode_Enabled: |
| return "Enabled"; |
| default: |
| return "(unknown)"; |
| } |
| } |
| |
| const char * ConnectivityManagerImpl::WiFiStationStateToStr(WiFiStationState state) |
| { |
| switch (state) |
| { |
| case kWiFiStationState_NotConnected: |
| return "NotConnected"; |
| case kWiFiStationState_Connecting: |
| return "Connecting"; |
| case kWiFiStationState_Connecting_Succeeded: |
| return "Connecting_Succeeded"; |
| case kWiFiStationState_Connecting_Failed: |
| return "Connecting_Failed"; |
| case kWiFiStationState_Connected: |
| return "Connected"; |
| case kWiFiStationState_Disconnecting: |
| return "Disconnecting"; |
| default: |
| return "(unknown)"; |
| } |
| } |
| |
| const char * ConnectivityManagerImpl::WiFiAPStateToStr(WiFiAPState state) |
| { |
| switch (state) |
| { |
| case kWiFiAPState_NotActive: |
| return "NotActive"; |
| case kWiFiAPState_Activating: |
| return "Activating"; |
| case kWiFiAPState_Active: |
| return "Active"; |
| case kWiFiAPState_Deactivating: |
| return "Deactivating"; |
| default: |
| return "(unknown)"; |
| } |
| } |
| |
| void ConnectivityManagerImpl::RefreshMessageLayer(void) |
| { |
| WEAVE_ERROR err = MessageLayer.RefreshEndpoints(); |
| if (err != WEAVE_NO_ERROR) |
| { |
| WeaveLogError(DeviceLayer, "MessageLayer.RefreshEndpoints() failed: %s", nl::ErrorStr(err)); |
| } |
| } |
| |
| void ConnectivityManagerImpl::HandleServiceTunnelNotification(WeaveTunnelConnectionMgr::TunnelConnNotifyReasons reason, |
| WEAVE_ERROR err, void *appCtxt) |
| { |
| bool newTunnelState = false; |
| bool prevTunnelState = GetFlag(sInstance.mFlags, kFlag_ServiceTunnelUp); |
| bool isRestricted = false; |
| |
| switch (reason) |
| { |
| case WeaveTunnelConnectionMgr::kStatus_TunDown: |
| WeaveLogProgress(DeviceLayer, "ConnectivityManager: Service tunnel down"); |
| break; |
| case WeaveTunnelConnectionMgr::kStatus_TunPrimaryConnError: |
| WeaveLogProgress(DeviceLayer, "ConnectivityManager: Service tunnel connection error: %s", ::nl::ErrorStr(err)); |
| break; |
| case WeaveTunnelConnectionMgr::kStatus_TunPrimaryUp: |
| newTunnelState = true; |
| isRestricted = (err == WEAVE_ERROR_TUNNEL_ROUTING_RESTRICTED); |
| WeaveLogProgress(DeviceLayer, "ConnectivityManager: %service tunnel established", (isRestricted) ? "RESTRICTED s" : "S"); |
| break; |
| default: |
| break; |
| } |
| |
| // If the tunnel state has changed... |
| if (newTunnelState != prevTunnelState) |
| { |
| // Update the cached copy of the state. |
| SetFlag(sInstance.mFlags, kFlag_ServiceTunnelUp, newTunnelState); |
| |
| // Alert other components of the change to the tunnel state. |
| WeaveDeviceEvent event; |
| event.Clear(); |
| event.Type = DeviceEventType::kServiceTunnelStateChange; |
| event.ServiceTunnelStateChange.Result = GetConnectivityChange(prevTunnelState, newTunnelState); |
| event.ServiceTunnelStateChange.IsRestricted = isRestricted; |
| PlatformMgr().PostEvent(&event); |
| |
| // If the new tunnel state represents a logical change in connectivity to the service, as it |
| // relates to the application, post a ServiceConnectivityChange event. |
| // (Note that the establishment of a restricted tunnel to the service does not constitute a |
| // logical change in service connectivity from the application's standpoint, as such a tunnel |
| // cannot be used for general application interactions, only pairing). |
| if (!newTunnelState || !isRestricted) |
| { |
| event.Clear(); |
| event.Type = DeviceEventType::kServiceConnectivityChange; |
| event.ServiceConnectivityChange.ViaTunnel.Result = (newTunnelState) ? kConnectivity_Established : kConnectivity_Lost; |
| event.ServiceConnectivityChange.ViaThread.Result = kConnectivity_NoChange; |
| event.ServiceConnectivityChange.Overall.Result = sInstance.HaveServiceConnectivityViaThread() |
| ? kConnectivity_NoChange |
| : event.ServiceConnectivityChange.ViaTunnel.Result; |
| PlatformMgr().PostEvent(&event); |
| } |
| } |
| } |
| |
| } // namespace DeviceLayer |
| } // namespace Weave |
| } // namespace nl |