diff --git a/drivers/wifi/nrf_wifi/inc/fmac_main.h b/drivers/wifi/nrf_wifi/inc/fmac_main.h index 23f96089eb63..c5ae4f66d459 100644 --- a/drivers/wifi/nrf_wifi/inc/fmac_main.h +++ b/drivers/wifi/nrf_wifi/inc/fmac_main.h @@ -88,6 +88,7 @@ struct nrf_wifi_vif_ctx_zep { struct k_work_delayable nrf_wifi_rpu_recovery_bringup_work; #endif /* CONFIG_NRF_WIFI_RPU_RECOVERY */ int rts_threshold_value; + unsigned short bss_max_idle_period; }; struct nrf_wifi_vif_ctx_map { diff --git a/drivers/wifi/nrf_wifi/inc/wifi_mgmt.h b/drivers/wifi/nrf_wifi/inc/wifi_mgmt.h index e2aa91caa483..8efa96da6a72 100644 --- a/drivers/wifi/nrf_wifi/inc/wifi_mgmt.h +++ b/drivers/wifi/nrf_wifi/inc/wifi_mgmt.h @@ -75,4 +75,7 @@ int nrf_wifi_set_rts_threshold(const struct device *dev, int nrf_wifi_get_rts_threshold(const struct device *dev, unsigned int *rts_threshold); + +int nrf_wifi_set_bss_max_idle_period(const struct device *dev, + unsigned short bss_max_idle_period); #endif /* __ZEPHYR_WIFI_MGMT_H__ */ diff --git a/drivers/wifi/nrf_wifi/src/fmac_main.c b/drivers/wifi/nrf_wifi/src/fmac_main.c index 72055fb02993..1ea3964bc66d 100644 --- a/drivers/wifi/nrf_wifi/src/fmac_main.c +++ b/drivers/wifi/nrf_wifi/src/fmac_main.c @@ -840,6 +840,9 @@ static int nrf_wifi_drv_main_zep(const struct device *dev) #endif /* CONFIG_NRF70_RADIO_TEST */ k_mutex_init(&rpu_drv_priv_zep.rpu_ctx_zep.rpu_lock); +#ifndef CONFIG_NRF70_RADIO_TEST + vif_ctx_zep->bss_max_idle_period = USHRT_MAX; +#endif /* !CONFIG_NRF70_RADIO_TEST */ return 0; #ifdef CONFIG_NRF70_RADIO_TEST fmac_deinit: @@ -865,6 +868,7 @@ static const struct wifi_mgmt_ops nrf_wifi_mgmt_ops = { .get_power_save_config = nrf_wifi_get_power_save_config, .set_rts_threshold = nrf_wifi_set_rts_threshold, .get_rts_threshold = nrf_wifi_get_rts_threshold, + .set_bss_max_idle_period = nrf_wifi_set_bss_max_idle_period, #endif #ifdef CONFIG_NRF70_SYSTEM_WITH_RAW_MODES .mode = nrf_wifi_mode, diff --git a/drivers/wifi/nrf_wifi/src/wifi_mgmt.c b/drivers/wifi/nrf_wifi/src/wifi_mgmt.c index 875ce786b570..c9b932578307 100644 --- a/drivers/wifi/nrf_wifi/src/wifi_mgmt.c +++ b/drivers/wifi/nrf_wifi/src/wifi_mgmt.c @@ -1080,3 +1080,56 @@ int nrf_wifi_get_rts_threshold(const struct device *dev, return ret; } + +int nrf_wifi_set_bss_max_idle_period(const struct device *dev, + unsigned short bss_max_idle_period) +{ + struct nrf_wifi_ctx_zep *rpu_ctx_zep = NULL; + struct nrf_wifi_vif_ctx_zep *vif_ctx_zep = NULL; + int ret = -1; + + if (!dev) { + LOG_ERR("%s: dev is NULL", __func__); + return ret; + } + + vif_ctx_zep = dev->data; + + if (!vif_ctx_zep) { + LOG_ERR("%s: vif_ctx_zep is NULL", __func__); + return ret; + } + + rpu_ctx_zep = vif_ctx_zep->rpu_ctx_zep; + + if (!rpu_ctx_zep) { + LOG_ERR("%s: rpu_ctx_zep is NULL", __func__); + return ret; + } + + + if (!rpu_ctx_zep->rpu_ctx) { + LOG_ERR("%s: RPU context not initialized", __func__); + return ret; + } + + if (((int)bss_max_idle_period < 0) || + (bss_max_idle_period > 64000)) { + /* 0 or value less than 64000 is passed to f/w. + * All other values considered as invalid. + */ + LOG_ERR("%s: Invalid max_idle_period value : %d", + __func__, (int)bss_max_idle_period); + return ret; + } + + k_mutex_lock(&vif_ctx_zep->vif_lock, K_FOREVER); + + vif_ctx_zep->bss_max_idle_period = bss_max_idle_period; + + ret = 0; + + k_mutex_unlock(&vif_ctx_zep->vif_lock); + + return ret; +} diff --git a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c index d06f0792fa28..54349e8ae00c 100644 --- a/drivers/wifi/nrf_wifi/src/wpa_supp_if.c +++ b/drivers/wifi/nrf_wifi/src/wpa_supp_if.c @@ -931,8 +931,10 @@ int nrf_wifi_wpa_supp_associate(void *if_priv, struct wpa_driver_associate_param assoc_info.use_mfp = NRF_WIFI_MFP_REQUIRED; } - if (params->bss_max_idle_period) { - assoc_info.bss_max_idle_time = params->bss_max_idle_period; + if (vif_ctx_zep->bss_max_idle_period == USHRT_MAX) { + assoc_info.bss_max_idle_time = CONFIG_WIFI_MGMT_BSS_MAX_IDLE_TIME; + } else { + assoc_info.bss_max_idle_time = vif_ctx_zep->bss_max_idle_period; } status = nrf_wifi_sys_fmac_assoc(rpu_ctx_zep->rpu_ctx, vif_ctx_zep->vif_idx, &assoc_info); diff --git a/include/zephyr/net/wifi_mgmt.h b/include/zephyr/net/wifi_mgmt.h index 40dd023839a7..a3ede63c8d80 100644 --- a/include/zephyr/net/wifi_mgmt.h +++ b/include/zephyr/net/wifi_mgmt.h @@ -133,6 +133,8 @@ enum net_request_wifi_cmd { NET_REQUEST_WIFI_CMD_CANDIDATE_SCAN, /** AP WPS config */ NET_REQUEST_WIFI_CMD_AP_WPS_CONFIG, + /** Configure BSS maximum idle period */ + NET_REQUEST_WIFI_CMD_BSS_MAX_IDLE_PERIOD, /** @cond INTERNAL_HIDDEN */ NET_REQUEST_WIFI_CMD_MAX /** @endcond */ @@ -317,6 +319,11 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_START_ROAMING); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_NEIGHBOR_REP_COMPLETE); +#define NET_REQUEST_WIFI_BSS_MAX_IDLE_PERIOD \ + (NET_WIFI_BASE | NET_REQUEST_WIFI_CMD_BSS_MAX_IDLE_PERIOD) + +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_WIFI_BSS_MAX_IDLE_PERIOD); + /** @cond INTERNAL_HIDDEN */ enum { @@ -1598,6 +1605,15 @@ struct wifi_mgmt_ops { * @return 0 if ok, < 0 if error */ int (*start_11r_roaming)(const struct device *dev); + /** Set BSS max idle period + * + * @param dev Pointer to the device structure for the driver instance. + * @param BSS max idle period value + * + * @return 0 if ok, < 0 if error + */ + int (*set_bss_max_idle_period)(const struct device *dev, + unsigned short bss_max_idle_period); }; /** Wi-Fi management offload API */ diff --git a/modules/hostap/src/supp_api.c b/modules/hostap/src/supp_api.c index 4f82068385cd..b3a28f5a9351 100644 --- a/modules/hostap/src/supp_api.c +++ b/modules/hostap/src/supp_api.c @@ -1772,6 +1772,19 @@ int supplicant_legacy_roam(const struct device *dev) return ret; } +int supplicant_set_bss_max_idle_period(const struct device *dev, + unsigned short bss_max_idle_period) +{ + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_mgmt_api(dev); + + if (!wifi_mgmt_api || !wifi_mgmt_api->set_bss_max_idle_period) { + wpa_printf(MSG_ERROR, "set_bss_max_idle_period is not supported"); + return -ENOTSUP; + } + + return wifi_mgmt_api->set_bss_max_idle_period(dev, bss_max_idle_period); +} + #ifdef CONFIG_WIFI_NM_WPA_SUPPLICANT_WNM int supplicant_btm_query(const struct device *dev, uint8_t reason) { diff --git a/modules/hostap/src/supp_api.h b/modules/hostap/src/supp_api.h index ddd3c3d66988..9d2b90b50fe0 100644 --- a/modules/hostap/src/supp_api.h +++ b/modules/hostap/src/supp_api.h @@ -305,6 +305,14 @@ int supplicant_get_wifi_conn_params(const struct device *dev, */ int supplicant_wps_config(const struct device *dev, struct wifi_wps_config_params *params); +/** @ Set Wi-Fi max idle period + * + * @param dev Wi-Fi interface handle to use + * @param bss_max_idle_period Maximum idle period to set + * @return 0 for OK; -1 for ERROR + */ +int supplicant_set_bss_max_idle_period(const struct device *dev, + unsigned short bss_max_idle_period); #ifdef CONFIG_AP int set_ap_bandwidth(const struct device *dev, enum wifi_frequency_bandwidths bandwidth); diff --git a/modules/hostap/src/supp_main.c b/modules/hostap/src/supp_main.c index ab20729448d3..ab27f87994aa 100644 --- a/modules/hostap/src/supp_main.c +++ b/modules/hostap/src/supp_main.c @@ -81,6 +81,7 @@ static const struct wifi_mgmt_ops mgmt_ops = { #endif .get_conn_params = supplicant_get_wifi_conn_params, .wps_config = supplicant_wps_config, + .set_bss_max_idle_period = supplicant_set_bss_max_idle_period, #ifdef CONFIG_AP .ap_enable = supplicant_ap_enable, .ap_disable = supplicant_ap_disable, diff --git a/subsys/net/l2/wifi/Kconfig b/subsys/net/l2/wifi/Kconfig index a2e029a592be..bddb1a7c8bd5 100644 --- a/subsys/net/l2/wifi/Kconfig +++ b/subsys/net/l2/wifi/Kconfig @@ -149,3 +149,19 @@ config HEAP_MEM_POOL_ADD_SIZE_WIFI_CERT endif # WIFI_SHELL_RUNTIME_CERTIFICATES endif # WIFI_NM_WPA_SUPPLICANT_CRYPTO_ENTERPRISE + +config WIFI_MGMT_BSS_MAX_IDLE_TIME + int "BSS max idle timeout in seconds" + range 0 64000 + default 300 + help + As per 802.11-2020: 11.21.13 BSS max idle period management + If dot11WirelessManagementImplemented is true, dot11BSSMaxIdlePeriod is + nonzero and dot11BSSMaxIdlePeriodIndicationByNonAPSTA is true, then a + non-S1G non-AP STA shall include a BSS Max Idle Period element + in the (Re)Association Request frame. If the BSS Max Idle Period + element is present in the (Re)Association Request frame received + by a non-S1G AP that has dot11BSSMaxIdlePeriodIndicationByNonAPSTA + equal to true, then the non-S1G AP may choose the non-AP STA’s + preferred maximum idle period. The non-S1G AP indicates its chosen + value to the non-S1G STA in the (Re)Association Response frame. diff --git a/subsys/net/l2/wifi/wifi_mgmt.c b/subsys/net/l2/wifi/wifi_mgmt.c index 0183faab1d50..f16f2581374f 100644 --- a/subsys/net/l2/wifi/wifi_mgmt.c +++ b/subsys/net/l2/wifi/wifi_mgmt.c @@ -1403,6 +1403,31 @@ static int wifi_set_enterprise_creds(uint64_t mgmt_request, struct net_if *iface NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_ENTERPRISE_CREDS, wifi_set_enterprise_creds); #endif +static int wifi_set_bss_max_idle_period(uint64_t mgmt_request, struct net_if *iface, + void *data, size_t len) +{ + const struct device *dev = net_if_get_device(iface); + const struct wifi_mgmt_ops *const wifi_mgmt_api = get_wifi_api(iface); + unsigned short *bss_max_idle_period = data; + + if (wifi_mgmt_api == NULL || wifi_mgmt_api->set_bss_max_idle_period == NULL) { + return -ENOTSUP; + } + + if (!net_if_is_admin_up(iface)) { + return -ENETDOWN; + } + + if (!data || len != sizeof(*bss_max_idle_period)) { + return -EINVAL; + } + + return wifi_mgmt_api->set_bss_max_idle_period(dev, *bss_max_idle_period); +} + +NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_WIFI_BSS_MAX_IDLE_PERIOD, + wifi_set_bss_max_idle_period); + #ifdef CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS void wifi_mgmt_raise_raw_scan_result_event(struct net_if *iface, struct wifi_raw_scan_result *raw_scan_result) diff --git a/subsys/net/l2/wifi/wifi_shell.c b/subsys/net/l2/wifi/wifi_shell.c index 29db29a0a2c8..da0ef9ef2ff3 100644 --- a/subsys/net/l2/wifi/wifi_shell.c +++ b/subsys/net/l2/wifi/wifi_shell.c @@ -3807,6 +3807,32 @@ static int cmd_wifi_pmksa_flush(const struct shell *sh, size_t argc, char *argv[ return 0; } + +static int cmd_wifi_set_bss_max_idle_period(const struct shell *sh, size_t argc, char *argv[]) +{ + struct net_if *iface = get_iface(IFACE_TYPE_STA, argc, argv); + unsigned short bss_max_idle_period = 0; + int idx = 1; + unsigned long val = 0; + + if (!parse_number(sh, &val, argv[idx++], "bss_max_idle_period", 0, USHRT_MAX)) { + return -EINVAL; + } + + bss_max_idle_period = (unsigned short)val; + + if (net_mgmt(NET_REQUEST_WIFI_BSS_MAX_IDLE_PERIOD, iface, + &bss_max_idle_period, sizeof(bss_max_idle_period))) { + shell_fprintf(sh, SHELL_WARNING, + "Setting BSS maximum idle period failed.\n"); + return -ENOEXEC; + } + + shell_fprintf(sh, SHELL_NORMAL, "BSS max idle period: %hu\n", bss_max_idle_period); + + return 0; +} + SHELL_STATIC_SUBCMD_SET_CREATE( wifi_cmd_ap, SHELL_CMD_ARG(disable, NULL, "Disable Access Point mode.\n" @@ -4285,6 +4311,12 @@ SHELL_SUBCMD_ADD((wifi), ps_exit_strategy, NULL, cmd_wifi_ps_exit_strategy, 2, 2); +SHELL_SUBCMD_ADD((wifi), bss_max_idle_period, NULL, + ".\n" + "[-i, --iface=] : Interface index.\n", + cmd_wifi_set_bss_max_idle_period, + 2, 2); + SHELL_CMD_REGISTER(wifi, &wifi_commands, "Wi-Fi commands", NULL); static int wifi_shell_init(void) diff --git a/west.yml b/west.yml index dba3ebbe9f3c..70033b1d5bb2 100644 --- a/west.yml +++ b/west.yml @@ -281,7 +281,7 @@ manifest: - hal - name: hostap path: modules/lib/hostap - revision: cf270006050cf944af699301c7f4de2b427cd862 + revision: pull/89/head - name: liblc3 revision: 48bbd3eacd36e99a57317a0a4867002e0b09e183 path: modules/lib/liblc3