diff --git a/drivers/wifi/siwx917/siwx917_wifi.c b/drivers/wifi/siwx917/siwx917_wifi.c index edd80698..4261c188 100644 --- a/drivers/wifi/siwx917/siwx917_wifi.c +++ b/drivers/wifi/siwx917/siwx917_wifi.c @@ -17,11 +17,28 @@ #include "sl_wifi_callback_framework.h" #include "sl_wifi.h" #include "sl_net.h" +#include "sl_net_default_values.h" LOG_MODULE_REGISTER(siwx917_wifi); NET_BUF_POOL_FIXED_DEFINE(siwx917_tx_pool, 1, _NET_ETH_MAX_FRAME_SIZE, 0, NULL); +static inline int siwx917_bandwidth(enum wifi_frequency_bandwidths bandwidth) +{ + + switch (bandwidth) { + case WIFI_FREQ_BANDWIDTH_20MHZ: + return SL_WIFI_BANDWIDTH_20MHz; + case WIFI_FREQ_BANDWIDTH_40MHZ: + return SL_WIFI_BANDWIDTH_40MHz; + case WIFI_FREQ_BANDWIDTH_80MHZ: + return SL_WIFI_BANDWIDTH_80MHz; + default: + LOG_ERR("Invalid bandwidth"); + return -EAGAIN; + } +} + static unsigned int siwx917_on_join(sl_wifi_event_t event, char *result, uint32_t result_size, void *arg) { @@ -281,13 +298,78 @@ static int siwx917_scan(const struct device *dev, struct wifi_scan_params *z_sca static int siwx917_status(const struct device *dev, struct wifi_iface_status *status) { struct siwx917_dev *sidev = dev->data; + sl_si91x_rsp_wireless_info_t wlan_info = { }; + int ret; int32_t rssi = -1; + __ASSERT(status, "status cannot be NULL"); + memset(status, 0, sizeof(*status)); status->state = sidev->state; - sl_wifi_get_signal_strength(SL_WIFI_CLIENT_INTERFACE, &rssi); - status->rssi = rssi; - return 0; + + ret = sl_wifi_get_wireless_info(&wlan_info); + if (ret) { + LOG_ERR("Failed to get the wireless info: 0x%x", ret); + return -EIO; + } + + strncpy(status->ssid, wlan_info.ssid, WIFI_SSID_MAX_LEN); + status->ssid_len = strlen(status->ssid); + memcpy(status->bssid, wlan_info.mac_address, WIFI_MAC_ADDR_LEN); + status->mfp = WIFI_MFP_REQUIRED; + + if (FIELD_GET(SL_WIFI_2_4GHZ_INTERFACE, sidev->interface)) { + status->band = WIFI_FREQ_BAND_2_4_GHZ; + } + + if (FIELD_GET(SL_WIFI_CLIENT_INTERFACE, sidev->interface)) { + sl_wifi_listen_interval_t listen_interval = { }; + + status->link_mode = WIFI_LINK_MODE_UNKNOWN; + status->iface_mode = WIFI_MODE_INFRA; + status->channel = wlan_info.channel_number; + sl_wifi_get_signal_strength(SL_WIFI_CLIENT_INTERFACE, &rssi); + status->rssi = rssi; + + sl_wifi_get_listen_interval(SL_WIFI_CLIENT_INTERFACE, &listen_interval); + status->beacon_interval = listen_interval.listen_interval; + } else if (FIELD_GET(SL_WIFI_AP_INTERFACE, sidev->interface)) { + sl_wifi_ap_configuration_t conf = { }; + + ret = sl_wifi_get_ap_configuration(SL_WIFI_AP_INTERFACE, &conf); + if (ret) { + LOG_ERR("Failed to get the AP configuration: 0x%x", ret); + return -EINVAL; + } + + status->link_mode = WIFI_4; + status->iface_mode = WIFI_MODE_AP; + status->channel = conf.channel.channel; + status->beacon_interval = conf.beacon_interval; + status->dtim_period = conf.dtim_beacon_count; + } else { + status->link_mode = WIFI_LINK_MODE_UNKNOWN; + status->iface_mode = WIFI_MODE_UNKNOWN; + status->channel = 0; + + return -EINVAL; + } + + switch (wlan_info.sec_type) { + case SL_WIFI_OPEN: + status->security = WIFI_SECURITY_TYPE_NONE; + break; + case SL_WIFI_WPA2: + status->security = WIFI_SECURITY_TYPE_PSK; + break; + case SL_WIFI_WPA3: + status->security = WIFI_SECURITY_TYPE_SAE; + break; + default: + status->security = WIFI_SECURITY_TYPE_UNKNOWN; + } + + return ret; } #ifdef CONFIG_WIFI_SIWX917_NET_STACK_NATIVE @@ -367,6 +449,195 @@ static void siwx917_ethernet_init(struct net_if *iface) } } +static int siwx917_ap_enable(const struct device *dev, struct wifi_connect_req_params *params) +{ + struct siwx917_dev *sidev = dev->data; + int ret; + + sl_wifi_ap_configuration_t configuration = { + .encryption = SL_WIFI_DEFAULT_ENCRYPTION, + .credential_id = SL_NET_DEFAULT_WIFI_AP_CREDENTIAL_ID, + .rate_protocol = SL_WIFI_RATE_PROTOCOL_AUTO, + .options = 0, + .keepalive_type = SL_SI91X_AP_NULL_BASED_KEEP_ALIVE, + .beacon_interval = 100, + .client_idle_timeout = 0xFF, + .dtim_beacon_count = 3, + .maximum_clients = 4, + .beacon_stop = 0, + .tdi_flags = SL_WIFI_TDI_NONE, + .is_11n_enabled = 1, + .ssid.length = params->ssid_length, + }; + + if (params->band != WIFI_FREQ_BAND_UNKNOWN && params->band != WIFI_FREQ_BAND_2_4_GHZ) { + return -ENOTSUP; + } + + if (params->channel == WIFI_CHANNEL_ANY) { + configuration.channel.channel = SL_WIFI_AUTO_CHANNEL; + } else { + configuration.channel.channel = params->channel; + } + + if (siwx917_bandwidth(params->bandwidth) < 0 ) { + return -EINVAL; + } + + configuration.channel.bandwidth = siwx917_bandwidth(params->bandwidth); + strncpy(configuration.ssid.value, params->ssid, params->ssid_length); + + switch (params->security) { + case WIFI_SECURITY_TYPE_NONE: + configuration.security = SL_WIFI_OPEN; + sl_net_set_credential(configuration.credential_id, + default_wifi_ap_credential.type, + (const void *)default_wifi_ap_credential.data, + default_wifi_ap_credential.data_length); + break; + + case WIFI_SECURITY_TYPE_PSK: + configuration.security = SL_WIFI_WPA2; + break; + + case WIFI_SECURITY_TYPE_PSK_SHA256: + configuration.security = SL_WIFI_WPA2; + if (params->mfp != WIFI_MFP_REQUIRED) { + LOG_ERR("MFP required"); + return -EINVAL; + } + + sl_si91x_set_join_configuration(SL_WIFI_AP_INTERFACE, + SL_SI91X_JOIN_FEAT_MFP_CAPABLE_REQUIRED); + break; + + case WIFI_SECURITY_TYPE_SAE: + configuration.security = SL_WIFI_WPA3; + break; + + default: + LOG_ERR("Unsupported security type"); + return -EINVAL; + } + + if (params->security != WIFI_SECURITY_TYPE_NONE) { + ret = sl_net_set_credential(configuration.credential_id, + SL_NET_WIFI_PSK, params->psk, + params->psk_length); + if (ret) { + LOG_ERR("Failed to set credentials: 0x%x", ret); + return -EINVAL; + } + } + + ret = sl_wifi_start_ap(SL_WIFI_AP_2_4GHZ_INTERFACE, &configuration); + if (ret) { + LOG_ERR("Failed to enable AP mode: 0x%x", ret); + return -EIO; + } + + sidev->state = WIFI_STATE_COMPLETED; + return ret; +} + +static int siwx917_ap_disable(const struct device *dev) +{ + struct siwx917_dev *sidev = dev->data; + int ret; + + ret = sl_wifi_stop_ap(SL_WIFI_AP_2_4GHZ_INTERFACE); + if (ret) { + LOG_ERR("Failed to disable Wi-Fi AP mode: 0x%x", ret); + return -EIO; + } + + sidev->state = WIFI_STATE_INTERFACE_DISABLED; + return ret; +} + +static int siwx917_ap_sta_disconnect(const struct device *dev, const uint8_t *mac_addr) +{ + struct siwx917_dev *sidev = dev->data; + sl_mac_address_t mac = { }; + int ret; + + __ASSERT(mac_addr, "mac_addr cannot be NULL"); + + memcpy(mac.octet, mac_addr, ARRAY_SIZE(mac.octet)); + + ret = sl_wifi_disconnect_ap_client(sidev->interface, &mac, SL_WIFI_DEAUTH); + if (ret) { + LOG_ERR("Failed to disconnect: 0x%x", ret); + return -EIO; + } + + return ret; +} + +static sl_status_t siwx917_on_connect(sl_wifi_event_t event, void *data, + uint32_t data_length, void *arg) +{ + ARG_UNUSED(event); + struct siwx917_dev *sidev = arg; + struct wifi_ap_sta_info sta_info = { }; + + __ASSERT(data, "data cannot be NULL"); + __ASSERT(arg, "arg cannot be NULL"); + + strncpy(sta_info.mac, (uint8_t *)data, data_length); + sta_info.mac_length = data_length; + sta_info.link_mode = WIFI_LINK_MODE_UNKNOWN; + + wifi_mgmt_raise_ap_sta_connected_event(sidev->iface, &sta_info); + + return SL_STATUS_OK; +} + +static sl_status_t siwx917_on_disconnect(sl_wifi_event_t event, void *data, + uint32_t data_length, void *arg) +{ + ARG_UNUSED(event); + struct siwx917_dev *sidev = arg; + struct wifi_ap_sta_info sta_info = { }; + + __ASSERT(data, "data cannot be NULL"); + __ASSERT(arg, "arg cannot be NULL"); + + memcpy(sta_info.mac, (uint8_t *)data, data_length); + sta_info.mac_length = data_length; + wifi_mgmt_raise_ap_sta_disconnected_event(sidev->iface, &sta_info); + + return SL_STATUS_OK; +} + +#if defined(CONFIG_NET_STATISTICS_WIFI) +static int siwx917_stats(const struct device *dev, struct net_stats_wifi *stats) +{ + struct siwx917_dev *sidev = dev->data; + sl_wifi_statistics_t statistics = { }; + int ret; + + __ASSERT(stats, "stats cannot be NULL"); + + ret = sl_wifi_get_statistics(FIELD_GET(SIWX917_INTERFACE_MASK, sidev->interface), + &statistics); + if (ret) { + LOG_ERR("Failed to get stat: 0x%x", ret); + return -EINVAL; + } + + stats->multicast.rx = statistics.mcast_rx_count; + stats->multicast.tx = statistics.mcast_tx_count; + stats->unicast.rx = statistics.ucast_rx_count; + stats->unicast.tx = statistics.ucast_tx_count; + stats->sta_mgmt.beacons_rx = statistics.beacon_rx_count; + stats->sta_mgmt.beacons_miss = statistics.beacon_lost_count; + stats->overrun_count = statistics.overrun_count; + + return ret; +} +#endif + static void siwx917_iface_init(struct net_if *iface) { struct siwx917_dev *sidev = iface->if_dev->dev->data; @@ -377,12 +648,18 @@ static void siwx917_iface_init(struct net_if *iface) sl_wifi_set_scan_callback(siwx917_on_scan, sidev); sl_wifi_set_join_callback(siwx917_on_join, sidev); + sl_wifi_set_callback(SL_WIFI_CLIENT_CONNECTED_EVENTS, siwx917_on_connect, sidev); + sl_wifi_set_callback(SL_WIFI_CLIENT_DISCONNECTED_EVENTS, siwx917_on_disconnect, + sidev); - status = sl_wifi_get_mac_address(SL_WIFI_CLIENT_INTERFACE, &sidev->macaddr); + sidev->interface = sl_wifi_get_default_interface(); + status = sl_wifi_get_mac_address(FIELD_GET(SIWX917_INTERFACE_MASK, sidev->interface), + &sidev->macaddr); if (status) { LOG_ERR("sl_wifi_get_mac_address(): %#04x", status); return; } + net_if_set_link_addr(iface, sidev->macaddr.octet, sizeof(sidev->macaddr.octet), NET_LINK_ETHERNET); siwx917_sock_init(iface); @@ -400,7 +677,13 @@ static const struct wifi_mgmt_ops siwx917_mgmt = { .scan = siwx917_scan, .connect = siwx917_connect, .disconnect = siwx917_disconnect, + .ap_enable = siwx917_ap_enable, + .ap_disable = siwx917_ap_disable, + .ap_sta_disconnect = siwx917_ap_sta_disconnect, .iface_status = siwx917_status, +#if defined(CONFIG_NET_STATISTICS_WIFI) + .get_stats = siwx917_stats, +#endif }; static const struct net_wifi_mgmt_offload siwx917_api = { diff --git a/drivers/wifi/siwx917/siwx917_wifi.h b/drivers/wifi/siwx917/siwx917_wifi.h index 06243fac..169f37e0 100644 --- a/drivers/wifi/siwx917/siwx917_wifi.h +++ b/drivers/wifi/siwx917/siwx917_wifi.h @@ -14,9 +14,12 @@ #include "sl_si91x_socket_types.h" #include "sl_si91x_protocol_types.h" +#define SIWX917_INTERFACE_MASK (0x03) + struct siwx917_dev { struct net_if *iface; sl_mac_address_t macaddr; + sl_wifi_interface_t interface; enum wifi_iface_state state; scan_result_cb_t scan_res_cb; uint16_t scan_max_bss_cnt;