/* * * Copyright (c) 2020 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. */ /* this file behaves like a config.h, comes first */ #include #include #include #include #include #include #include #include #include #include #include #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE #include #endif #include "mt7933_pos.h" #include "wifi_api_ex.h" using namespace ::chip; using namespace ::chip::Inet; using namespace ::chip::System; using namespace ::chip::DeviceLayer::Internal; namespace chip { namespace DeviceLayer { CHIP_ERROR ConnectivityManagerImpl::WiFiInit(void) { CHIP_ERROR err = CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; ChipLogProgress(DeviceLayer, "ConnectivityManager Wi-Fi init"); #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION // Queue work items to bootstrap the AP and station state machines once // the Chip event loop is running. mWiFiStationMode = kWiFiStationMode_Disabled; mWiFiStationState = kWiFiStationState_NotConnected; mLastStationConnectFailTime = System::Clock::kZero; mWiFiStationReconnectInterval = System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_WIFI_STATION_RECONNECT_INTERVAL); #endif #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP mWiFiAPMode = kWiFiAPMode_Disabled; mWiFiAPState = kWiFiAPState_NotActive; mWiFiAPIdleTimeout = System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_WIFI_AP_IDLE_TIMEOUT); mLastAPDemandTime = System::Clock::kZero; #endif mFlags.ClearAll(); mFilogicCtx = PlatformMgrImpl().mFilogicCtx; if (!IsWiFiStationProvisioned()) { #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP mWiFiAPMode = kWiFiAPMode_Enabled; mWiFiAPState = kWiFiAPState_NotActive; filogic_wifi_init_async(mFilogicCtx, FILOGIC_WIFI_OPMODE_AP); err = CHIP_NO_ERROR; SuccessOrExit(err); #endif } else { #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION mWiFiStationMode = kWiFiStationMode_Enabled; mWiFiStationState = kWiFiStationState_NotConnected; filogic_wifi_init_async(mFilogicCtx, FILOGIC_WIFI_OPMODE_STA); err = CHIP_NO_ERROR; SuccessOrExit(err); #endif } ChipLogProgress(DeviceLayer, "ConnectivityManager Wi-Fi init done"); exit: return err; } void ConnectivityManagerImpl::ChangeWiFiAPState(WiFiAPState newState) { if (mWiFiAPState != newState) { ChipLogProgress(DeviceLayer, "WiFi AP state change: %s -> %s", WiFiAPStateToStr(mWiFiAPState), WiFiAPStateToStr(newState)); mWiFiAPState = newState; } } void ConnectivityManagerImpl::_OnWiFiPlatformEvent(const ChipDeviceEvent * event) { if (event->Type != DeviceEventType::kMtkWiFiEvent) return; ChipLogProgress(DeviceLayer, "%s WiFi event %s", __func__, filogic_event_to_name(event->Platform.FilogicEvent.event)); const filogic_async_event_data * event_data; bool hadIPv4Conn = mFlags.Has(ConnectivityFlags::kHaveIPv4InternetConnectivity); bool hadIPv6Conn = mFlags.Has(ConnectivityFlags::kHaveIPv6InternetConnectivity); event_data = &event->Platform.MtkWiFiEvent.event_data; if (event_data->event_id == FILOGIC_WIFI_INIT_OK) { if (FILOGIC_WIFI_PORT_STA == event_data->u.wifi_init.port) { mWiFiStationState = kWiFiStationState_NotConnected; DriveStationState(); } else if (FILOGIC_WIFI_PORT_AP == event_data->u.wifi_init.port) { ConfigureWiFiAP(); ChangeWiFiAPState(kWiFiAPState_Activating); } else assert(0); } else if (event_data->event_id == FILOGIC_AP_START_OK) { ChangeWiFiAPState(kWiFiAPState_Active); } else if (event_data->event_id == FILOGIC_SET_OPMODE_OK) { if (event_data->u.wifi_opmode.opmode == WIFI_MODE_STA_ONLY) ChangeWiFiStationState(kWiFiStationState_NotConnected); else if (event_data->u.wifi_opmode.opmode == WIFI_MODE_AP_ONLY) ChangeWiFiAPState(kWiFiAPState_Active); else assert(0); } else if (event_data->event_id == FILOGIC_AP_STATION_CONNECTED) { MaintainOnDemandWiFiAP(); } else if (event_data->event_id == FILOGIC_AP_STATION_DISCONNECTED) { } else if (event_data->event_id == FILOGIC_STA_DISCONNECTED_FROM_AP) { if (mWiFiStationState == kWiFiStationState_Connecting) { ChangeWiFiStationState(kWiFiStationState_Connecting_Failed); } DriveStationState(); } else if (!hadIPv4Conn && event_data->event_id == FILOGIC_STA_IPV4_ADDR_READY) { if (mWiFiStationState == kWiFiStationState_Connecting) { ChangeWiFiStationState(kWiFiStationState_Connecting_Succeeded); } ChipLogProgress(DeviceLayer, "ip addr: %s", event_data->u.ipv4_str.addr); DriveStationState(); UpdateInternetConnectivityState(TRUE, hadIPv6Conn, event_data->u.ipv4_str.addr); } if (!hadIPv6Conn && event_data->event_id == FILOGIC_STA_IPV6_ADDR_READY) { if (mWiFiStationState == kWiFiStationState_Connecting) { ChangeWiFiStationState(kWiFiStationState_Connecting_Succeeded); } const char * addrv6 = (const char *) &event_data->u.ipv6_str.addr[0]; ChipLogProgress(DeviceLayer, "ip addr: %s", addrv6); DriveStationState(); UpdateInternetConnectivityState(hadIPv4Conn, TRUE, event_data->u.ipv6_str.addr); } else if (event->Platform.FilogicEvent.event == FILOGIC_STA_CONNECTED_TO_AP) { ChipLogProgress(DeviceLayer, "WIFI_EVENT_STA_CONNECTED"); if (mWiFiStationState == kWiFiStationState_Connecting) { ChangeWiFiStationState(kWiFiStationState_Connecting_Succeeded); } DriveStationState(); } } #if CHIP_DEVICE_CONFIG_ENABLE_WIFI ConnectivityManager::WiFiStationMode ConnectivityManagerImpl::GetFilogicStationMode(void) { #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION filogic_wifi_opmode_t opmode; int32_t ret; filogic_wifi_opmode_get_sync(mFilogicCtx, &opmode); if (opmode == FILOGIC_WIFI_OPMODE_STA || opmode == FILOGIC_WIFI_OPMODE_DUAL) return kWiFiStationMode_Enabled; #endif return kWiFiStationMode_Disabled; } ConnectivityManager::WiFiAPMode ConnectivityManagerImpl::GetFilogicAPMode(void) { #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP filogic_wifi_opmode_t opmode; int32_t ret; filogic_wifi_opmode_get_sync(mFilogicCtx, &opmode); if (opmode == FILOGIC_WIFI_OPMODE_AP || opmode == FILOGIC_WIFI_OPMODE_DUAL) return kWiFiAPMode_Enabled; #endif return kWiFiAPMode_Disabled; } filogic_wifi_opmode_t ConnectivityManagerImpl::GetFilogicNextOpMode(WiFiStationMode staMode, WiFiAPMode apMode) { bool sta, ap; filogic_wifi_opmode_t opmode; ChipLogProgress(DeviceLayer, "%s %d %d", __func__, staMode, apMode); sta = staMode == kWiFiStationMode_Enabled; ap = apMode == kWiFiAPMode_Enabled; if (sta && ap) opmode = FILOGIC_WIFI_OPMODE_DUAL; else if (ap) opmode = FILOGIC_WIFI_OPMODE_AP; else if (sta) opmode = FILOGIC_WIFI_OPMODE_STA; else opmode = FILOGIC_WIFI_OPMODE_NONE; return opmode; } void ConnectivityManagerImpl::SetFlogicNextMode(filogic_wifi_opmode_t nextMode) { ChipLogProgress(DeviceLayer, "WiFi driver mode set %s", filogic_opmode_to_name(nextMode)); filogic_wifi_opmode_set_async(mFilogicCtx, nextMode); } #endif #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION ConnectivityManager::WiFiStationMode ConnectivityManagerImpl::_GetWiFiStationMode(void) { if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled) { filogic_wifi_opmode_t opmode; filogic_wifi_opmode_get_sync(mFilogicCtx, &opmode); if (opmode == FILOGIC_WIFI_OPMODE_AP) mWiFiStationMode = kWiFiStationMode_Disabled; else mWiFiStationMode = kWiFiStationMode_Enabled; } return mWiFiStationMode; } CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationMode(ConnectivityManager::WiFiStationMode val) { ChipLogProgress(DeviceLayer, "%s", __func__); if (mWiFiStationMode != val) { ChipLogProgress(DeviceLayer, "WiFi station mode change: %s -> %s", WiFiStationModeToStr(mWiFiStationMode), WiFiStationModeToStr(val)); DeviceLayer::SystemLayer().ScheduleWork(DriveStationState, NULL); mWiFiStationMode = val; } return CHIP_NO_ERROR; } CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationReconnectInterval(System::Clock::Timeout val) { ChipLogProgress(DeviceLayer, "%s", __func__); mWiFiStationReconnectInterval = val; return CHIP_NO_ERROR; } CHIP_ERROR ConnectivityManagerImpl::_GetAndLogWifiStatsCounters(void) { ChipLogProgress(DeviceLayer, "%s", __func__); return CHIP_ERROR_NOT_IMPLEMENTED; } bool ConnectivityManagerImpl::_IsWiFiStationEnabled(void) { return GetWiFiStationMode() == kWiFiStationMode_Enabled; } bool ConnectivityManagerImpl::_IsWiFiStationProvisioned(void) { filogic_wifi_sta_prov_t prov = {}; /* See if we have SSID */ if (filogic_wifi_sta_prov_get_sync(mFilogicCtx, &prov)) { return prov.ssid[0] != '\0'; } return false; } void ConnectivityManagerImpl::_ClearWiFiStationProvision(void) { ChipLogProgress(DeviceLayer, "%s", __func__); if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled) { #ifdef MT793X_PORTING wfx_clear_wifi_provision(); #endif /* MT793X_PORTING */ DeviceLayer::SystemLayer().ScheduleWork(DriveStationState, NULL); } } void ConnectivityManagerImpl::_OnWiFiScanDone() { // CHIP_ERROR_NOT_IMPLEMENTED } void ConnectivityManagerImpl::_OnWiFiStationProvisionChange() { ChipLogProgress(DeviceLayer, "%s", __func__); // Schedule a call to the DriveStationState method to adjust the station state as needed. ChipLogProgress(DeviceLayer, "_ON WIFI PROVISION CHANGE"); DeviceLayer::SystemLayer().ScheduleWork(DriveStationState, NULL); } #endif #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP void ConnectivityManagerImpl::DriveAPState(void) { CHIP_ERROR err = CHIP_NO_ERROR; WiFiAPMode driverAPMode = GetFilogicAPMode(); filogic_wifi_opmode_t nextMode; ChipLogProgress(DeviceLayer, "%s", __func__); if (mWiFiAPMode != driverAPMode) { nextMode = GetFilogicNextOpMode(mWiFiStationMode, driverAPMode); ChipLogProgress(DeviceLayer, "WiFi Driver AP mode set: %d", nextMode); SetFlogicNextMode(nextMode); if (driverAPMode == kWiFiAPMode_Enabled) { } // TODO wait driver event } } CHIP_ERROR ConnectivityManagerImpl::ConfigureWiFiAP(void) { char ssid[32]; int ssid_len; ChipLogProgress(DeviceLayer, "%s", __func__); CHIP_ERROR err = CHIP_NO_ERROR; // TODO, generate uint16_t discriminator = 0x8888; ssid_len = snprintf(ssid, sizeof(ssid), "%s%03X-%04X-%04X", CHIP_DEVICE_CONFIG_WIFI_AP_SSID_PREFIX, discriminator, CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID, CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID); int8_t channel = CHIP_DEVICE_CONFIG_WIFI_AP_CHANNEL; filogic_wifi_ap_config_async(mFilogicCtx, channel, ssid, ssid_len); return err; } void ConnectivityManagerImpl::DriveAPState(::chip::System::Layer * aLayer, void * aAppState) { sInstance.DriveAPState(); } CHIP_ERROR ConnectivityManagerImpl::_SetWiFiAPMode(WiFiAPMode val) { ChipLogProgress(DeviceLayer, "%s", __func__); 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; exit: return err; } void ConnectivityManagerImpl::_DemandStartWiFiAP(void) { ChipLogProgress(DeviceLayer, "%s", __func__); if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision) { mLastAPDemandTime = System::SystemClock().GetMonotonicTimestamp(); DeviceLayer::SystemLayer().ScheduleWork(DriveAPState, NULL); } } void ConnectivityManagerImpl::_StopOnDemandWiFiAP(void) { ChipLogProgress(DeviceLayer, "%s", __func__); if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision) { mLastAPDemandTime = System::Clock::kZero; DeviceLayer::SystemLayer().ScheduleWork(DriveAPState, NULL); } } void ConnectivityManagerImpl::_MaintainOnDemandWiFiAP(void) { ChipLogProgress(DeviceLayer, "%s", __func__); if (mWiFiAPMode == kWiFiAPMode_OnDemand || mWiFiAPMode == kWiFiAPMode_OnDemand_NoStationProvision) { if (mWiFiAPState == kWiFiAPState_Activating || mWiFiAPState == kWiFiAPState_Active) { mLastAPDemandTime = System::SystemClock().GetMonotonicTimestamp(); } } } void ConnectivityManagerImpl::_SetWiFiAPIdleTimeout(System::Clock::Timeout val) { ChipLogProgress(DeviceLayer, "%s", __func__); mWiFiAPIdleTimeout = val; DeviceLayer::SystemLayer().ScheduleWork(DriveAPState, NULL); } #endif /* CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP */ /**************************************************************************** * ConnectivityManager Private Methods ****************************************************************************/ #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION void ConnectivityManagerImpl::DriveStationState() { ChipLogProgress(DeviceLayer, "%s", __func__); CHIP_ERROR err = CHIP_NO_ERROR; int32_t status; bool stationConnected; // Refresh the current station mode. GetWiFiStationMode(); // If the station interface is NOT under application control... if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled) { if (mWiFiStationMode != kWiFiStationMode_Enabled) { ChipLogProgress(DeviceLayer, "WiFi station mode set"); mWiFiStationState = kWiFiStationState_NotConnected; SetFlogicNextMode(FILOGIC_WIFI_OPMODE_STA); return; } } stationConnected = filogic_wifi_sta_get_link_status_sync(mFilogicCtx); // 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); ChipLogProgress(DeviceLayer, "WiFi station interface connected"); mLastStationConnectFailTime = System::Clock::kZero; 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())) { ChipLogProgress(DeviceLayer, "Disconnecting WiFi station interface"); status = wifi_connection_disconnect_ap(); if (status < 0) { ChipLogError(DeviceLayer, "WiFi disconnect : FAIL: %ld", status); } ChangeWiFiStationState(kWiFiStationState_Disconnecting); } } // Otherwise the station interface is NOT connected to an AP, so... else { System::Clock::Timestamp now = System::SystemClock().GetMonotonicTimestamp(); // 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) { ChipLogProgress(DeviceLayer, "WiFi station interface disconnected"); mLastStationConnectFailTime = System::Clock::kZero; 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()) { // 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 == System::Clock::kZero || now >= mLastStationConnectFailTime + mWiFiStationReconnectInterval) { if (mWiFiStationState != kWiFiStationState_Connecting) { ChipLogProgress(DeviceLayer, "Attempting to connect WiFi"); status = wifi_config_reload_setting(); if (status < 0) { ChipLogError(DeviceLayer, "WiFi start connect : FAIL %ld", status); goto exit; } ChangeWiFiStationState(kWiFiStationState_Connecting); } } // Otherwise arrange another connection attempt at a suitable point in the future. else { System::Clock::Timestamp timeToNextConnect = (mLastStationConnectFailTime + mWiFiStationReconnectInterval) - now; ChipLogProgress(DeviceLayer, "Next WiFi station reconnect in %" PRIu32 " ms", System::Clock::Milliseconds32(timeToNextConnect).count()); ReturnOnFailure(DeviceLayer::SystemLayer().StartTimer(timeToNextConnect, DriveStationState, NULL)); } } } exit: ChipLogProgress(DeviceLayer, "Done driving station state, nothing else to do..."); } void ConnectivityManagerImpl::OnStationConnected() { ChipLogProgress(DeviceLayer, "%s", __func__); ChipDeviceEvent event; NetworkCommissioning::GenioWiFiDriver::GetInstance().OnConnectWiFiNetwork(); // Alert other components of the new state. event.Type = DeviceEventType::kWiFiConnectivityChange; event.WiFiConnectivityChange.Result = kConnectivity_Established; (void) PlatformMgr().PostEvent(&event); UpdateInternetConnectivityState(FALSE, FALSE, NULL); } void ConnectivityManagerImpl::OnStationDisconnected() { ChipLogProgress(DeviceLayer, "%s", __func__); // TODO Invoke WARM to perform actions that occur when the WiFi station interface goes down. // Alert other components of the new state. ChipDeviceEvent event; event.Type = DeviceEventType::kWiFiConnectivityChange; event.WiFiConnectivityChange.Result = kConnectivity_Lost; (void) PlatformMgr().PostEvent(&event); UpdateInternetConnectivityState(FALSE, FALSE, NULL); } void ConnectivityManagerImpl::DriveStationState(::chip::System::Layer * aLayer, void * aAppState) { ChipLogProgress(DeviceLayer, "%s", __func__); sInstance.DriveStationState(); } void ConnectivityManagerImpl::ChangeWiFiStationState(WiFiStationState newState) { ChipLogProgress(DeviceLayer, "%s", __func__); if (mWiFiStationState != newState) { ChipLogProgress(DeviceLayer, "WiFi station state change: %s -> %s", WiFiStationStateToStr(mWiFiStationState), WiFiStationStateToStr(newState)); mWiFiStationState = newState; } } void ConnectivityManagerImpl::UpdateInternetConnectivityState(bool haveIPv4Conn, bool haveIPv6Conn, const uint8_t * ipAddr) { ChipLogProgress(DeviceLayer, "%s", __func__); bool hadIPv4Conn = mFlags.Has(ConnectivityFlags::kHaveIPv4InternetConnectivity); bool hadIPv6Conn = mFlags.Has(ConnectivityFlags::kHaveIPv6InternetConnectivity); ConnectivityChange connV4Change = GetConnectivityChange(hadIPv4Conn, haveIPv4Conn); ConnectivityChange connV6Change = GetConnectivityChange(hadIPv6Conn, haveIPv6Conn); IPAddress addr; // If the WiFi station is currently in the connected state... if (mWiFiStationState == kWiFiStationState_Connected) { IPAddress::FromString((char *) ipAddr, addr); } // If the internet connectivity state has changed... if (connV4Change != kConnectivity_NoChange) { // Update the current state. mFlags.Set(ConnectivityFlags::kHaveIPv4InternetConnectivity, haveIPv4Conn); // Alert other components of the state change. ChipDeviceEvent event; event.Type = DeviceEventType::kInternetConnectivityChange; event.InternetConnectivityChange.IPv4 = connV4Change; event.InternetConnectivityChange.IPv6 = kConnectivity_NoChange; event.InternetConnectivityChange.ipAddress = addr; (void) PlatformMgr().PostEvent(&event); ChipLogProgress(DeviceLayer, "%s Internet connectivity %s", "IPv4", (haveIPv4Conn) ? "ESTABLISHED" : "LOST"); } // If the internet connectivity state has changed... if (connV6Change != kConnectivity_NoChange) { // Update the current state. mFlags.Set(ConnectivityFlags::kHaveIPv6InternetConnectivity, haveIPv6Conn); // Alert other components of the state change. ChipDeviceEvent event; event.Type = DeviceEventType::kInternetConnectivityChange; event.InternetConnectivityChange.IPv4 = kConnectivity_NoChange; event.InternetConnectivityChange.IPv6 = connV6Change; event.InternetConnectivityChange.ipAddress = addr; (void) PlatformMgr().PostEvent(&event); ChipLogProgress(DeviceLayer, "%s Internet connectivity %s", "IPv6", (haveIPv6Conn) ? "ESTABLISHED" : "LOST"); } } #endif } // namespace DeviceLayer } // namespace chip