| /* |
| * |
| * Copyright (c) 2020-2022 Project CHIP Authors |
| * Copyright (c) 2020 Nest Labs, Inc. |
| * Copyright 2023-2024 NXP |
| * 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 "NetworkCommissioningDriver.h" |
| #include <lib/support/CodeUtils.h> |
| #include <lib/support/logging/CHIPLogging.h> |
| #include <platform/ConnectivityManager.h> |
| #include <platform/DiagnosticDataProvider.h> |
| #include <platform/internal/BLEManager.h> |
| |
| #include <platform/internal/GenericConnectivityManagerImpl_UDP.ipp> |
| |
| #if INET_CONFIG_ENABLE_TCP_ENDPOINT |
| #include <platform/internal/GenericConnectivityManagerImpl_TCP.ipp> |
| #endif |
| |
| #if CHIP_SYSTEM_CONFIG_USE_LWIP |
| #include <lwip/dns.h> |
| #include <lwip/ip_addr.h> |
| #include <lwip/nd6.h> |
| #include <lwip/netif.h> |
| #endif |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE |
| #include <platform/internal/GenericConnectivityManagerImpl_BLE.ipp> |
| #endif |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_WPA |
| |
| extern "C" { |
| #include "wlan.h" |
| #include "wm_net.h" |
| } |
| |
| #include <platform/internal/GenericConnectivityManagerImpl_WiFi.ipp> |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_THREAD |
| |
| #include <openthread/mdns.h> |
| |
| #include "border_agent.h" |
| #include "br_rtos_manager.h" |
| #include "infra_if.h" |
| #endif /* CHIP_DEVICE_CONFIG_ENABLE_THREAD */ |
| |
| #endif /* CHIP_DEVICE_CONFIG_ENABLE_WPA */ |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_THREAD |
| #include "ConnectivityManagerImpl.h" |
| #include <platform/internal/GenericConnectivityManagerImpl_Thread.ipp> |
| #endif /* CHIP_DEVICE_CONFIG_ENABLE_THREAD */ |
| |
| using namespace ::chip; |
| using namespace ::chip::Inet; |
| using namespace ::chip::System; |
| using namespace ::chip::DeviceLayer::Internal; |
| using namespace ::chip::DeviceLayer::DeviceEventType; |
| |
| // Table 9-50 "Status codes" of IEEE 802.11-2020: Unspecified failure |
| // Temporary default status code before SDK API to map wlan_event_reason to IEEE Status codes |
| #define WLAN_REFUSED_REASON_UNSPECIFIED 1 |
| |
| namespace chip { |
| namespace DeviceLayer { |
| |
| ConnectivityManagerImpl ConnectivityManagerImpl::sInstance; |
| #if CHIP_DEVICE_CONFIG_ENABLE_WPA |
| netif_ext_callback_t ConnectivityManagerImpl::sNetifCallback; |
| #endif /* CHIP_DEVICE_CONFIG_ENABLE_WPA */ |
| |
| CHIP_ERROR ConnectivityManagerImpl::_Init() |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| mWiFiStationMode = kWiFiStationMode_Disabled; |
| mWiFiStationState = kWiFiStationState_NotConnected; |
| mWiFiStationReconnectIntervalMS = CHIP_DEVICE_CONFIG_WIFI_STATION_RECONNECT_INTERVAL; |
| |
| // Initialize the generic base classes that require it. |
| #if CHIP_DEVICE_CONFIG_ENABLE_THREAD |
| GenericConnectivityManagerImpl_Thread<ConnectivityManagerImpl>::_Init(); |
| #endif |
| |
| 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_THREAD |
| GenericConnectivityManagerImpl_Thread<ConnectivityManagerImpl>::_OnPlatformEvent(event); |
| #endif |
| #if CHIP_DEVICE_CONFIG_ENABLE_WPA |
| if (event->Type == kPlatformNxpWlanEvent) |
| { |
| ProcessWlanEvent(event->Platform.WlanEventReason); |
| } |
| else if (event->Type == kPlatformNxpIpChangeEvent) |
| { |
| UpdateInternetConnectivityState(); |
| } |
| else if (event->Type == kPlatformNxpStartWlanConnectEvent) |
| { |
| bool is_wlan_added = false; |
| struct wlan_network searchedNetwork = { 0 }; |
| |
| /* If network was added before on a previous connection call or other API, do not add it again */ |
| if (wlan_get_network_byname(event->Platform.pNetworkDataEvent->name, &searchedNetwork) != WM_SUCCESS) |
| { |
| if (wlan_add_network(event->Platform.pNetworkDataEvent) == WM_SUCCESS) |
| { |
| ChipLogProgress(DeviceLayer, "Added WLAN \"%s\"", event->Platform.pNetworkDataEvent->name); |
| is_wlan_added = true; |
| } |
| } |
| else |
| { |
| /* In case network was added before, signal that it is added and that connection can start */ |
| is_wlan_added = true; |
| } |
| |
| /* At this point, the network details should be registered in the wlan driver */ |
| if (is_wlan_added == true) |
| { |
| _SetWiFiStationState(kWiFiStationState_Connecting); |
| ChipLogProgress(DeviceLayer, "WLAN connecting to network.name = \"%s\"", event->Platform.pNetworkDataEvent->name); |
| #if WIFI_DFS_OPTIMIZATION |
| /* Skip DFS (Dynamic Frequency Selection) channels during scan, DFS is used to avoid interferences */ |
| wlan_connect_opt(event->Platform.pNetworkDataEvent->name, true); |
| #else |
| wlan_connect(event->Platform.pNetworkDataEvent->name); |
| #endif |
| } |
| if (event->Platform.pNetworkDataEvent != NULL) |
| { |
| free(event->Platform.pNetworkDataEvent); |
| } |
| } |
| else if (event->Type == kPlatformNxpScanWiFiNetworkDoneEvent) |
| { |
| NetworkCommissioning::NXPWiFiDriver::GetInstance().ScanWiFINetworkDoneFromMatterTaskContext( |
| event->Platform.ScanWiFiNetworkCount); |
| } |
| else if (event->Type == kPlatformNxpStartWlanInitWaitTimerEvent) |
| { |
| DeviceLayer::SystemLayer().StartTimer(System::Clock::Milliseconds32(kWlanInitWaitMs), ConnectNetworkTimerHandler, |
| (void *) event->Platform.pNetworkDataEvent); |
| } |
| #endif |
| } |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_WPA |
| |
| ConnectivityManager::WiFiStationMode ConnectivityManagerImpl::_GetWiFiStationMode() |
| { |
| 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; |
| exit: |
| return err; |
| } |
| |
| void ConnectivityManagerImpl::_SetWiFiStationState(ConnectivityManager::WiFiStationState val) |
| { |
| if (mWiFiStationState != val) |
| { |
| ChipLogProgress(DeviceLayer, "WiFi station state change: %s -> %s", WiFiStationStateToStr(mWiFiStationState), |
| WiFiStationStateToStr(val)); |
| } |
| |
| mWiFiStationState = val; |
| } |
| |
| 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() |
| { |
| return (mWiFiStationState == kWiFiStationState_Connected); |
| } |
| |
| bool ConnectivityManagerImpl::_IsWiFiStationApplicationControlled() |
| { |
| return mWiFiStationMode == ConnectivityManager::kWiFiStationMode_ApplicationControlled; |
| } |
| |
| void ConnectivityManagerImpl::ProcessWlanEvent(enum wlan_event_reason wlanEvent) |
| { |
| WiFiDiagnosticsDelegate * delegate = GetDiagnosticDataProvider().GetWiFiDiagnosticsDelegate(); |
| uint8_t associationFailureCause = |
| chip::to_underlying(chip::app::Clusters::WiFiNetworkDiagnostics::AssociationFailureCauseEnum::kUnknown); |
| |
| #if CHIP_DETAIL_LOGGING |
| enum wlan_connection_state state; |
| int result; |
| |
| result = wlan_get_connection_state(&state); |
| if (result == WM_SUCCESS) |
| { |
| ChipLogDetail(DeviceLayer, "WLAN event: %d, WLAN connection state: %d", wlanEvent, state); |
| } |
| else |
| { |
| ChipLogDetail(DeviceLayer, "WLAN event: %d, WLAN connection state: unknown", wlanEvent); |
| } |
| #endif /* CHIP_DETAIL_LOGGING */ |
| |
| switch (wlanEvent) |
| { |
| case WLAN_REASON_SUCCESS: |
| ChipLogProgress(DeviceLayer, "Connected to WLAN network = %d", is_sta_ipv6_connected()); |
| if (sInstance._GetWiFiStationState() == kWiFiStationState_Connecting) |
| { |
| sInstance._SetWiFiStationState(kWiFiStationState_Connecting_Succeeded); |
| sInstance._SetWiFiStationState(kWiFiStationState_Connected); |
| NetworkCommissioning::NXPWiFiDriver::GetInstance().OnConnectWiFiNetwork(NetworkCommissioning::Status::kSuccess, |
| CharSpan(), wlanEvent); |
| sInstance.OnStationConnected(); |
| } |
| break; |
| |
| case WLAN_REASON_AUTH_SUCCESS: |
| ChipLogProgress(DeviceLayer, "Associated to WLAN network"); |
| break; |
| |
| case WLAN_REASON_CONNECT_FAILED: |
| ChipLogError(DeviceLayer, "WLAN (re)connect failed"); |
| sInstance._SetWiFiStationState(kWiFiStationState_NotConnected); |
| associationFailureCause = |
| chip::to_underlying(chip::app::Clusters::WiFiNetworkDiagnostics::AssociationFailureCauseEnum::kAssociationFailed); |
| if (delegate) |
| { |
| delegate->OnAssociationFailureDetected(associationFailureCause, WLAN_REFUSED_REASON_UNSPECIFIED); |
| } |
| UpdateInternetConnectivityState(); |
| break; |
| |
| case WLAN_REASON_NETWORK_NOT_FOUND: |
| ChipLogError(DeviceLayer, "WLAN network not found"); |
| NetworkCommissioning::NXPWiFiDriver::GetInstance().OnConnectWiFiNetwork(NetworkCommissioning::Status::kNetworkNotFound, |
| CharSpan(), wlanEvent); |
| associationFailureCause = |
| chip::to_underlying(chip::app::Clusters::WiFiNetworkDiagnostics::AssociationFailureCauseEnum::kSsidNotFound); |
| if (delegate) |
| { |
| delegate->OnAssociationFailureDetected(associationFailureCause, WLAN_REFUSED_REASON_UNSPECIFIED); |
| } |
| break; |
| |
| case WLAN_REASON_NETWORK_AUTH_FAILED: |
| ChipLogError(DeviceLayer, "Authentication to WLAN network failed"); |
| NetworkCommissioning::NXPWiFiDriver::GetInstance().OnConnectWiFiNetwork(NetworkCommissioning::Status::kAuthFailure, |
| CharSpan(), wlanEvent); |
| ChipLogError(DeviceLayer, "Authentication to WLAN network failed end"); |
| associationFailureCause = |
| chip::to_underlying(chip::app::Clusters::WiFiNetworkDiagnostics::AssociationFailureCauseEnum::kAuthenticationFailed); |
| if (delegate) |
| { |
| delegate->OnAssociationFailureDetected(associationFailureCause, WLAN_REFUSED_REASON_UNSPECIFIED); |
| } |
| break; |
| |
| case WLAN_REASON_LINK_LOST: |
| ChipLogError(DeviceLayer, "WLAN link lost"); |
| if (sInstance._GetWiFiStationState() == kWiFiStationState_Connected) |
| { |
| sInstance._SetWiFiStationState(kWiFiStationState_NotConnected); |
| sInstance.OnStationDisconnected(); |
| if (delegate) |
| { |
| delegate->OnAssociationFailureDetected(associationFailureCause, WLAN_REFUSED_REASON_UNSPECIFIED); |
| } |
| } |
| break; |
| |
| case WLAN_REASON_USER_DISCONNECT: |
| ChipLogProgress(DeviceLayer, "Disconnected from WLAN network"); |
| sInstance._SetWiFiStationState(kWiFiStationState_NotConnected); |
| sInstance.OnStationDisconnected(); |
| if (delegate) |
| { |
| delegate->OnAssociationFailureDetected(associationFailureCause, WLAN_REFUSED_REASON_UNSPECIFIED); |
| } |
| break; |
| |
| case WLAN_REASON_INITIALIZED: |
| sInstance._SetWiFiStationState(kWiFiStationState_NotConnected); |
| sInstance._SetWiFiStationMode(kWiFiStationMode_Enabled); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| int ConnectivityManagerImpl::_WlanEventCallback(enum wlan_event_reason wlanEvent, void * data) |
| { |
| ChipDeviceEvent event; |
| event.Type = DeviceEventType::kPlatformNxpWlanEvent; |
| event.Platform.WlanEventReason = wlanEvent; |
| (void) PlatformMgr().PostEvent(&event); |
| return 0; |
| } |
| |
| void ConnectivityManagerImpl::OnStationConnected() |
| { |
| ChipDeviceEvent event; |
| |
| event.Type = DeviceEventType::kWiFiConnectivityChange; |
| event.WiFiConnectivityChange.Result = kConnectivity_Established; |
| (void) PlatformMgr().PostEvent(&event); |
| |
| /* Update the connectivity state in case the connected event has been received after getting an IP addr */ |
| UpdateInternetConnectivityState(); |
| WiFiDiagnosticsDelegate * delegate = GetDiagnosticDataProvider().GetWiFiDiagnosticsDelegate(); |
| |
| if (delegate) |
| { |
| delegate->OnConnectionStatusChanged( |
| chip::to_underlying(chip::app::Clusters::WiFiNetworkDiagnostics::ConnectionStatusEnum::kConnected)); |
| } |
| } |
| |
| void ConnectivityManagerImpl::OnStationDisconnected() |
| { |
| ChipDeviceEvent event; |
| |
| event.Type = DeviceEventType::kWiFiConnectivityChange; |
| event.WiFiConnectivityChange.Result = kConnectivity_Lost; |
| (void) PlatformMgr().PostEvent(&event); |
| |
| WiFiDiagnosticsDelegate * delegate = GetDiagnosticDataProvider().GetWiFiDiagnosticsDelegate(); |
| |
| if (delegate) |
| { |
| delegate->OnConnectionStatusChanged( |
| chip::to_underlying(chip::app::Clusters::WiFiNetworkDiagnostics::ConnectionStatusEnum::kNotConnected)); |
| } |
| |
| /* Update the connectivity state in case the connected event has been received after getting an IP addr */ |
| UpdateInternetConnectivityState(); |
| } |
| |
| void ConnectivityManagerImpl::UpdateInternetConnectivityState() |
| { |
| bool haveIPv4Conn = false; |
| bool haveIPv6Conn = false; |
| const bool hadIPv4Conn = mFlags.Has(ConnectivityFlags::kHaveIPv4InternetConnectivity); |
| const bool hadIPv6Conn = mFlags.Has(ConnectivityFlags::kHaveIPv6InternetConnectivity); |
| const ip_addr_t * addr4; |
| const ip6_addr_t * addr6; |
| CHIP_ERROR err; |
| ChipDeviceEvent event; |
| |
| // If the WiFi station is currently in the connected state... |
| if (_IsWiFiStationConnected()) |
| { |
| // Get the LwIP netif for the WiFi station interface. |
| struct netif * netif = static_cast<struct netif *>(net_get_mlan_handle()); |
| |
| // If the WiFi station interface is up... |
| if ((netif != nullptr) && netif_is_up(netif) && netif_is_link_up(netif)) |
| { |
| #if INET_CONFIG_ENABLE_IPV4 |
| // Check if a DNS server is currently configured. If so... |
| ip_addr_t dnsServerAddr = *dns_getserver(0); |
| if (!ip_addr_isany_val(dnsServerAddr)) |
| { |
| // If the station interface has been assigned an IPv4 address, and has |
| // an IPv4 gateway, then presume that the device has IPv4 Internet |
| // connectivity. |
| if (!ip4_addr_isany_val(*netif_ip4_addr(netif)) && !ip4_addr_isany_val(*netif_ip4_gw(netif))) |
| { |
| haveIPv4Conn = true; |
| addr4 = &netif->ip_addr; |
| } |
| } |
| #endif |
| |
| // Search among the IPv6 addresses assigned to the interface for an |
| // address that is in the valid state. Search goes backwards because |
| // the link-local address is in the first slot and we prefer to report |
| // other than the link-local address value if there are multiple addresses. |
| for (int i = (LWIP_IPV6_NUM_ADDRESSES - 1); i >= 0; i--) |
| { |
| if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) |
| { |
| haveIPv6Conn = true; |
| addr6 = netif_ip6_addr(netif, i); |
| break; |
| } |
| } |
| } |
| } |
| |
| // Update the current state. |
| mFlags.Set(ConnectivityFlags::kHaveIPv4InternetConnectivity, haveIPv4Conn) |
| .Set(ConnectivityFlags::kHaveIPv6InternetConnectivity, haveIPv6Conn); |
| |
| if (haveIPv4Conn != hadIPv4Conn) |
| { |
| /* Check if the */ |
| event.Type = DeviceEventType::kInternetConnectivityChange; |
| event.InternetConnectivityChange.IPv4 = GetConnectivityChange(hadIPv4Conn, haveIPv4Conn); |
| event.InternetConnectivityChange.IPv6 = kConnectivity_NoChange; |
| if (haveIPv4Conn) |
| { |
| event.InternetConnectivityChange.ipAddress = IPAddress(*addr4); |
| } |
| err = PlatformMgr().PostEvent(&event); |
| VerifyOrDie(err == CHIP_NO_ERROR); |
| |
| ChipLogProgress(DeviceLayer, "%s Internet connectivity %s", "IPv4", (haveIPv4Conn) ? "ESTABLISHED" : "LOST"); |
| } |
| |
| if (haveIPv6Conn != hadIPv6Conn) |
| { |
| event.Type = DeviceEventType::kInternetConnectivityChange; |
| event.InternetConnectivityChange.IPv4 = kConnectivity_NoChange; |
| event.InternetConnectivityChange.IPv6 = GetConnectivityChange(hadIPv6Conn, haveIPv6Conn); |
| |
| #if CHIP_ENABLE_OPENTHREAD |
| // In case of boot, start the Border Router services including MDNS Server, otherwise inform of link state change |
| // The posted event will signal the application to restart the Matter mDNS server instance |
| bool bLinkState = event.InternetConnectivityChange.IPv6 == kConnectivity_Established ? true : false; |
| BrHandleStateChange(bLinkState); |
| #endif |
| if (haveIPv6Conn) |
| { |
| event.InternetConnectivityChange.ipAddress = IPAddress(*addr6); |
| } |
| err = PlatformMgr().PostEvent(&event); |
| VerifyOrDie(err == CHIP_NO_ERROR); |
| |
| ChipLogProgress(DeviceLayer, "%s Internet connectivity %s", "IPv6", (haveIPv6Conn) ? "ESTABLISHED" : "LOST"); |
| } |
| |
| #if CHIP_ENABLE_OPENTHREAD |
| if (haveIPv6Conn && UpdateIp6AddrList()) |
| { |
| UpdateMdnsHost(); |
| } |
| #endif |
| } |
| |
| void ConnectivityManagerImpl::_NetifExtCallback(struct netif * netif, netif_nsc_reason_t reason, |
| const netif_ext_callback_args_t * args) |
| { |
| struct netif * station_netif; |
| ChipDeviceEvent event; |
| |
| ChipLogDetail(DeviceLayer, "_NetifExtCallback: netif=%p, reason=0x%04x", netif, reason); |
| |
| station_netif = static_cast<struct netif *>(net_get_mlan_handle()); |
| if (netif == station_netif) |
| { |
| event.Type = DeviceEventType::kPlatformNxpIpChangeEvent; |
| (void) PlatformMgr().PostEvent(&event); |
| } |
| } |
| |
| void ConnectivityManagerImpl::StartWiFiManagement() |
| { |
| struct netif * netif = nullptr; |
| int32_t result; |
| |
| LOCK_TCPIP_CORE(); |
| netif = static_cast<struct netif *>(net_get_mlan_handle()); |
| if (netif != nullptr) |
| { |
| memset(&ConnectivityManagerImpl::sNetifCallback, 0, sizeof(ConnectivityManagerImpl::sNetifCallback)); |
| netif_add_ext_callback(&ConnectivityManagerImpl::sNetifCallback, &_NetifExtCallback); |
| } |
| UNLOCK_TCPIP_CORE(); |
| |
| result = wlan_start(_WlanEventCallback); |
| |
| if (result != WM_SUCCESS) |
| { |
| ChipLogError(DeviceLayer, "Failed to start WLAN Connection Manager"); |
| chipDie(); |
| } |
| } |
| #if CHIP_ENABLE_OPENTHREAD |
| void ConnectivityManagerImpl::BrHandleStateChange(bool bLinkState) |
| { |
| if (mBorderRouterInit == false) |
| { |
| if (bLinkState) |
| { |
| struct netif * extNetIfPtr = static_cast<struct netif *>(net_get_mlan_handle()); |
| struct netif * thrNetIfPtr = ThreadStackMgrImpl().ThreadNetIf(); |
| otInstance * thrInstancePtr; |
| |
| // Need to wait for the wifi to be connected because the mlan netif can be !=null but not initialized |
| // properly. If the thread netif is !=null it means that it was fully initialized |
| |
| // Lock OT task ? |
| if ((thrNetIfPtr) && (mWiFiStationState == kWiFiStationState_Connected)) |
| { |
| // Initalize internal interface variables, these can be used by other modules like the DNSSD Impl to |
| // get the underlying IP interface |
| Inet::InterfaceId tmpExtIf(extNetIfPtr); |
| Inet::InterfaceId tmpThrIf(thrNetIfPtr); |
| mExternalNetIf = tmpExtIf; |
| mThreadNetIf = tmpThrIf; |
| |
| mBorderRouterInit = true; |
| // Check if OT instance is init |
| thrInstancePtr = ThreadStackMgrImpl().OTInstance(); |
| |
| BrInitPlatform(thrInstancePtr, extNetIfPtr, thrNetIfPtr); |
| BrInitServices(); |
| |
| UpdateIp6AddrList(); |
| UpdateMdnsHost(); |
| BorderAgentInit(thrInstancePtr, mHostname); |
| } |
| } |
| } |
| else |
| { |
| InfraIfLinkState(bLinkState); |
| } |
| } |
| |
| void ConnectivityManagerImpl::UpdateMdnsHost() |
| { |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| otMdnsHost mdnsHost; |
| |
| if (strlen(mHostname) == 0) |
| { |
| uint8_t macBuffer[ConfigurationManager::kPrimaryMACAddressLength]; |
| MutableByteSpan mac(macBuffer); |
| err = DeviceLayer::ConfigurationMgr().GetPrimaryMACAddress(mac); |
| SuccessOrExit(err); |
| |
| chip::Dnssd::MakeHostName(mHostname, sizeof(mHostname), mac); |
| } |
| |
| mdnsHost.mAddresses = mIp6AddrList; |
| mdnsHost.mAddressesLength = mIp6AddrNum; |
| mdnsHost.mHostName = mHostname; |
| mdnsHost.mInfraIfIndex = netif_get_index(mExternalNetIf.GetPlatformInterface()); |
| |
| // Allways use ID 0 for host |
| otMdnsRegisterHost(ThreadStackMgrImpl().OTInstance(), &mdnsHost, 0, nullptr); |
| |
| exit: |
| return; |
| } |
| |
| bool ConnectivityManagerImpl::UpdateIp6AddrList() |
| { |
| const ip6_addr_t * addr6 = nullptr; |
| bool bAddrChange = false; |
| uint32_t newIp6AddrNum = 0; |
| struct netif * extNetIfPtr = mExternalNetIf.GetPlatformInterface(); |
| uint32_t lwipIterator, addrListIterator; |
| |
| for (lwipIterator = 0; lwipIterator < LWIP_IPV6_NUM_ADDRESSES; lwipIterator++) |
| { |
| if (ip6_addr_ispreferred(netif_ip6_addr_state(extNetIfPtr, lwipIterator)) && (mIp6AddrNum <= kMaxIp6Addr)) |
| { |
| addr6 = netif_ip6_addr(extNetIfPtr, lwipIterator); |
| for (addrListIterator = 0; addrListIterator < kMaxIp6Addr; addrListIterator++) |
| { |
| if (0 == memcmp(&mIp6AddrList[addrListIterator].mFields.m32, addr6->addr, sizeof(Inet::IPAddress))) |
| { |
| break; |
| } |
| } |
| if (addrListIterator == kMaxIp6Addr) |
| { |
| bAddrChange |= true; |
| } |
| memcpy(&mIp6AddrList[newIp6AddrNum++].mFields.m32, addr6->addr, sizeof(Inet::IPAddress)); |
| } |
| } |
| |
| bAddrChange |= (newIp6AddrNum != mIp6AddrNum) ? true : false; |
| mIp6AddrNum = newIp6AddrNum; |
| |
| return bAddrChange; |
| } |
| |
| Inet::InterfaceId ConnectivityManagerImpl::GetThreadInterface() |
| { |
| return sInstance.mThreadNetIf; |
| } |
| |
| Inet::InterfaceId ConnectivityManagerImpl::GetExternalInterface() |
| { |
| return sInstance.mExternalNetIf; |
| } |
| #endif // CHIP_ENABLE_OPENTHREAD |
| #endif // CHIP_DEVICE_CONFIG_ENABLE_WPA |
| |
| CHIP_ERROR ConnectivityManagerImpl::ProvisionWiFiNetwork(const char * ssid, uint8_t ssidLen, const char * key, uint8_t keyLen) |
| { |
| #if CHIP_DEVICE_CONFIG_ENABLE_WPA |
| CHIP_ERROR ret = CHIP_NO_ERROR; |
| struct wlan_network * pNetworkData = (struct wlan_network *) malloc(sizeof(struct wlan_network)); |
| |
| VerifyOrExit(pNetworkData != NULL, ret = CHIP_ERROR_NO_MEMORY); |
| VerifyOrExit(ssidLen <= IEEEtypes_SSID_SIZE, ret = CHIP_ERROR_INVALID_ARGUMENT); |
| VerifyOrExit(mWiFiStationState != kWiFiStationState_Connecting, ret = CHIP_ERROR_BUSY); |
| |
| // Need to enable the WIFI interface here when Thread is enabled as a secondary network interface. We don't want to enable |
| // WIFI from the init phase anymore and we will only do it in case the commissioner is provisioning the device with |
| // the WIFI credentials. |
| if (mWifiManagerInit == false) |
| { |
| StartWiFiManagement(); |
| mWifiManagerInit = true; |
| } |
| |
| memset(pNetworkData, 0, sizeof(struct wlan_network)); |
| |
| if (ssidLen < WLAN_NETWORK_NAME_MAX_LENGTH) |
| { |
| memcpy(pNetworkData->name, ssid, ssidLen); |
| pNetworkData->name[ssidLen] = '\0'; |
| } |
| else |
| { |
| memcpy(pNetworkData->name, ssid, WLAN_NETWORK_NAME_MAX_LENGTH); |
| pNetworkData->name[WLAN_NETWORK_NAME_MAX_LENGTH] = '\0'; |
| } |
| |
| memcpy(pNetworkData->ssid, ssid, ssidLen); |
| pNetworkData->ip.ipv4.addr_type = ADDR_TYPE_DHCP; |
| pNetworkData->ssid_specific = 1; |
| |
| pNetworkData->security.type = WLAN_SECURITY_NONE; |
| |
| if (keyLen > 0) |
| { |
| pNetworkData->security.type = WLAN_SECURITY_WILDCARD; |
| memcpy(pNetworkData->security.psk, key, keyLen); |
| pNetworkData->security.psk_len = keyLen; |
| } |
| |
| ConnectNetworkTimerHandler(NULL, (void *) pNetworkData); |
| |
| exit: |
| return ret; |
| #else |
| return CHIP_ERROR_NOT_IMPLEMENTED; |
| #endif |
| } |
| |
| #if CHIP_DEVICE_CONFIG_ENABLE_WPA |
| void ConnectivityManagerImpl::ConnectNetworkTimerHandler(::chip::System::Layer * aLayer, void * context) |
| { |
| ChipDeviceEvent event; |
| |
| /* |
| * Make sure to have the Wi-Fi station enabled before scheduling a connect event . |
| * Otherwise start a new timer to check again the status later. |
| */ |
| if (ConnectivityMgr().IsWiFiStationEnabled()) |
| { |
| /* Post an event to start the connection asynchronously in the Matter task context */ |
| event.Type = DeviceEventType::kPlatformNxpStartWlanConnectEvent; |
| event.Platform.pNetworkDataEvent = (struct wlan_network *) context; |
| (void) PlatformMgr().PostEvent(&event); |
| } |
| else |
| { |
| /* Post an event to start a delay timer asynchronously in the Matter task context */ |
| event.Type = DeviceEventType::kPlatformNxpStartWlanInitWaitTimerEvent; |
| event.Platform.pNetworkDataEvent = (struct wlan_network *) context; |
| (void) PlatformMgr().PostEvent(&event); |
| } |
| } |
| |
| /* Can be used to disconnect from WiFi network. |
| */ |
| CHIP_ERROR ConnectivityManagerImpl::_DisconnectNetwork(void) |
| { |
| int ret = 0; |
| CHIP_ERROR err = CHIP_NO_ERROR; |
| |
| if (ConnectivityMgrImpl().IsWiFiStationConnected()) |
| { |
| ChipLogProgress(NetworkProvisioning, "Disconnecting from WiFi network."); |
| |
| ret = wlan_disconnect(); |
| |
| if (ret != WM_SUCCESS) |
| { |
| ChipLogError(NetworkProvisioning, "Failed to disconnect from network with error: %u", (uint8_t) ret); |
| err = CHIP_ERROR_UNEXPECTED_EVENT; |
| } |
| } |
| else |
| { |
| ChipLogError(NetworkProvisioning, "Error: WiFi not connected!"); |
| err = CHIP_ERROR_INCORRECT_STATE; |
| } |
| |
| return err; |
| } |
| |
| #if CHIP_CONFIG_ENABLE_ICD_SERVER |
| CHIP_ERROR ConnectivityManagerImpl::_SetPollingInterval(System::Clock::Milliseconds32 pollingInterval) |
| { |
| /* |
| * ToDo: Call API to put device into sleep |
| */ |
| return CHIP_NO_ERROR; |
| } |
| #endif // CHIP_CONFIG_ENABLE_ICD_SERVER |
| #endif |
| |
| } // namespace DeviceLayer |
| } // namespace chip |