blob: 802fe2708e3e26322938aceab21328f53e722e90 [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2020 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 <iomanip>
#include <platform/internal/CHIPDeviceLayerInternal.h>
#include <sstream>
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>
#include <platform/ConnectivityManager.h>
#include <platform/internal/GenericConnectivityManagerImpl_UDP.ipp>
#include <platform/nxp/mw320/ConnectivityManagerImpl.h>
#if INET_CONFIG_ENABLE_TCP_ENDPOINT
#include <platform/internal/GenericConnectivityManagerImpl_TCP.ipp>
#endif
#include <app/clusters/network-commissioning/network-commissioning.h>
#include <platform/nxp/mw320/NetworkCommissioningDriver.h>
#include <lwip/dns.h>
#include <lwip/ip_addr.h>
#include <lwip/nd6.h>
#include <lwip/netif.h>
extern "C" {
#include "wlan.h"
void test_wlan_scan(int argc, char ** argv);
void test_wlan_add(int argc, char ** argv);
static struct wlan_network sta_network;
}
#if CHIP_DEVICE_CONFIG_ENABLE_WPA
#include <platform/internal/GenericConnectivityManagerImpl_WiFi.ipp>
#endif
// NetworkCommission++
#include <platform/nxp/mw320/NetworkCommissioningDriver.h>
// NetworkCommission--
using namespace ::chip;
using namespace ::chip::Inet;
using namespace ::chip::System;
using namespace ::chip::TLV;
using namespace ::chip::DeviceLayer::Internal;
using namespace ::chip::app::Clusters::GeneralDiagnostics;
using namespace ::chip::app::Clusters::WiFiNetworkDiagnostics;
using namespace ::chip::app::Clusters::NetworkCommissioning;
using namespace ::chip::DeviceLayer::NetworkCommissioning;
// NetworkCommission++
namespace {
constexpr EndpointId kNetworkCommissioningEndpointMain = 0;
constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE;
#if (USE_ETHERNET_COMMISSION == 1)
DeviceLayer::NetworkCommissioning::Mw320EthernetDriver sEthernetDriver;
app::Clusters::NetworkCommissioning::Instance sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain,
&sEthernetDriver);
#else
Mw320WiFiDriver sWiFiDriver;
Instance sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain, &sWiFiDriver);
#endif // USE_ETHERNET_COMMISSION
} // namespace
// NetworkCommission--
namespace chip {
namespace DeviceLayer {
ConnectivityManagerImpl ConnectivityManagerImpl::sInstance;
uint8_t ConnectivityManagerImpl::sInterestedSSID[Internal::kMaxWiFiSSIDLength];
uint8_t ConnectivityManagerImpl::sInterestedSSIDLen;
// Configured SSID
uint8_t ConnectivityManagerImpl::sCfgSSID[Internal::kMaxWiFiSSIDLength];
uint8_t ConnectivityManagerImpl::sCfgSSIDLen;
NetworkCommissioning::WiFiDriver::ScanCallback * ConnectivityManagerImpl::mpScanCallback;
NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * ConnectivityManagerImpl::mpConnectCallback;
CHIP_ERROR ConnectivityManagerImpl::_Init()
{
CHIP_ERROR err = CHIP_NO_ERROR;
mpConnectCallback = nullptr;
mpScanCallback = nullptr;
mWiFiStationMode = kWiFiStationMode_Disabled;
mWiFiStationReconnectIntervalMS = CHIP_DEVICE_CONFIG_WIFI_STATION_RECONNECT_INTERVAL;
sWiFiNetworkCommissioningInstance.Init();
// Initialize the generic base classes that require it.
SuccessOrExit(err);
exit:
return err;
}
void ConnectivityManagerImpl::_OnPlatformEvent(const ChipDeviceEvent * event)
{
// Forward the event to the generic base classes as needed.
}
#if CHIP_DEVICE_CONFIG_ENABLE_WPA
ConnectivityManager::WiFiStationMode ConnectivityManagerImpl::_GetWiFiStationMode()
{
if (mWiFiStationMode != kWiFiStationMode_ApplicationControlled)
{
mWiFiStationMode =
kWiFiStationMode_Enabled; //(mWpaSupplicant.iface != nullptr) ? kWiFiStationMode_Enabled : kWiFiStationMode_Disabled;
}
return mWiFiStationMode;
}
CHIP_ERROR ConnectivityManagerImpl::_SetWiFiStationMode(ConnectivityManager::WiFiStationMode val)
{
CHIP_ERROR err = CHIP_NO_ERROR;
VerifyOrExit(val != ConnectivityManager::kWiFiStationMode_NotSupported, err = CHIP_ERROR_INVALID_ARGUMENT);
if (mWiFiStationMode != val)
{
ChipLogProgress(DeviceLayer, "WiFi station mode change: %s -> %s", WiFiStationModeToStr(mWiFiStationMode),
WiFiStationModeToStr(val));
}
mWiFiStationMode = val;
test_wlan_scan(0, NULL);
exit:
return err;
}
CHIP_ERROR ConnectivityManagerImpl::_SetWiFiAPMode(WiFiAPMode val)
{
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;
}
bool ConnectivityManagerImpl::_IsWiFiStationEnabled()
{
return GetWiFiStationMode() == kWiFiStationMode_Enabled;
}
bool ConnectivityManagerImpl::_IsWiFiStationConnected()
{
// ToDo: Change the status to response the WiFi status honestly
bool ret = true;
return ret;
}
bool ConnectivityManagerImpl::_IsWiFiStationApplicationControlled()
{
return mWiFiStationMode == ConnectivityManager::kWiFiStationMode_ApplicationControlled;
}
void ConnectivityManagerImpl::StartWiFiManagement() {}
CHIP_ERROR ConnectivityManagerImpl::CommitConfig()
{
ChipLogProgress(DeviceLayer, "[mw320] save config, connected network (ToDo)");
return CHIP_NO_ERROR;
}
CHIP_ERROR ConnectivityManagerImpl::GetWiFiBssId(MutableByteSpan & value)
{
constexpr size_t bssIdSize = 6;
VerifyOrReturnError(value.size() >= bssIdSize, CHIP_ERROR_BUFFER_TOO_SMALL);
int ret = wlan_get_current_network(&sta_network);
if (ret != WM_SUCCESS)
{
ChipLogProgress(DeviceLayer, "GetWiFiBssId failed: %d", ret);
return CHIP_ERROR_READ_FAILED;
}
memcpy(value.data(), sta_network.bssid, bssIdSize);
value.reduce_size(bssIdSize);
ChipLogProgress(DeviceLayer, "GetWiFiBssId: %02x:%02x:%02x:%02x:%02x:%02x", value.data()[0], value.data()[1], value.data()[2],
value.data()[3], value.data()[4], value.data()[5]);
return CHIP_NO_ERROR;
}
CHIP_ERROR ConnectivityManagerImpl::GetWiFiSecurityType(SecurityTypeEnum & securityType)
{
int ret = wlan_get_current_network(&sta_network);
if (ret != WM_SUCCESS)
{
// Set as no security by default
securityType = SecurityTypeEnum::kNone;
return CHIP_NO_ERROR;
}
switch (sta_network.security.type)
{
case WLAN_SECURITY_WEP_OPEN:
case WLAN_SECURITY_WEP_SHARED:
securityType = SecurityTypeEnum::kWep;
break;
case WLAN_SECURITY_WPA:
securityType = SecurityTypeEnum::kWpa;
break;
case WLAN_SECURITY_WPA2:
securityType = SecurityTypeEnum::kWpa2;
break;
case WLAN_SECURITY_WPA3_SAE:
securityType = SecurityTypeEnum::kWpa3;
break;
case WLAN_SECURITY_NONE:
default: // Default: No_security
securityType = SecurityTypeEnum::kNone;
}
ChipLogProgress(DeviceLayer, "GetWiFiSecurityType: %u", to_underlying(securityType));
return CHIP_NO_ERROR;
}
CHIP_ERROR ConnectivityManagerImpl::GetWiFiVersion(WiFiVersionEnum & wiFiVersion)
{
wiFiVersion = WiFiVersionEnum::kN;
ChipLogProgress(DeviceLayer, "GetWiFiVersion: %u", to_underlying(wiFiVersion));
return CHIP_NO_ERROR;
}
CHIP_ERROR ConnectivityManagerImpl::GetConfiguredNetwork(NetworkCommissioning::Network & network)
{
network.connected = true;
memcpy(network.networkID, sCfgSSID, sCfgSSIDLen);
network.networkIDLen = sCfgSSIDLen;
ChipLogDetail(DeviceLayer, "[mw320] Current connected network: (ToDo)");
return CHIP_NO_ERROR;
}
CHIP_ERROR ConnectivityManagerImpl::StartWiFiScan(ByteSpan ssid, NetworkCommissioning::WiFiDriver::ScanCallback * callback)
{
// There is another ongoing scan request, reject the new one.
// ====> Do it after scan is implemented (ToDo)
VerifyOrReturnError(mpScanCallback == nullptr, CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(ssid.size() <= sizeof(sInterestedSSID), CHIP_ERROR_INVALID_ARGUMENT);
CHIP_ERROR ret = CHIP_NO_ERROR;
memset(sInterestedSSID, 0, sizeof(sInterestedSSID));
memcpy(sInterestedSSID, ssid.data(), ssid.size());
sInterestedSSIDLen = ssid.size();
ChipLogProgress(DeviceLayer, "[mw320] initialized network scan. %u, [%s]", sInterestedSSIDLen, sInterestedSSID);
mpScanCallback = callback;
// Do Scan
if (wlan_scan(_OnWpaInterfaceScanDone))
{
ChipLogProgress(DeviceLayer, "Error: scan request failed");
}
else
{
ChipLogProgress(DeviceLayer, "Scan scheduled now...");
}
ChipLogProgress(DeviceLayer, "[mw320]: initialized network scan. ");
return ret;
}
void ConnectivityManagerImpl::UpdateNetworkStatus()
{
Network configuredNetwork;
VerifyOrReturn(IsWiFiStationEnabled() && mpStatusChangeCallback != nullptr);
CHIP_ERROR err = GetConfiguredNetwork(configuredNetwork);
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Failed to get configured network when updating network status: %s", err.AsString());
return;
}
// If we have already connected to the WiFi AP, then return null to indicate a success state.
if (IsWiFiStationConnected())
{
mpStatusChangeCallback->OnNetworkingStatusChange(
Status::kSuccess, MakeOptional(ByteSpan(configuredNetwork.networkID, configuredNetwork.networkIDLen)), NullOptional);
return;
}
mpStatusChangeCallback->OnNetworkingStatusChange(
Status::kUnknownError, MakeOptional(ByteSpan(configuredNetwork.networkID, configuredNetwork.networkIDLen)), NullOptional);
}
#endif // CHIP_DEVICE_CONFIG_ENABLE_WPA
CHIP_ERROR
ConnectivityManagerImpl::ConnectWiFiNetworkAsync(ByteSpan ssid, ByteSpan credentials,
NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * apCallback)
{
CHIP_ERROR ret = CHIP_NO_ERROR;
char ssidStr[kMaxWiFiSSIDLength + 1u] = { 0 };
char keyStr[kMaxWiFiKeyLength + 1u] = { 0 };
VerifyOrReturnError(ssid.size() <= kMaxWiFiSSIDLength, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(credentials.size() <= kMaxWiFiKeyLength, CHIP_ERROR_INVALID_ARGUMENT);
// There is another ongoing connect request, reject the new one.
VerifyOrReturnError(mpConnectCallback == nullptr, CHIP_ERROR_INCORRECT_STATE);
memcpy(ssidStr, ssid.data(), ssid.size());
memcpy(keyStr, credentials.data(), credentials.size());
//
memcpy(sCfgSSID, ssidStr, ssid.size());
sCfgSSIDLen = ssid.size();
//
mpConnectCallback = apCallback;
#if (MW320_CONNECT_SCAN_SYNC == 1)
if (mpConnectCallback != nullptr)
{
mpConnectCallback->OnResult(Status::kSuccess, CharSpan(), 0);
mpConnectCallback = nullptr;
}
#endif // MW320_CONNECT_SCAN_SYNC
return ret;
}
bool ConnectivityManagerImpl::_GetBssInfo(const uint8_t sid, NetworkCommissioning::WiFiScanResponse & result)
{
struct wlan_scan_result res;
int err;
err = wlan_get_scan_result(sid, &res);
if (err)
{
ChipLogProgress(DeviceLayer, "Error: can't get scan res %d", sid);
return false;
}
// => ssid
memset(result.ssid, 0, sizeof(result.ssid));
result.ssidLen = strlen(res.ssid);
memcpy(result.ssid, res.ssid, result.ssidLen);
// => bssid
memcpy(result.bssid, res.bssid, kWiFiBSSIDLength);
// => rssi
result.rssi = static_cast<int8_t>(0 - res.rssi);
// => band, mw320 only works in 2.4G
result.wiFiBand = app::Clusters::NetworkCommissioning::WiFiBandEnum::k2g4;
// => channel
result.channel = res.channel;
// => security
if (res.wep)
{
result.security.Set(WiFiSecurity::kWep);
}
else if (res.wpa)
{
result.security.Set(WiFiSecurity::kWpaPersonal);
}
else if ((res.wpa2) || (res.wpa2_entp))
{
result.security.Set(WiFiSecurity::kWpa2Personal);
}
else if (res.wpa3_sae)
{
result.security.Set(WiFiSecurity::kWpa3Personal);
}
else
{
result.security.Set(WiFiSecurity::kUnencrypted);
}
return true;
}
/*
Convert the ascii string to hex string with upper case
*/
std::string ConnectivityManagerImpl::to_hex_string(const std::string & input)
{
std::stringstream hex_stream;
std::string hex_upstr;
hex_stream << std::hex << std::internal << std::setfill('0');
for (auto & byte : input)
hex_stream << std::setw(2) << static_cast<int>(static_cast<unsigned char>(byte));
hex_upstr = hex_stream.str();
transform(hex_upstr.begin(), hex_upstr.end(), hex_upstr.begin(), [](unsigned char c) { return toupper(c); });
return hex_upstr;
}
int ConnectivityManagerImpl::_OnWpaInterfaceScanDone(unsigned int count)
{
ChipLogProgress(DeviceLayer, "network scan done (%d)", count);
// No ap reported
if (count == 0)
{
ChipLogProgress(DeviceLayer, "=> no network found");
DeviceLayer::SystemLayer().ScheduleLambda([]() {
if (mpScanCallback != nullptr)
{
mpScanCallback->OnFinished(Status::kSuccess, CharSpan(), nullptr);
mpScanCallback = nullptr;
}
});
return 0;
}
// Get the scan result from SDK and push to the list
std::vector<WiFiScanResponse> * networkScanned = new std::vector<WiFiScanResponse>();
for (uint8_t id = 0; id < count; id++)
{
WiFiScanResponse network;
if (_GetBssInfo(id, network))
{
std::string ascii_ssid((char *) (network.ssid));
std::string hex_ssid = to_hex_string(ascii_ssid);
if (sInterestedSSIDLen == 0)
{
networkScanned->push_back(network);
}
else if (network.ssidLen == sInterestedSSIDLen && memcmp(network.ssid, sInterestedSSID, sInterestedSSIDLen) == 0)
// else if ((network.ssidLen<<1) == sInterestedSSIDLen && memcmp(hex_ssid.c_str(), sInterestedSSID, sInterestedSSIDLen)
// == 0)
{
networkScanned->push_back(network);
}
}
}
DeviceLayer::SystemLayer().ScheduleLambda([networkScanned]() {
// Note: We cannot post a event in ScheduleLambda since std::vector is not trivial copiable. This results in the use of
// const_cast but should be fine for almost all cases, since we actually handled the ownership of this element to this
// lambda.
if (mpScanCallback != nullptr)
{
Mw320ScanResponseIterator<WiFiScanResponse> iter(const_cast<std::vector<WiFiScanResponse> *>(networkScanned));
mpScanCallback->OnFinished(Status::kSuccess, CharSpan(), &iter);
mpScanCallback = nullptr;
}
delete const_cast<std::vector<WiFiScanResponse> *>(networkScanned);
});
return 0;
}
} // namespace DeviceLayer
} // namespace chip