/* * * Copyright (c) 2021 Project CHIP Authors * 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. */ /* this file behaves like a config.h, comes first */ #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #include "lega_wlan_api.h" void lega_wlan_clear_pmk(void); #ifdef __cplusplus } #endif using namespace ::chip::DeviceLayer::Internal; using chip::DeviceLayer::Internal::DeviceNetworkInfo; namespace { constexpr uint8_t kWiFiMaxNetworks = 15; uint8_t NumAP = 0; lega_wlan_wifi_conf wifi_conf; lega_wlan_scan_ap_record_t scan_result[kWiFiMaxNetworks]; } // namespace #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP CHIP_ERROR ASRUtils::IsAPEnabled(bool & apEnabled) { if (lega_wlan_get_wifi_mode() == SOFTAP) { apEnabled = true; } else { apEnabled = false; } return CHIP_NO_ERROR; } #endif CHIP_ERROR ASRUtils::IsStationEnabled(bool & staEnabled) { if (lega_wlan_get_wifi_mode() == STA) { staEnabled = true; } else { staEnabled = false; } return CHIP_NO_ERROR; } bool ASRUtils::IsStationProvisioned(void) { lega_wlan_wifi_conf stationConfig; bool stationConnected; Internal::ASRUtils::IsStationConnected(stationConnected); return (asr_wifi_get_config(&stationConfig) == CHIP_NO_ERROR && stationConfig.ssid_len != 0) || stationConnected; } static bool is_sta_connected = false; CHIP_ERROR ASRUtils::IsStationConnected(bool & connected) { connected = is_sta_connected; return CHIP_NO_ERROR; } CHIP_ERROR ASRUtils::SetStationConnected(bool connected) { is_sta_connected = connected; return CHIP_NO_ERROR; } CHIP_ERROR ASRUtils::EnableStationMode(void) { int curmode = lega_wlan_get_wifi_mode(); if (curmode == STA) { ChipLogError(DeviceLayer, "EnableStationMode, STA already"); } else { ChipLogProgress(DeviceLayer, "Changing ASR WiFi mode to STA"); lega_wlan_init_type_t conf; memset(&conf, 0, sizeof(lega_wlan_init_type_t)); conf.wifi_mode = STA; conf.dhcp_mode = WLAN_DHCP_CLIENT; // before wlan open with sta mode, make sure the wlan is closed. lega_wlan_close(); if (lega_wlan_open(&conf) != 0) { ChipLogError(DeviceLayer, "lega_wlan_open() failed"); return CHIP_ERROR_INTERNAL; } } return CHIP_NO_ERROR; } CHIP_ERROR ASRUtils::GetWiFiSSID(char * buf, size_t bufSize) { size_t num = 0; return ASRConfig::ReadConfigValueStr(ASRConfig::kConfigKey_WiFiSSID, buf, bufSize, num); } CHIP_ERROR ASRUtils::StoreWiFiSSID(char * buf, size_t size) { return ASRConfig::WriteConfigValueStr(ASRConfig::kConfigKey_WiFiSSID, buf, size); } CHIP_ERROR ASRUtils::GetWiFiPassword(char * buf, size_t bufSize) { size_t num = 0; return ASRConfig::ReadConfigValueStr(ASRConfig::kConfigKey_WiFiPassword, buf, bufSize, num); } CHIP_ERROR ASRUtils::StoreWiFiPassword(char * buf, size_t size) { return ASRConfig::WriteConfigValueStr(ASRConfig::kConfigKey_WiFiPassword, buf, size); } CHIP_ERROR ASRUtils::GetWiFiSecurityCode(uint32_t & security) { return ASRConfig::ReadConfigValue(ASRConfig::kConfigKey_WiFiSecurity, security); } CHIP_ERROR ASRUtils::StoreWiFiSecurityCode(uint32_t security) { return ASRConfig::WriteConfigValue(ASRConfig::kConfigKey_WiFiSecurity, security); } CHIP_ERROR ASRUtils::wifi_get_mode(uint32_t & mode) { return ASRConfig::ReadConfigValue(ASRConfig::kConfigKey_WiFiMode, mode); } CHIP_ERROR ASRUtils::wifi_set_mode(uint32_t mode) { return ASRConfig::WriteConfigValue(ASRConfig::kConfigKey_WiFiMode, mode); } CHIP_ERROR ASRUtils::asr_wifi_set_config(lega_wlan_wifi_conf * conf) { CHIP_ERROR err = CHIP_NO_ERROR; /* Store Wi-Fi Configurations in Storage */ err = StoreWiFiSSID((char *) conf->wifi_ssid, conf->ssid_len + 1); SuccessOrExit(err); err = StoreWiFiPassword((char *) conf->wifi_key, conf->key_len + 1); SuccessOrExit(err); err = StoreWiFiSecurityCode(conf->security); SuccessOrExit(err); memcpy(&wifi_conf, conf, sizeof(lega_wlan_wifi_conf)); exit: return err; } CHIP_ERROR ASRUtils::asr_wifi_get_config(lega_wlan_wifi_conf * conf) { uint32_t code = 0; CHIP_ERROR err = CHIP_NO_ERROR; if (ASRConfig::ConfigValueExists(ASRConfig::kConfigKey_WiFiSSID) && ASRConfig::ConfigValueExists(ASRConfig::kConfigKey_WiFiPassword) && ASRConfig::ConfigValueExists(ASRConfig::kConfigKey_WiFiSecurity)) { /* Retrieve Wi-Fi Configurations from Storage */ err = GetWiFiSSID((char *) conf->wifi_ssid, sizeof(conf->wifi_ssid)); SuccessOrExit(err); err = GetWiFiPassword((char *) conf->wifi_key, sizeof(conf->wifi_key)); SuccessOrExit(err); err = GetWiFiSecurityCode(code); conf->ssid_len = strlen((char *) conf->wifi_ssid); conf->key_len = strlen((char *) conf->wifi_key); SuccessOrExit(err); conf->security = static_cast(code); } else { return CHIP_ERROR_KEY_NOT_FOUND; } exit: return err; } CHIP_ERROR ASRUtils::GetWiFiStationProvision(Internal::DeviceNetworkInfo & netInfo, bool includeCredentials) { CHIP_ERROR err = CHIP_NO_ERROR; lega_wlan_wifi_conf stationConfig; err = asr_wifi_get_config(&stationConfig); SuccessOrExit(err); ChipLogProgress(DeviceLayer, "GetWiFiStationProvision"); VerifyOrExit(strlen((const char *) stationConfig.wifi_ssid) != 0, err = CHIP_ERROR_INCORRECT_STATE); netInfo.NetworkId = kWiFiStationNetworkId; netInfo.FieldPresent.NetworkId = true; memcpy(netInfo.WiFiSSID, stationConfig.wifi_ssid, std::min(strlen(reinterpret_cast(stationConfig.wifi_ssid)) + 1, sizeof(netInfo.WiFiSSID))); // Enforce that netInfo wifiSSID is null terminated netInfo.WiFiSSID[kMaxWiFiSSIDLength] = '\0'; if (includeCredentials) { static_assert(sizeof(netInfo.WiFiKey) < 255, "Our min might not fit in netInfo.WiFiKeyLen"); netInfo.WiFiKeyLen = static_cast(std::min(strlen((char *) stationConfig.wifi_key), sizeof(netInfo.WiFiKey))); memcpy(netInfo.WiFiKey, stationConfig.wifi_key, netInfo.WiFiKeyLen); } exit: return err; } CHIP_ERROR ASRUtils::ClearWiFiStationProvision(void) { CHIP_ERROR err = CHIP_NO_ERROR; lega_wlan_wifi_conf stationConfig; ChipLogProgress(DeviceLayer, "ClearWiFiStationProvision"); // Clear the ASR WiFi station configuration. memset(&stationConfig, 0, sizeof(stationConfig)); ReturnLogErrorOnFailure(asr_wifi_set_config(&stationConfig)); return err; } CHIP_ERROR ASRUtils::asr_wifi_disconnect(void) { CHIP_ERROR err = CHIP_NO_ERROR; ChipLogProgress(DeviceLayer, "asr_wifi_disconnect"); if (lega_wlan_close() != 0) { ChipLogError(DeviceLayer, "asr_wifi_disconnect() failed"); err = CHIP_ERROR_INTERNAL; } return err; } CHIP_ERROR ASRUtils::asr_wifi_connect(void) { CHIP_ERROR err = CHIP_NO_ERROR; lega_wlan_wifi_conf stationConfig; lega_wlan_init_type_t conf; memset(&conf, 0, sizeof(lega_wlan_init_type_t)); conf.wifi_mode = STA; conf.dhcp_mode = WLAN_DHCP_CLIENT; asr_wifi_get_config(&stationConfig); strncpy((char *) conf.wifi_ssid, (char *) stationConfig.wifi_ssid, stationConfig.ssid_len); strncpy((char *) conf.wifi_key, (char *) stationConfig.wifi_key, stationConfig.key_len); conf.security = stationConfig.security; ChipLogProgress(DeviceLayer, "Connecting to AP : [%s]\r\n", StringOrNullMarker(conf.wifi_ssid)); lega_wlan_clear_pmk(); if (lega_wlan_open(&conf) != 0) { ChipLogError(DeviceLayer, "asr_wifi_connect() failed"); err = CHIP_ERROR_INTERNAL; } return err; } void ASRUtils::lega_wifi_scan_ind(lega_wlan_scan_result_t * result) { NumAP = 0; for (int i = 0; i < result->ap_num; i++) { if (i < kWiFiMaxNetworks) { memcpy(&scan_result[i], &result->ap_list[i], sizeof(lega_wlan_scan_ap_record_t)); NumAP++; } } NetworkCommissioning::ASRWiFiDriver::GetInstance().OnScanWiFiNetworkDone(); } CHIP_ERROR ASRUtils::StartScanWiFiNetworks(ByteSpan ssid) { if (Internal::ASRUtils::EnableStationMode() != CHIP_NO_ERROR) { ChipLogProgress(DeviceLayer, "Start Scan WiFi Networks Failed"); return CHIP_ERROR_INTERNAL; } NumAP = 0; memset(scan_result, 0, sizeof(scan_result)); lega_wlan_scan_compeleted_cb_register(Internal::ASRUtils::lega_wifi_scan_ind); if (!ssid.empty()) // ssid is given, only scan this network { char cSsid[DeviceLayer::Internal::kMaxWiFiSSIDLength] = {}; memcpy(cSsid, ssid.data(), ssid.size()); lega_wlan_start_scan_active(cSsid, 0); } else // scan all networks { lega_wlan_start_scan(); } return CHIP_NO_ERROR; } lega_wlan_scan_ap_record_t * ASRUtils::GetScanResults(void) { return scan_result; } uint8_t ASRUtils::GetScanApNum(void) { return NumAP; }