blob: eed494cffda2933b4daff71650659eaef6eb27fa [file] [log] [blame]
/*
*
* Copyright (c) 2022 Project CHIP Authors
*
* 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.
*/
#pragma once
#include <app-common/zap-generated/cluster-enums.h>
#include <app/icd/server/ICDServerConfig.h>
#include <array>
#include <cmsis_os2.h>
#include <lib/support/BitFlags.h>
#include <lib/support/Span.h>
#include <platform/silabs/wifi/WifiStateProvider.h>
#include <platform/silabs/wifi/icd/PowerSaveInterface.h>
#include <platform/silabs/wifi/wfx_msgs.h>
#include <sl_cmsis_os2_common.h>
#include <sl_status.h>
#if (SLI_SI91X_MCU_INTERFACE | EXP_BOARD)
#include "rsi_common_apis.h"
#include "sl_si91x_types.h"
#include "sl_wifi_constants.h"
#include "sl_wifi_device.h"
#endif // (SLI_SI91X_MCU_INTERFACE | EXP_BOARD)
/* Updated constants */
constexpr size_t kWifiMacAddressLength = 6;
/* Defines to update */
// TODO: Not sure why the pass key max length differs for the 917 SoC & NCP
#if (SLI_SI91X_MCU_INTERFACE | EXP_BOARD)
// MAX PASSKEY LENGTH including NULL character
#define WFX_MAX_PASSKEY_LENGTH (SL_WIFI_MAX_PSK_LENGTH)
#else
// MAX PASSKEY LENGTH including NULL character
#define WFX_MAX_PASSKEY_LENGTH (64)
#endif // (SLI_SI91X_MCU_INTERFACE | EXP_BOARD)
// MAX SSID LENGTH excluding NULL character
#define WFX_MAX_SSID_LENGTH (32)
#define MAX_JOIN_RETRIES_COUNT (5)
/* Note that these are same as RSI_security */
typedef enum
{
WFX_SEC_UNSPECIFIED = 0,
WFX_SEC_NONE = 1,
WFX_SEC_WEP = 2,
WFX_SEC_WPA = 3,
WFX_SEC_WPA2 = 4,
WFX_SEC_WPA3 = 5,
WFX_SEC_WPA_WPA2_MIXED = 6,
} wfx_sec_t;
typedef struct wfx_wifi_scan_result
{
uint8_t ssid[WFX_MAX_SSID_LENGTH]; // excludes null-character
size_t ssid_length;
wfx_sec_t security;
uint8_t bssid[kWifiMacAddressLength];
uint8_t chan;
int16_t rssi; /* I suspect this is in dBm - so signed */
chip::app::Clusters::NetworkCommissioning::WiFiBandEnum wiFiBand;
} wfx_wifi_scan_result_t;
using ScanCallback = void (*)(wfx_wifi_scan_result_t *);
typedef struct wfx_wifi_scan_ext
{
uint32_t beacon_lost_count;
uint32_t beacon_rx_count;
uint32_t mcast_rx_count;
uint32_t mcast_tx_count;
uint32_t ucast_rx_count;
uint32_t ucast_tx_count;
uint32_t overrun_count;
} wfx_wifi_scan_ext_t;
#ifdef RS911X_WIFI
/*
* This Sh%t is here to support WFXUtils - and the Matter stuff that uses it
* We took it from the SDK (for WF200)
*/
typedef enum
{
SL_WFX_STA_INTERFACE = 0, ///< Interface 0, linked to the station
SL_WFX_SOFTAP_INTERFACE = 1, ///< Interface 1, linked to the softap
} sl_wfx_interface_t;
#endif
/* Updated section */
namespace chip {
namespace DeviceLayer {
namespace Silabs {
/**
* @brief Public Interface for the Wi-Fi platform APIs
*
*/
class WifiInterface : public WifiStateProvider, public PowerSaveInterface
{
public:
enum class WifiEvent : uint8_t
{
kStartUp = 0,
kConnect = 1,
kDisconnect = 2,
kScanComplete = 3,
kGotIPv4 = 4,
kGotIPv6 = 5,
kLostIP = 6,
};
enum class WifiState : uint16_t
{
kStationInit = (1 << 0),
kAPReady = (1 << 1),
kStationProvisioned = (1 << 2),
kStationConnecting = (1 << 3),
kStationConnected = (1 << 4),
kStationDhcpDone = (1 << 6), /* Requested to do DHCP after conn */
kStationMode = (1 << 7), /* Enable Station Mode */
kAPMode = (1 << 8), /* Enable AP Mode */
kStationReady = (kStationConnected | kStationDhcpDone),
kStationStarted = (1 << 9),
kScanStarted = (1 << 10), /* Scan Started */
};
enum class WifiDisconnectionReasons : uint16_t // using uint16 to match current structure during the transition
{
kUnknownError = 1, // Disconnation due to an internal error
kAccessPointLost = 2, // Device did not receive AP beacon too many times
kAccessPoint = 3, // AP disconnected the device
kApplication = 4, // Application requested disconnection
kWPACouterMeasures = 5, // WPA contermeasures triggered a disconnection
};
// TODO: Figure out if we need this structure. We have different strcutures for the same use
struct WifiCredentials
{
WifiCredentials() { Clear(); }
uint8_t ssid[WFX_MAX_SSID_LENGTH] = { 0 };
size_t ssidLength = 0;
uint8_t passkey[WFX_MAX_PASSKEY_LENGTH] = { 0 };
size_t passkeyLength = 0;
wfx_sec_t security = WFX_SEC_UNSPECIFIED;
WifiCredentials & operator=(const WifiCredentials & other)
{
if (this != &other)
{
memcpy(ssid, other.ssid, WFX_MAX_SSID_LENGTH);
ssidLength = other.ssidLength;
memcpy(passkey, other.passkey, WFX_MAX_PASSKEY_LENGTH);
passkeyLength = other.passkeyLength;
security = other.security;
}
return *this;
}
void Clear()
{
memset(ssid, 0, WFX_MAX_SSID_LENGTH);
ssidLength = 0;
memset(passkey, 0, WFX_MAX_PASSKEY_LENGTH);
passkeyLength = 0;
security = WFX_SEC_UNSPECIFIED;
}
};
using MacAddress = std::array<uint8_t, kWifiMacAddressLength>;
virtual ~WifiInterface() = default;
/**
* @brief Returns the singleton instance of the WiFi interface
*
* @note This function needs to be implemented in the child classes sources file
*
* @return WifiInterface&
*/
static WifiInterface & GetInstance();
/**
* @brief Function initalizes the WiFi module before starting the WiFi task.
*
* @return CHIP_ERROR CHIP_NO_ERROR, if the initialization succeeded
* CHIP_ERROR_INTERNAL, if sequence failed due to internal API error
* CHIP_ERROR_NO_MEMORY, if sequence failed due to unavaliablility of memory
*/
virtual CHIP_ERROR InitWiFiStack(void) = 0;
/**
* @brief Returns the provide interfaces MAC address
* Valid buffer large enough for the MAC address must be provided to the function
*
* @param[in] interface SL_WFX_STA_INTERFACE or SL_WFX_SOFTAP_INTERFACE.
* If soft AP is not enabled, the interface is ignored and the function always returns the Station MAC
* address
* @param[out] addr Interface MAC addres
*
* @return CHIP_ERROR CHIP_NO_ERROR on success
* CHIP_ERROR_BUFFER_TOO_SMALL if the provided ByteSpan size is too small
*
*/
virtual CHIP_ERROR GetMacAddress(sl_wfx_interface_t interface, chip::MutableByteSpan & addr) = 0;
/**
* @brief Triggers a network scan
* The function is asynchronous and the result is provided via the callback.
*
* @param ssid The SSID to scan for. If empty, all networks are scanned
* @param callback The callback to be called when the scan is complete. Cannot be nullptr.
* The callback is called asynchrounously.
*
* @return CHIP_ERROR CHIP_NO_ERROR if the network scan was successfully started
* CHIP_INVALID_ARGUMENT if the callback is nullptr
* CHIP_ERROR_IN_PROGRESS, if there is already a network scan in progress
* CHIP_ERROR_INVALID_STRING_LENGTH, if there SSID length exceeds handled limit
* other, if there is a platform error when starting the scan
*/
virtual CHIP_ERROR StartNetworkScan(chip::ByteSpan ssid, ScanCallback callback) = 0;
/**
* @brief Creates and starts the WiFi task that processes Wifi events and operations
*
* @return CHIP_ERROR CHIP_NO_ERROR if the task was successfully started and initialized
* CHIP_ERROR_NO_MEMORY if the task failed to be created
* CHIP_ERROR_INTERNAL if software or hardware initialization failed
*/
virtual CHIP_ERROR StartWifiTask() = 0;
/**
* @brief Configures the Wi-Fi devices as a Wi-Fi station
*/
virtual void ConfigureStationMode() = 0;
/**
* @brief Triggers the device to disconnect from the connected Wi-Fi network
*
* @note The disconnection is not immediate. It can take a certain amount of time for the device to be in a disconnected state
* once the function is called. When the function returns, the device might not have yet disconnected from the Wi-Fi network.
*
* @return CHIP_ERROR CHIP_NO_ERROR, disconnection request was succesfully triggered
* otherwise, CHIP_ERROR_INTERNAL
*/
virtual CHIP_ERROR TriggerDisconnection() = 0;
/**
* @brief Gets the connected access point information.
* See @wfx_wifi_scan_result_t for the information that is returned by the function.
*
* @param[out] info AP information
*
* @return CHIP_ERROR CHIP_NO_ERROR, device has succesfully pulled all the AP information
* CHIP_ERROR_INTERNAL, otherwise. If the function returns an error, the data in ap cannot be used.
*/
virtual CHIP_ERROR GetAccessPointInfo(wfx_wifi_scan_result_t & info) = 0;
/**
* @brief Gets the connected access point extended information.
* See @wfx_wifi_scan_ext_t for the information that is returned by the information
*
* @param[out] info AP extended information
*
* @return CHIP_ERROR CHIP_NO_ERROR, device has succesfully pulled all the AP information
* CHIP_ERROR_INTERNAL, otherwise. If the function returns an error, the data in ap cannot be used.
*/
virtual CHIP_ERROR GetAccessPointExtendedInfo(wfx_wifi_scan_ext_t & info) = 0;
/**
* @brief Function resets the BeaconLostCount, BeaconRxCount, PacketMulticastRxCount, PacketMulticastTxCount,
* PacketUnicastRxCount, PacketUnicastTxCount back to 0
*
* @return CHIP_ERROR CHIP_NO_ERROR, the counters were succesfully reset to 0.
* CHIP_ERROR_INTERNAL, if there was an error when resetting the counter values
*/
virtual CHIP_ERROR ResetCounters() = 0;
/**
* @brief Clears the stored Wi-Fi crendetials stored in RAM only
*/
virtual void ClearWifiCredentials() = 0;
/**
* @brief Stores the Wi-Fi credentials
*
* @note Function does not validate if the device already has Wi-Fi credentials.
* It is the responsibility of the caller to ensuret that.
* The function will overwrite any existing Wi-Fi credentials.
*
* @param[in] credentials
*/
virtual void SetWifiCredentials(const WifiCredentials & credentials) = 0;
/**
* @brief Returns the configured Wi-Fi credentials
*
* @param[out] credentials stored wifi crendetials
*
* @return CHIP_ERROR CHIP_ERROR_INCORRECT_STATE, if the device does not have any set credentials
* CHIP_NO_ERROR, otherwise
*/
virtual CHIP_ERROR GetWifiCredentials(WifiCredentials & credentials) = 0;
/**
* @brief Triggers a connection attempt the Access Point who's crendetials match the ones store with the SetWifiCredentials API.
* The function triggers an async connection attempt. The upper layers are notified trought a platform event if the
* connection attempt was successful or not.
*
* The returned error code only indicates if the connection attempt was triggered or not.
*
* @return CHIP_ERROR CHIP_NO_ERROR, the connection attempt was succesfully triggered
* CHIP_ERROR_INCORRECT_STATE, the Wi-Fi station does not have any Wi-Fi credentials
* CHIP_ERROR_INVALID_ARGUMENT, the provisionned crendetials do not match the Wi-Fi station requirements
* CHIP_ERROR_INTERNAL, otherwise
*/
virtual CHIP_ERROR ConnectToAccessPoint(void) = 0;
/**
* @brief Cancels the on-going network scan operation.
* If one isn't in-progress, function doesn't do anything
*/
virtual void CancelScanNetworks() = 0;
/**
* @brief Provide all the frequency bands supported by the Wi-Fi interface.
*
* The default implementation returns the 2.4 GHz band support.
*
* @return a bitmask of supported Wi-Fi bands where each bit is associated with a WiFiBandEnum value.
*/
virtual uint32_t GetSupportedWiFiBandsMask() const
{
// Default to 2.4G support only
return static_cast<uint32_t>(1UL << chip::to_underlying(chip::app::Clusters::NetworkCommissioning::WiFiBandEnum::k2g4));
}
/**
* @brief Function resets reconnection attempt interval back to the minimum value
*/
void ResetConnectionRetryInterval();
protected:
/**
* @brief Function notifies the PlatformManager that an IPv6 event occured on the WiFi interface.
*
* @param gotIPv6Addr true, got an IPv6 address
* false, lost or wasn't able to get an IPv6 address
*/
void NotifyIPv6Change(bool gotIPv6Addr);
#if CHIP_DEVICE_CONFIG_ENABLE_IPV4
/**
* @brief Updates the IPv4 address in the Wi-Fi interface and notifies the application layer about the new IP address.
*
* @param[in] ip New IPv4 address
*/
void GotIPv4Address(uint32_t ip);
/**
* @brief Function notifies the PlatformManager that an IPv4 event occured on the WiFi interface.
*
* @param gotIPv4Addr true, got an IPv4 address
* false, lost or wasn't able to get an IPv4 address
*/
void NotifyIPv4Change(bool gotIPv4Addr);
#endif /* CHIP_DEVICE_CONFIG_ENABLE_IPV4 */
/**
* @brief Function notifies the PlatformManager that a disconnection event occurred
*
* @param reason reason for the disconnection
*/
void NotifyDisconnection(WifiDisconnectionReasons reason);
/**
* @brief Function notifies the PlatformManager that a connection event occurred
*
* @param[in] ap pointer to the structure that contains the MAC address of the AP
*/
void NotifyConnection(const MacAddress & ap);
/**
* @brief Function resets the IP notification states
*
*/
void ResetIPNotificationStates();
/**
* @brief Notifies upper-layers that Wi-Fi initialization has succesfully completed
*/
void NotifyWifiTaskInitialized(void);
/**
* @brief Function schedules a reconnection attempt with the Access Point
*
* @note The retry interval increases exponentially with each attempt, starting from a minimum value and doubling each time,
* up to a maximum value. For example, if the initial retry interval is 1 second, the subsequent intervals will be 2
* seconds, 4 seconds, 8 seconds, and so on, until the maximum retry interval is reached.
*/
void ScheduleConnectionAttempt();
bool mHasNotifiedIPv6 = false;
#if CHIP_DEVICE_CONFIG_ENABLE_IPV4
bool mHasNotifiedIPv4 = false;
#endif // CHIP_DEVICE_CONFIG_ENABLE_IPV4
private:
osTimerId_t mRetryTimer;
};
} // namespace Silabs
} // namespace DeviceLayer
} // namespace chip
// TODO: This structure can be split into members of the interfaces
// This needs to be after the class definition since it depends on class members
typedef struct wfx_rsi_s
{
chip::BitFlags<chip::DeviceLayer::Silabs::WifiInterface::WifiState> dev_state;
uint16_t ap_chan; /* The chan our STA is using */
chip::DeviceLayer::Silabs::WifiInterface::WifiCredentials credentials;
ScanCallback scan_cb;
uint8_t * scan_ssid; /* Which one are we scanning for */
size_t scan_ssid_length;
#ifdef SL_WFX_CONFIG_SOFTAP
chip::DeviceLayer::Silabs::WifiInterface::MacAddress softap_mac;
#endif
chip::DeviceLayer::Silabs::WifiInterface::MacAddress sta_mac;
chip::DeviceLayer::Silabs::WifiInterface::MacAddress ap_mac; /* To which our STA is connected */
chip::DeviceLayer::Silabs::WifiInterface::MacAddress ap_bssid; /* To which our STA is connected */
uint8_t ip4_addr[4]; /* Not sure if this is enough */
} WfxRsi_t;