/* * * 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 #include #include #include #include #include #include #include #include #if INET_CONFIG_ENABLE_TCP_ENDPOINT #include #endif #include #include #include #include #include #include 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 #endif // NetworkCommission++ #include // NetworkCommission-- using namespace ::chip; using namespace ::chip::Inet; using namespace ::chip::System; 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(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(static_cast(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 * networkScanned = new std::vector(); 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 iter(const_cast *>(networkScanned)); mpScanCallback->OnFinished(Status::kSuccess, CharSpan(), &iter); mpScanCallback = nullptr; } delete const_cast *>(networkScanned); }); return 0; } } // namespace DeviceLayer } // namespace chip