/* * * Copyright (c) 2022 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 #include #include #include #include #include #include "wlan_ui_pub.h" using namespace ::chip; #if CHIP_DEVICE_CONFIG_ENABLE_WIFI namespace chip { namespace DeviceLayer { namespace NetworkCommissioning { namespace { constexpr char kWiFiSSIDKeyName[] = "wifi-ssid"; constexpr char kWiFiCredentialsKeyName[] = "wifi-pass"; } // namespace CHIP_ERROR BekenWiFiDriver::Init(NetworkStatusChangeCallback * networkStatusChangeCallback) { CHIP_ERROR err; ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::Init\r\n"); err = GetSavedNetWorkConfig(&mSavedNetwork); mStagingNetwork = mSavedNetwork; mpScanCallback = nullptr; mpConnectCallback = nullptr; mpStatusChangeCallback = networkStatusChangeCallback; return err; } CHIP_ERROR BekenWiFiDriver::GetSavedNetWorkConfig(WiFiNetwork * WifiNetconf) { CHIP_ERROR err; size_t ssidLen = 0; size_t credentialsLen = 0; memset(WifiNetconf, 0x0, sizeof(WiFiNetwork)); err = PersistedStorage::KeyValueStoreMgr().Get(kWiFiCredentialsKeyName, WifiNetconf->credentials, sizeof(WifiNetconf->credentials), &credentialsLen); if (err == CHIP_ERROR_NOT_FOUND) { return CHIP_NO_ERROR; } err = PersistedStorage::KeyValueStoreMgr().Get(kWiFiSSIDKeyName, WifiNetconf->ssid, sizeof(WifiNetconf->ssid), &ssidLen); if (err == CHIP_ERROR_NOT_FOUND) { return CHIP_NO_ERROR; } WifiNetconf->credentialsLen = credentialsLen; WifiNetconf->ssidLen = ssidLen; return err; } void BekenWiFiDriver::Shutdown() { mpStatusChangeCallback = nullptr; } CHIP_ERROR BekenWiFiDriver::CommitConfiguration() { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::CommitConfiguration\r\n"); ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Put(kWiFiSSIDKeyName, mStagingNetwork.ssid, mStagingNetwork.ssidLen)); ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Put(kWiFiCredentialsKeyName, mStagingNetwork.credentials, mStagingNetwork.credentialsLen)); mSavedNetwork = mStagingNetwork; return CHIP_NO_ERROR; } CHIP_ERROR BekenWiFiDriver::RevertConfiguration() { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::RevertConfiguration\r\n"); mStagingNetwork = mSavedNetwork; return CHIP_NO_ERROR; } bool BekenWiFiDriver::NetworkMatch(const WiFiNetwork & network, ByteSpan networkId) { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::NetworkMatch\r\n"); return networkId.size() == network.ssidLen && memcmp(networkId.data(), network.ssid, network.ssidLen) == 0; } Status BekenWiFiDriver::AddOrUpdateNetwork(ByteSpan ssid, ByteSpan credentials, MutableCharSpan & outDebugText, uint8_t & outNetworkIndex) { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::AddOrUpdateNetwork\r\n"); outDebugText.reduce_size(0); outNetworkIndex = 0; VerifyOrReturnError(mStagingNetwork.ssidLen == 0 || NetworkMatch(mStagingNetwork, ssid), Status::kBoundsExceeded); VerifyOrReturnError(credentials.size() <= sizeof(mStagingNetwork.credentials), Status::kOutOfRange); VerifyOrReturnError(ssid.size() <= sizeof(mStagingNetwork.ssid), Status::kOutOfRange); memcpy(mStagingNetwork.credentials, credentials.data(), credentials.size()); mStagingNetwork.credentialsLen = static_cast(credentials.size()); memcpy(mStagingNetwork.ssid, ssid.data(), ssid.size()); mStagingNetwork.ssidLen = static_cast(ssid.size()); return Status::kSuccess; } Status BekenWiFiDriver::RemoveNetwork(ByteSpan networkId, MutableCharSpan & outDebugText, uint8_t & outNetworkIndex) { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::RemoveNetwork\r\n"); outDebugText.reduce_size(0); outNetworkIndex = 0; VerifyOrReturnError(NetworkMatch(mStagingNetwork, networkId), Status::kNetworkIDNotFound); // Use empty ssid for representing invalid network mStagingNetwork.ssidLen = 0; return Status::kSuccess; } Status BekenWiFiDriver::ReorderNetwork(ByteSpan networkId, uint8_t index, MutableCharSpan & outDebugText) { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::ReorderNetwork\r\n"); // Only one network is supported now outDebugText.reduce_size(0); VerifyOrReturnError(index == 0, Status::kOutOfRange); VerifyOrReturnError(NetworkMatch(mStagingNetwork, networkId), Status::kNetworkIDNotFound); return Status::kSuccess; } CHIP_ERROR BekenWiFiDriver::ConnectWiFiNetwork(const char * ssid, uint8_t ssidLen, const char * key, uint8_t keyLen) { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::ConnectWiFiNetwork....ssid:%s", StringOrNullMarker(ssid)); ReturnErrorOnFailure(ConnectivityMgr().SetWiFiStationMode(ConnectivityManager::kWiFiStationMode_Disabled)); wifi_sta_config_t sta_config; memset(&sta_config, 0x0, sizeof(sta_config)); sta_config.security = WIFI_SECURITY_AUTO; // can't use WIFI_DEFAULT_STA_CONFIG because of C99 designator error Platform::CopyString(sta_config.ssid, ssidLen, ssid); Platform::CopyString(sta_config.password, keyLen, key); BK_LOG_ON_ERR(bk_wifi_sta_set_config(&sta_config)); BK_LOG_ON_ERR(bk_wifi_sta_start()); BK_LOG_ON_ERR(bk_wifi_sta_connect()); return ConnectivityMgr().SetWiFiStationMode(ConnectivityManager::kWiFiStationMode_Enabled); } void BekenWiFiDriver::OnConnectWiFiNetwork() { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::OnConnectWiFiNetwork\r\n"); if (mpConnectCallback) { // chip::DeviceLayer::PlatformMgr().LockChipStack(); mpConnectCallback->OnResult(Status::kSuccess, CharSpan(), 0); // chip::DeviceLayer::PlatformMgr().UnlockChipStack(); mpConnectCallback = nullptr; } } void BekenWiFiDriver::ConnectNetwork(ByteSpan networkId, ConnectCallback * callback) { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::ConnectNetwork\r\n"); CHIP_ERROR err = CHIP_NO_ERROR; Status networkingStatus = Status::kSuccess; VerifyOrExit(NetworkMatch(mStagingNetwork, networkId), networkingStatus = Status::kNetworkIDNotFound); VerifyOrExit(mpConnectCallback == nullptr, networkingStatus = Status::kUnknownError); err = ConnectWiFiNetwork(reinterpret_cast(mStagingNetwork.ssid), mStagingNetwork.ssidLen, reinterpret_cast(mStagingNetwork.credentials), mStagingNetwork.credentialsLen); mpConnectCallback = callback; exit: if (err != CHIP_NO_ERROR) { networkingStatus = Status::kUnknownError; } if (networkingStatus != Status::kSuccess) { ChipLogError(NetworkProvisioning, "Failed to connect to WiFi network:%s", chip::ErrorStr(err)); mpConnectCallback = nullptr; // chip::DeviceLayer::PlatformMgr().LockChipStack(); callback->OnResult(networkingStatus, CharSpan(), 0); // chip::DeviceLayer::PlatformMgr().UnlockChipStack(); } } CHIP_ERROR GetConnectedNetwork(Network & network) { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::GetConnectedNetwork\r\n"); wifi_link_status_t wifi_setting; memset(&wifi_setting, 0x0, sizeof(wifi_setting)); bk_wifi_sta_get_link_status(&wifi_setting); uint8_t length = strnlen(reinterpret_cast(wifi_setting.ssid), DeviceLayer::Internal::kMaxWiFiSSIDLength); os_memcpy(network.networkID, wifi_setting.ssid, length); ChipLogProgress(NetworkProvisioning, "networkID:[%s][%d]\r\n", network.networkID, length); network.networkIDLen = length; return CHIP_NO_ERROR; } void BekenWiFiDriver::OnNetworkStatusChange() { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::OnNetworkStatusChange\r\n"); Network configuredNetwork = { 0 }; VerifyOrReturn(mpStatusChangeCallback != nullptr); GetConnectedNetwork(configuredNetwork); if (configuredNetwork.networkIDLen) { mpStatusChangeCallback->OnNetworkingStatusChange( Status::kSuccess, MakeOptional(ByteSpan(configuredNetwork.networkID, configuredNetwork.networkIDLen)), NullOptional); return; } mpStatusChangeCallback->OnNetworkingStatusChange( Status::kUnknownError, MakeOptional(ByteSpan(configuredNetwork.networkID, configuredNetwork.networkIDLen)), MakeOptional(GetLastDisconnectReason())); } CHIP_ERROR BekenWiFiDriver::SetLastDisconnectReason(const ChipDeviceEvent * event) { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::SetLastDisconnectReason\r\n"); mLastDisconnectedReason = event->Platform.BKSystemEvent.Data.WiFiStaDisconnected; return CHIP_NO_ERROR; } int32_t BekenWiFiDriver::GetLastDisconnectReason() { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::GetLastDisconnectReason\r\n"); return mLastDisconnectedReason; } static beken_semaphore_t matter_scan_sema = NULL; int scan_done_handler(void * arg, event_module_t event_module, int event_id, void * event_data) { if (matter_scan_sema) { rtos_set_semaphore(&matter_scan_sema); } return BK_OK; } CHIP_ERROR BekenWiFiDriver::StartScanWiFiNetworks(ByteSpan ssid) { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::StartScanWiFiNetworks\r\n"); wifi_scan_config_t config = { 0 }; if (ssid.data() == NULL) // non-directed scanning { ChipLogProgress(NetworkProvisioning, "non-directed scanning...\r\n"); BK_LOG_ON_ERR(bk_wifi_scan_start(NULL)); } else // directed scanning { os_memcpy(config.ssid, ssid.data(), ssid.size()); ChipLogProgress(NetworkProvisioning, "directed scanning... ssid:%s ; %d \r\n", config.ssid, ssid.size()); BK_LOG_ON_ERR(bk_wifi_scan_start(&config)); } return CHIP_NO_ERROR; } void BekenWiFiDriver::OnScanWiFiNetworkDone() { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::OnScanWiFiNetworkDone\r\n"); if (!GetInstance().mpScanCallback) { ChipLogProgress(NetworkProvisioning, "can't find the ScanCallback function\r\n"); return; } wifi_scan_result_t scan_result = { 0 }; int scan_rst_ap_num = 0; BK_LOG_ON_ERR(bk_wifi_scan_get_result(&scan_result)); scan_rst_ap_num = scan_result.ap_num; if (scan_rst_ap_num < 2) // beken scan result > = 1 { ChipLogProgress(NetworkProvisioning, "NULL AP\r\n"); GetInstance().mpScanCallback->OnFinished(Status::kNetworkNotFound, CharSpan(), nullptr); } else { ChipLogProgress(NetworkProvisioning, "AP num = %d\r\n", scan_rst_ap_num); BKScanResponseIterator iter(scan_rst_ap_num, &scan_result); GetInstance().mpScanCallback->OnFinished(Status::kSuccess, CharSpan(), &iter); } GetInstance().mpScanCallback = nullptr; bk_wifi_scan_free_result(&scan_result); } void BekenWiFiDriver::ScanNetworks(ByteSpan ssid, WiFiDriver::ScanCallback * callback) { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::ScanNetworks\r\n"); if (callback != nullptr) { mpScanCallback = callback; if (matter_scan_sema == NULL) { BK_LOG_ON_ERR(rtos_init_semaphore(&matter_scan_sema, 1)); } BK_LOG_ON_ERR(bk_event_register_cb(EVENT_MOD_WIFI, EVENT_WIFI_SCAN_DONE, scan_done_handler, NULL)); if (StartScanWiFiNetworks(ssid) != CHIP_NO_ERROR) { mpScanCallback = nullptr; callback->OnFinished(Status::kUnknownError, CharSpan(), nullptr); } BK_LOG_ON_ERR(rtos_get_semaphore(&matter_scan_sema, 4000)); // timeout 4000ms BK_LOG_ON_ERR(bk_event_unregister_cb(EVENT_MOD_WIFI, EVENT_WIFI_SCAN_DONE, scan_done_handler)); BK_LOG_ON_ERR(rtos_deinit_semaphore(&matter_scan_sema)); matter_scan_sema = NULL; OnScanWiFiNetworkDone(); } } size_t BekenWiFiDriver::WiFiNetworkIterator::Count() { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::WiFiNetworkIterator::Count\r\n"); return mDriver->mStagingNetwork.ssidLen == 0 ? 0 : 1; } bool BekenWiFiDriver::WiFiNetworkIterator::Next(Network & item) { ChipLogProgress(NetworkProvisioning, "BekenWiFiDriver::WiFiNetworkIterator::Next\r\n"); if (mExhausted || mDriver->mStagingNetwork.ssidLen == 0) { return false; } uint8_t length = strnlen(reinterpret_cast(mDriver->mStagingNetwork.ssid), DeviceLayer::Internal::kMaxWiFiSSIDLength); memcpy(item.networkID, mDriver->mStagingNetwork.ssid, length); item.networkIDLen = length; item.connected = false; mExhausted = true; Network connectedNetwork = { 0 }; CHIP_ERROR err = GetConnectedNetwork(connectedNetwork); if (err == CHIP_NO_ERROR) { if (connectedNetwork.networkIDLen == item.networkIDLen && memcmp(connectedNetwork.networkID, item.networkID, item.networkIDLen) == 0) { item.connected = true; } } return true; } } // namespace NetworkCommissioning } // namespace DeviceLayer } // namespace chip #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI