diff --git a/drivers/wifi/siwx91x/siwx91x_wifi.c b/drivers/wifi/siwx91x/siwx91x_wifi.c index 680030405a3..f99509f7700 100644 --- a/drivers/wifi/siwx91x/siwx91x_wifi.c +++ b/drivers/wifi/siwx91x/siwx91x_wifi.c @@ -34,6 +34,48 @@ enum { DEMAND_TWT = 2, }; +static int siwx91x_nwp_reboot_if_required(const struct device *dev, uint8_t oper_mode) +{ + struct siwx91x_dev *sidev = dev->data; + int ret; + + if (sidev->reboot_needed) { + ret = siwx91x_nwp_mode_switch(oper_mode, sidev->hidden_ssid, sidev->max_num_sta); + if (ret < 0) { + LOG_ERR("Failed to reboot the device: %d", ret); + return ret; + } + + sidev->reboot_needed = false; + } + + return 0; +} + +static int siwx91x_set_hidden_ssid(const struct device *dev, bool enable) +{ + struct siwx91x_dev *sidev = dev->data; + + if (sidev->hidden_ssid != enable) { + sidev->hidden_ssid = enable; + sidev->reboot_needed = true; + } + + return 0; +} + +static int siwx91x_set_max_sta(const struct device *dev, uint8_t max_sta) +{ + struct siwx91x_dev *sidev = dev->data; + + if (sidev->max_num_sta != max_sta) { + sidev->max_num_sta = max_sta; + sidev->reboot_needed = true; + } + + return 0; +} + static int siwx91x_sl_to_z_mode(sl_wifi_interface_t interface) { switch (interface) { @@ -319,6 +361,7 @@ static int siwx91x_ap_disable_if_required(const struct device *dev, { struct wifi_iface_status prev_params = { }; uint32_t prev_psk_length = WIFI_PSK_MAX_LEN; + struct siwx91x_dev *sidev = dev->data; uint8_t prev_psk[WIFI_PSK_MAX_LEN]; sl_net_credential_type_t psk_type; int ret; @@ -328,7 +371,7 @@ static int siwx91x_ap_disable_if_required(const struct device *dev, return ret; } - if (siwx91x_param_changed(&prev_params, new_params)) { + if (sidev->reboot_needed || siwx91x_param_changed(&prev_params, new_params)) { return siwx91x_ap_disable(dev); } @@ -392,7 +435,8 @@ static int siwx91x_ap_enable(const struct device *dev, struct wifi_connect_req_p struct siwx91x_dev *sidev = dev->data; /* Wiseconnect requires a valid PSK even if WIFI_SECURITY_TYPE_NONE is selected */ static const char dummy_psk[] = "dummy_value"; - sl_status_t ret; + sl_wifi_ap_configuration_t saved_ap_cfg; + int ret; int sec; sl_wifi_ap_configuration_t siwx91x_ap_cfg = { @@ -401,11 +445,11 @@ static int siwx91x_ap_enable(const struct device *dev, struct wifi_connect_req_p .rate_protocol = SL_WIFI_RATE_PROTOCOL_AUTO, .encryption = SL_WIFI_DEFAULT_ENCRYPTION, .channel.bandwidth = SL_WIFI_BANDWIDTH_20MHz, + .maximum_clients = sidev->max_num_sta, .tdi_flags = SL_WIFI_TDI_NONE, .client_idle_timeout = 0xFF, .beacon_interval = 100, .dtim_beacon_count = 3, - .maximum_clients = 4, .beacon_stop = 0, .options = 0, .is_11n_enabled = 1, @@ -416,6 +460,8 @@ static int siwx91x_ap_enable(const struct device *dev, struct wifi_connect_req_p return -EINVAL; } + /* Device hiddes both length and ssid at same time */ + siwx91x_set_hidden_ssid(dev, params->ignore_broadcast_ssid); if (sidev->state == WIFI_STATE_COMPLETED) { ret = siwx91x_ap_disable_if_required(dev, params); if (ret < 0) { @@ -458,9 +504,18 @@ static int siwx91x_ap_enable(const struct device *dev, struct wifi_connect_req_p return -EINVAL; } + ret = siwx91x_nwp_reboot_if_required(dev, WIFI_SOFTAP_MODE); + if (ret < 0) { + return ret; + } + + sli_get_saved_ap_configuration(&saved_ap_cfg); + if (saved_ap_cfg.client_idle_timeout != 0) { + siwx91x_ap_cfg.client_idle_timeout = saved_ap_cfg.client_idle_timeout; + } + siwx91x_ap_cfg.ssid.length = params->ssid_length; strncpy(siwx91x_ap_cfg.ssid.value, params->ssid, params->ssid_length); - if (params->mfp != WIFI_MFP_DISABLE) { LOG_WRN("Needed MFP disable but got MFP %s, hence setting to MFP disable", wifi_mfp_txt(params->mfp)); @@ -904,7 +959,7 @@ static int siwx91x_mode(const struct device *dev, struct wifi_mode_info *mode) mode->mode = cur_mode; } else if (mode->oper == WIFI_MGMT_SET) { if (cur_mode != mode->mode) { - ret = siwx91x_nwp_mode_switch(mode->mode); + ret = siwx91x_nwp_mode_switch(mode->mode, false, 0); if (ret < 0) { return ret; } @@ -915,6 +970,38 @@ static int siwx91x_mode(const struct device *dev, struct wifi_mode_info *mode) return 0; } +static int siwx91x_ap_config_params(const struct device *dev, struct wifi_ap_config_params *params) +{ + sl_wifi_interface_t interface = sl_wifi_get_default_interface(); + sl_wifi_ap_configuration_t siwx91x_ap_cfg; + + __ASSERT(params, "params cannot be NULL"); + + if (FIELD_GET(SIWX91X_INTERFACE_MASK, interface) != SL_WIFI_AP_INTERFACE) { + LOG_ERR("Wi-Fi not in AP mode"); + return -EINVAL; + } + + if ((params->type & WIFI_AP_CONFIG_PARAM_BANDWIDTH) && + params->bandwidth != WIFI_FREQ_BANDWIDTH_20MHZ) { + return -ENOTSUP; + } + + sli_get_saved_ap_configuration(&siwx91x_ap_cfg); + siwx91x_ap_cfg.channel.bandwidth = SL_WIFI_BANDWIDTH_20MHz; + if (params->type & WIFI_AP_CONFIG_PARAM_MAX_INACTIVITY) { + siwx91x_ap_cfg.client_idle_timeout = params->max_inactivity * 1000; + } + + if (params->type & WIFI_AP_CONFIG_PARAM_MAX_NUM_STA) { + siwx91x_set_max_sta(dev, params->max_num_sta); + } + + sli_save_ap_configuration(&siwx91x_ap_cfg); + + return 0; +} + #ifdef CONFIG_WIFI_SILABS_SIWX91X_NET_STACK_NATIVE static int siwx91x_send(const struct device *dev, struct net_pkt *pkt) @@ -1226,6 +1313,7 @@ static const struct wifi_mgmt_ops siwx91x_mgmt = { .iface_status = siwx91x_status, .mode = siwx91x_mode, .set_twt = siwx91x_set_twt, + .ap_config_params = siwx91x_ap_config_params, #if defined(CONFIG_NET_STATISTICS_WIFI) .get_stats = siwx91x_stats, #endif @@ -1242,7 +1330,9 @@ static const struct net_wifi_mgmt_offload siwx91x_api = { .wifi_mgmt_api = &siwx91x_mgmt, }; -static struct siwx91x_dev sidev; +static struct siwx91x_dev sidev = { + .max_num_sta = CONFIG_WIFI_MGMT_AP_MAX_NUM_STA, +}; #ifdef CONFIG_WIFI_SILABS_SIWX91X_NET_STACK_NATIVE ETH_NET_DEVICE_DT_INST_DEFINE(0, siwx91x_dev_init, NULL, &sidev, NULL, diff --git a/drivers/wifi/siwx91x/siwx91x_wifi.h b/drivers/wifi/siwx91x/siwx91x_wifi.h index 873da7564a0..d89c44a3d6c 100644 --- a/drivers/wifi/siwx91x/siwx91x_wifi.h +++ b/drivers/wifi/siwx91x/siwx91x_wifi.h @@ -21,6 +21,9 @@ struct siwx91x_dev { enum wifi_iface_state scan_prev_state; scan_result_cb_t scan_res_cb; uint16_t scan_max_bss_cnt; + uint8_t max_num_sta; + bool reboot_needed; + bool hidden_ssid; #ifdef CONFIG_WIFI_SILABS_SIWX91X_NET_STACK_OFFLOAD struct k_event fds_recv_event; diff --git a/soc/silabs/silabs_siwx91x/siwg917/nwp.c b/soc/silabs/silabs_siwx91x/siwg917/nwp.c index e620140e3fd..4ad30bce802 100644 --- a/soc/silabs/silabs_siwx91x/siwg917/nwp.c +++ b/soc/silabs/silabs_siwx91x/siwg917/nwp.c @@ -20,13 +20,16 @@ #include "rsi_ble_common_config.h" #endif +#define AP_MAX_NUM_STA 4 + LOG_MODULE_REGISTER(siwx91x_nwp); BUILD_ASSERT(DT_REG_SIZE(DT_CHOSEN(zephyr_sram)) == KB(195) || DT_REG_SIZE(DT_CHOSEN(zephyr_sram)) == KB(255) || DT_REG_SIZE(DT_CHOSEN(zephyr_sram)) == KB(319)); -int siwx91x_get_nwp_config(sl_wifi_device_configuration_t *get_config, uint8_t wifi_oper_mode) +int siwx91x_get_nwp_config(sl_wifi_device_configuration_t *get_config, uint8_t wifi_oper_mode, + bool hidden_ssid, uint8_t max_num_sta) { sl_wifi_device_configuration_t default_config = { .band = SL_SI91X_WIFI_BAND_2_4GHZ, @@ -48,6 +51,13 @@ int siwx91x_get_nwp_config(sl_wifi_device_configuration_t *get_config, uint8_t w sl_si91x_boot_configuration_t *boot_config = &default_config.boot_config; __ASSERT(get_config, "get_config cannot be NULL"); + __ASSERT((hidden_ssid == true || max_num_sta != 0) && wifi_oper_mode != WIFI_SOFTAP_MODE, + "hidden_ssid or max_num_sta requires SOFTAP mode"); + + if (wifi_oper_mode == WIFI_SOFTAP_MODE && max_num_sta > AP_MAX_NUM_STA) { + LOG_ERR("Exceeded maximum supported stations (%d)", AP_MAX_NUM_STA); + return -EINVAL; + } /* The size does not match exactly because 1 KB is reserved at the start of the RAM */ if (DT_REG_SIZE(DT_CHOSEN(zephyr_sram)) == KB(195)) { @@ -110,6 +120,15 @@ int siwx91x_get_nwp_config(sl_wifi_device_configuration_t *get_config, uint8_t w } else if (wifi_oper_mode == WIFI_SOFTAP_MODE) { boot_config->oper_mode = SL_SI91X_ACCESS_POINT_MODE; boot_config->coex_mode = SL_SI91X_WLAN_ONLY_MODE; + boot_config->custom_feature_bit_map |= SL_SI91X_CUSTOM_FEAT_LIMIT_PACKETS_PER_STA; + + if (hidden_ssid) { + boot_config->custom_feature_bit_map |= + SL_SI91X_CUSTOM_FEAT_AP_IN_HIDDEN_MODE; + } + + boot_config->custom_feature_bit_map |= + SL_WIFI_CUSTOM_FEAT_MAX_NUM_OF_CLIENTS(max_num_sta); if (IS_ENABLED(CONFIG_BT_SILABS_SIWX91X)) { LOG_WRN("Bluetooth is not supported in AP mode"); @@ -166,12 +185,12 @@ int siwx91x_get_nwp_config(sl_wifi_device_configuration_t *get_config, uint8_t w return 0; } -int siwx91x_nwp_mode_switch(uint8_t oper_mode) +int siwx91x_nwp_mode_switch(uint8_t oper_mode, bool hidden_ssid, uint8_t max_num_sta) { sl_wifi_device_configuration_t nwp_config; int status; - status = siwx91x_get_nwp_config(&nwp_config, oper_mode); + status = siwx91x_get_nwp_config(&nwp_config, oper_mode, hidden_ssid, max_num_sta); if (status < 0) { return status; } @@ -195,7 +214,7 @@ static int siwg917_nwp_init(void) sl_wifi_device_configuration_t network_config; sl_status_t status; - siwx91x_get_nwp_config(&network_config, WIFI_STA_MODE); + siwx91x_get_nwp_config(&network_config, WIFI_STA_MODE, false, 0); /* TODO: If sl_net_*_profile() functions will be needed for WiFi then call * sl_net_set_profile() here. Currently these are unused. */ diff --git a/soc/silabs/silabs_siwx91x/siwg917/nwp.h b/soc/silabs/silabs_siwx91x/siwg917/nwp.h index a75a2f07e05..978d7c44ec2 100644 --- a/soc/silabs/silabs_siwx91x/siwg917/nwp.h +++ b/soc/silabs/silabs_siwx91x/siwg917/nwp.h @@ -17,9 +17,11 @@ * of the NWP to apply the new mode along with the updated features. * * @param[in] oper_mode Wi-Fi operating mode to switch to. + * @param[in] hidden_ssid SSID and its length (used only in WIFI_AP_MODE). + * @param[in] max_num_sta Maximum number of supported stations (only for WIFI_AP_MODE). * * @return 0 on success, negative error code on failure. */ -int siwx91x_nwp_mode_switch(uint8_t oper_mode); +int siwx91x_nwp_mode_switch(uint8_t oper_mode, bool hidden_ssid, uint8_t max_num_sta); #endif