blob: f65c6ecb11617de72f308be41d84dbfaf6059b65 [file] [log] [blame]
/*
*
* 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 <platform/internal/CHIPDeviceLayerInternal.h>
#include <lib/core/ErrorStr.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>
#include <platform/ASR/ASRConfig.h>
#include <platform/ASR/ASRUtils.h>
#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<lega_wlan_security_e>(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,
min(strlen(reinterpret_cast<char *>(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<uint8_t>(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;
}