/* * Copyright (c) 2022 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. */ #include #include #include #include #include #include #include #include #include #if INET_CONFIG_ENABLE_TCP_ENDPOINT #include #endif #if CHIP_DEVICE_CONFIG_ENABLE_WIFI #include #if CHIP_DEVICE_LAYER_TARGET_BL602 #include #endif #if CHIP_DEVICE_LAYER_TARGET_BL702 #include #endif #endif #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE #include #include #endif #if CHIP_DEVICE_CONFIG_ENABLE_THREAD #include #endif using namespace ::chip; using namespace ::chip::Inet; using namespace ::chip::System; using namespace ::chip::DeviceLayer::Internal; namespace chip { namespace DeviceLayer { ConnectivityManagerImpl ConnectivityManagerImpl::sInstance; CHIP_ERROR ConnectivityManagerImpl::_Init() { // Initialize the generic base classes that require it. #if CHIP_DEVICE_CONFIG_ENABLE_THREAD GenericConnectivityManagerImpl_Thread::_Init(); #endif #if CHIP_DEVICE_CONFIG_ENABLE_WIFI mWiFiStationState = ConnectivityManager::kWiFiStationState_NotConnected; ReturnErrorOnFailure(SetWiFiStationMode(kWiFiStationMode_Enabled)); PlatformMgr().AddEventHandler(NetworkCommissioning::NetworkEventHandler, 0); #endif return CHIP_NO_ERROR; } void ConnectivityManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event) { // Forward the event to the generic base classes as needed. #if CHIP_DEVICE_CONFIG_ENABLE_THREAD GenericConnectivityManagerImpl_Thread::_OnPlatformEvent(event); #endif } #if CHIP_DEVICE_CONFIG_ENABLE_WIFI bool ConnectivityManagerImpl::_IsWiFiStationEnabled(void) { return GetWiFiStationMode() == kWiFiStationMode_Enabled; } bool ConnectivityManagerImpl::_IsWiFiStationProvisioned(void) { CHIP_ERROR err = CHIP_NO_ERROR; char ssid[64] = { 0 }; char psk[64] = { 0 }; size_t ssidLen = 0; size_t pskLen = 0; err = PersistedStorage::KeyValueStoreMgr().Get(BLConfig::kConfigKey_WiFiSSID, (void *) ssid, 64, &ssidLen, 0); SuccessOrExit(err); err = PersistedStorage::KeyValueStoreMgr().Get(BLConfig::kConfigKey_WiFiPassword, (void *) psk, 64, &pskLen, 0); SuccessOrExit(err); return (ssidLen != 0); exit: return false; } CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationMode(WiFiStationMode val) { CHIP_ERROR err = CHIP_NO_ERROR; VerifyOrExit(val != kWiFiStationMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT); if (val != kWiFiStationMode_ApplicationControlled) { DeviceLayer::SystemLayer().ScheduleWork(DriveStationState, NULL); } if (mWiFiStationMode != val) { ChipLogProgress(DeviceLayer, "WiFi station mode change: %s -> %s", WiFiStationModeToStr(mWiFiStationMode), WiFiStationModeToStr(val)); } mWiFiStationMode = val; exit: return err; } void ConnectivityManagerImpl::ChangeWiFiStationState(WiFiStationState newState) { if (mWiFiStationState != newState) { ChipLogProgress(DeviceLayer, "WiFi station state change: %s -> %s", WiFiStationStateToStr(mWiFiStationState), WiFiStationStateToStr(newState)); mWiFiStationState = newState; ConnectivityMgrImpl().DriveStationState(); SystemLayer().ScheduleLambda([]() { NetworkCommissioning::BLWiFiDriver::GetInstance().OnNetworkStatusChange(); }); } } void ConnectivityManagerImpl::_ClearWiFiStationProvision(void) { CHIP_ERROR err = CHIP_NO_ERROR; err = PersistedStorage::KeyValueStoreMgr().Delete(BLConfig::kConfigKey_WiFiSSID); SuccessOrExit(err); err = PersistedStorage::KeyValueStoreMgr().Delete(BLConfig::kConfigKey_WiFiPassword); SuccessOrExit(err); exit: return; } void ConnectivityManagerImpl::_OnWiFiStationProvisionChange(void) { DeviceLayer::SystemLayer().ScheduleWork(DriveStationState, NULL); } CHIP_ERROR ConnectivityManagerImpl::ConnectProvisionedWiFiNetwork(void) { char ssid[64] = { 0 }; char psk[64] = { 0 }; size_t ssidLen = 0; size_t pskLen = 0; ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Get(BLConfig::kConfigKey_WiFiSSID, (void *) ssid, 64, &ssidLen, 0)); ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Get(BLConfig::kConfigKey_WiFiPassword, (void *) psk, 64, &pskLen, 0)); NetworkCommissioning::BLWiFiDriver::GetInstance().ConnectWiFiNetwork(ssid, ssidLen, psk, pskLen); return CHIP_NO_ERROR; } void ConnectivityManagerImpl::OnWiFiStationConnected() { ChipDeviceEvent event; event.Type = DeviceEventType::kWiFiConnectivityChange; event.WiFiConnectivityChange.Result = kConnectivity_Established; PlatformMgr().PostEventOrDie(&event); WiFiDiagnosticsDelegate * delegate = GetDiagnosticDataProvider().GetWiFiDiagnosticsDelegate(); if (delegate) { delegate->OnConnectionStatusChanged( chip::to_underlying(chip::app::Clusters::WiFiNetworkDiagnostics::ConnectionStatusEnum::kConnected)); } } void ConnectivityManagerImpl::DriveStationState() { ChipLogProgress(DeviceLayer, "DriveStationState: mWiFiStationState=%s", WiFiStationStateToStr(mWiFiStationState)); switch (mWiFiStationState) { case ConnectivityManager::kWiFiStationState_NotConnected: { if (GetWiFiStationMode() == ConnectivityManager::kWiFiStationMode_Enabled && IsWiFiStationProvisioned()) { ConnectProvisionedWiFiNetwork(); } } break; case ConnectivityManager::kWiFiStationState_Connecting: { ChipLogProgress(DeviceLayer, "Wi-Fi station is connecting to AP"); } break; case ConnectivityManager::kWiFiStationState_Connecting_Succeeded: { ChipLogProgress(DeviceLayer, "Wi-Fi station successfully connects to AP"); mConnectivityFlag.ClearAll(); mConnectivityFlag.Set(ConnectivityFlags::kAwaitingConnectivity); } break; case ConnectivityManager::kWiFiStationState_Connecting_Failed: { ChipLogProgress(DeviceLayer, "Wi-Fi station connecting failed"); mConnectivityFlag.ClearAll(); OnWiFiStationDisconnected(); if (ConnectivityManager::kWiFiStationState_Connecting == mWiFiStationState) { SystemLayer().ScheduleLambda([]() { NetworkCommissioning::BLWiFiDriver::GetInstance().OnConnectWiFiNetwork(false); }); } } break; case ConnectivityManager::kWiFiStationState_Connected: { ChipLogProgress(DeviceLayer, "Wi-Fi station connected."); OnWiFiStationConnected(); SystemLayer().ScheduleLambda([]() { NetworkCommissioning::BLWiFiDriver::GetInstance().OnConnectWiFiNetwork(true); }); } break; case ConnectivityManager::kWiFiStationState_Disconnecting: { ChipLogProgress(DeviceLayer, "Wi-Fi station is disconnecting to AP"); mConnectivityFlag.ClearAll(); } break; default: break; } } void ConnectivityManagerImpl::DriveStationState(::chip::System::Layer * aLayer, void * aAppState) { ConnectivityMgrImpl().DriveStationState(); } #endif #if CHIP_DEVICE_CONFIG_ENABLE_ETHERNET || CHIP_DEVICE_CONFIG_ENABLE_WIFI void ConnectivityManagerImpl::OnConnectivityChanged(struct netif * interface) { bool haveIPv4Conn = false; bool haveIPv6Conn = false; const bool hadIPv4Conn = mConnectivityFlag.Has(ConnectivityFlags::kHaveIPv4InternetConnectivity); const bool hadIPv6Conn = mConnectivityFlag.Has(ConnectivityFlags::kHaveIPv6InternetConnectivity); IPAddress addr; if (interface != NULL && netif_is_up(interface) && netif_is_link_up(interface)) { mConnectivityFlag.Clear(ConnectivityFlags::kAwaitingConnectivity); if (!ip4_addr_isany(netif_ip4_addr(interface)) && !ip4_addr_isany(netif_ip4_gw(interface))) { haveIPv4Conn = true; char addrStr[INET_ADDRSTRLEN]; ip4addr_ntoa_r(netif_ip4_addr(interface), addrStr, sizeof(addrStr)); IPAddress::FromString(addrStr, addr); if (0 != memcmp(netif_ip4_addr(interface), &m_ip4addr, sizeof(ip4_addr_t))) { ChipLogProgress(DeviceLayer, "IPv4 Address Assigned, %s", ip4addr_ntoa(netif_ip4_addr(interface))); memcpy(&m_ip4addr, netif_ip4_addr(interface), sizeof(ip4_addr_t)); ConnectivityMgrImpl().OnIPv4AddressAvailable(); } } // 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 (uint32_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (!ip6_addr_islinklocal(netif_ip6_addr(interface, i)) && ip6_addr_isvalid(netif_ip6_addr_state(interface, i))) { haveIPv6Conn = true; if (0 != memcmp(netif_ip6_addr(interface, i), m_ip6addr + i, sizeof(ip6_addr_t))) { ChipLogProgress(DeviceLayer, "IPv6 Address Assigned, %s", ip6addr_ntoa(netif_ip6_addr(interface, i))); memcpy(m_ip6addr + i, netif_ip6_addr(interface, i), sizeof(ip6_addr_t)); ConnectivityMgrImpl().OnIPv6AddressAvailable(); } } } } // If the internet connectivity state has changed... if (haveIPv4Conn != hadIPv4Conn || haveIPv6Conn != hadIPv6Conn) { // Update the current state. mConnectivityFlag.Set(ConnectivityFlags::kHaveIPv4InternetConnectivity, haveIPv4Conn); mConnectivityFlag.Set(ConnectivityFlags::kHaveIPv6InternetConnectivity, haveIPv6Conn); // Alert other components of the state change. ChipDeviceEvent event; event.Type = DeviceEventType::kInternetConnectivityChange; event.InternetConnectivityChange.IPv4 = GetConnectivityChange(hadIPv4Conn, haveIPv4Conn); event.InternetConnectivityChange.IPv6 = GetConnectivityChange(hadIPv6Conn, haveIPv6Conn); event.InternetConnectivityChange.ipAddress = addr; PlatformMgr().PostEventOrDie(&event); if (haveIPv4Conn != hadIPv4Conn) { memset(&m_ip4addr, 0, sizeof(ip4_addr_t)); ChipLogProgress(DeviceLayer, "%s Internet connectivity %s", "IPv4", (haveIPv4Conn) ? "ESTABLISHED" : "LOST"); } if (haveIPv6Conn != hadIPv6Conn) { memset(&m_ip6addr, 0, sizeof(ip6_addr_t) * LWIP_IPV6_NUM_ADDRESSES); ChipLogProgress(DeviceLayer, "%s Internet connectivity %s", "IPv6", (haveIPv6Conn) ? "ESTABLISHED" : "LOST"); } } } void ConnectivityManagerImpl::OnIPv4AddressAvailable() { ChipDeviceEvent event; event.Type = DeviceEventType::kInterfaceIpAddressChanged; event.InterfaceIpAddressChanged.Type = InterfaceIpChangeType::kIpV4_Assigned; PlatformMgr().PostEventOrDie(&event); } void ConnectivityManagerImpl::OnIPv6AddressAvailable() { ChipDeviceEvent event; event.Type = DeviceEventType::kInterfaceIpAddressChanged; event.InterfaceIpAddressChanged.Type = InterfaceIpChangeType::kIpV6_Assigned; PlatformMgr().PostEventOrDie(&event); } #endif } // namespace DeviceLayer } // namespace chip