diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h index 27da9abb1401..069356d61d73 100644 --- a/core/hdd/inc/wlan_hdd_cfg.h +++ b/core/hdd/inc/wlan_hdd_cfg.h @@ -242,7 +242,7 @@ struct hdd_config { bool enable_sar_safety; bool config_sar_safety_sleep_index; #endif - + bool get_roam_chan_from_fw; uint32_t fisa_enable; }; diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index b8a875e079a7..b1bd7af6be9d 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1900,6 +1900,7 @@ struct hdd_context { /* value for packet capturte mode */ uint8_t val_pkt_capture_mode; #endif + bool roam_ch_from_fw_supported; }; /** diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 6f5488a4679b..9cd40facf299 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -1585,7 +1585,10 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = .vendor_id = QCA_NL80211_VENDOR_ID, .subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS_EVENT, }, - + [QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO, + } }; /** @@ -6207,6 +6210,41 @@ wlan_hdd_add_fils_params_roam_auth_event(struct sk_buff *skb, #endif #ifdef WLAN_FEATURE_ROAM_OFFLOAD +void hdd_send_roam_scan_ch_list_event(struct hdd_context *hdd_ctx, + uint16_t buf_len, uint8_t *buf) +{ + struct sk_buff *vendor_event; + uint32_t len, ret; + + if (!hdd_ctx) { + hdd_err_rl("hdd context is null"); + return; + } + + len = nla_total_size(buf_len) + NLMSG_HDRLEN; + vendor_event = + cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, NULL, len, + QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + ret = nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_CONNECT_CHANNELS, + buf_len, buf); + if (ret) { + hdd_err("OEM event put fails status %d", ret); + kfree_skb(vendor_event); + return; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + /** * wlan_hdd_send_roam_auth_event() - Send the roamed and authorized event * @adapter: Pointer to adapter struct diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h index ed90ac0d5835..c3fb56d3b696 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.h +++ b/core/hdd/src/wlan_hdd_cfg80211.h @@ -397,6 +397,17 @@ void wlan_hdd_cfg80211_unlink_bss(struct hdd_adapter *adapter, void wlan_hdd_cfg80211_acs_ch_select_evt(struct hdd_adapter *adapter); #ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * hdd_send_roam_scan_ch_list_event() - roam scan ch list event to user space + * @hdd_ctx: HDD context + * @buf_len: length of frequency list + * @buf: pointer to buffer of frequency list + * + * Return: None + */ +void hdd_send_roam_scan_ch_list_event(struct hdd_context *hdd_ctx, + uint16_t buf_len, uint8_t *buf); + int wlan_hdd_send_roam_auth_event(struct hdd_adapter *adapter, uint8_t *bssid, uint8_t *req_rsn_ie, uint32_t req_rsn_length, uint8_t *rsp_rsn_ie, uint32_t rsp_rsn_length, struct csr_roam_info @@ -409,6 +420,12 @@ static inline int wlan_hdd_send_roam_auth_event(struct hdd_adapter *adapter, { return 0; } + +static inline void +hdd_send_roam_scan_ch_list_event(struct hdd_context *hdd_ctx, + uint16_t buf_len, uint8_t *buf) +{ +} #endif int wlan_hdd_cfg80211_update_apies(struct hdd_adapter *adapter); diff --git a/core/hdd/src/wlan_hdd_ioctl.c b/core/hdd/src/wlan_hdd_ioctl.c index 5555d358026a..2a02890867fe 100644 --- a/core/hdd/src/wlan_hdd_ioctl.c +++ b/core/hdd/src/wlan_hdd_ioctl.c @@ -3996,6 +3996,137 @@ static int drv_cmd_set_roam_scan_channels(struct hdd_adapter *adapter, return hdd_parse_set_roam_scan_channels(adapter, command); } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static bool is_roam_ch_from_fw_supported(struct hdd_context *hdd_ctx) +{ + return hdd_ctx->roam_ch_from_fw_supported; +} + +struct roam_ch_priv { + struct roam_scan_ch_resp roam_ch; +}; + +void hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle, + struct roam_scan_ch_resp *roam_ch, + void *context) +{ + struct osif_request *request; + struct roam_ch_priv *priv; + uint8_t *event = NULL, i = 0; + uint32_t *freq = NULL, len; + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + + hdd_debug("roam scan ch list event received : vdev_id:%d command resp: %d", + roam_ch->vdev_id, roam_ch->command_resp); + /** + * If command response is set in the response message, then it is + * getroamscanchannels command response else this event is asyncronous + * event raised by firmware. + */ + if (!roam_ch->command_resp) { + len = roam_ch->num_channels * sizeof(roam_ch->chan_list[0]); + event = (uint8_t *)qdf_mem_malloc(len); + if (!event) { + hdd_err("Failed to alloc event response buf vdev_id: %d", + roam_ch->vdev_id); + return; + } + freq = (uint32_t *)event; + for (i = 0; i < roam_ch->num_channels && + i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) { + freq[i] = roam_ch->chan_list[i]; + } + + hdd_send_roam_scan_ch_list_event(hdd_ctx, len, event); + qdf_mem_free(event); + return; + } + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + priv = osif_request_priv(request); + + priv->roam_ch.num_channels = roam_ch->num_channels; + for (i = 0; i < priv->roam_ch.num_channels && + i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) + priv->roam_ch.chan_list[i] = roam_ch->chan_list[i]; + + osif_request_complete(request); + osif_request_put(request); +} + +static uint32_t +hdd_get_roam_chan_from_fw(struct hdd_adapter *adapter, uint32_t *chan_list, + uint8_t *num_channels) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct hdd_context *hdd_ctx; + int ret, i; + void *cookie; + struct osif_request *request; + struct roam_ch_priv *priv; + struct roam_scan_ch_resp *p_roam_ch; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv) + + sizeof(priv->roam_ch.chan_list[0]) * + WNI_CFG_VALID_CHANNEL_LIST_LEN, + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + + priv = osif_request_priv(request); + p_roam_ch = &priv->roam_ch; + /** channel list starts after response structure*/ + priv->roam_ch.chan_list = (uint32_t *)(p_roam_ch + 1); + cookie = osif_request_cookie(request); + status = sme_get_roam_scan_ch(hdd_ctx->mac_handle, + adapter->vdev_id, cookie); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to retrieve roam channels"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving raom channels"); + goto cleanup; + } + + priv = osif_request_priv(request); + *num_channels = priv->roam_ch.num_channels; + for (i = 0; i < *num_channels; i++) + chan_list[i] = priv->roam_ch.chan_list[i]; + +cleanup: + osif_request_put(request); + + return ret; +} +#else +static bool is_roam_ch_from_fw_supported(struct hdd_context *hdd_ctx) +{ + return false; +} + +static uint32_t +hdd_get_roam_chan_from_fw(struct hdd_adapter *adapter, uint32_t *chan_list, + uint8_t *num_channels) +{ + return QDF_STATUS_E_INVAL; +} +#endif + static int drv_cmd_get_roam_scan_channels(struct hdd_adapter *adapter, struct hdd_context *hdd_ctx, uint8_t *command, @@ -4010,6 +4141,18 @@ static int drv_cmd_get_roam_scan_channels(struct hdd_adapter *adapter, int len; uint8_t chan; + if (is_roam_ch_from_fw_supported(hdd_ctx)) { + ret = hdd_get_roam_chan_from_fw(adapter, freq_list, + &num_channels); + if (ret == QDF_STATUS_SUCCESS) { + goto fill_ch_resp; + } else { + hdd_err("failed to get roam scan channel list from FW"); + ret = -EFAULT; + goto exit; + } + } + if (QDF_STATUS_SUCCESS != sme_get_roam_scan_channel_list(hdd_ctx->mac_handle, freq_list, @@ -4020,6 +4163,7 @@ static int drv_cmd_get_roam_scan_channels(struct hdd_adapter *adapter, goto exit; } +fill_ch_resp: qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL, adapter->vdev_id, num_channels); diff --git a/core/hdd/src/wlan_hdd_ioctl.h b/core/hdd/src/wlan_hdd_ioctl.h index 5296724e4a0b..e3825110a8e3 100644 --- a/core/hdd/src/wlan_hdd_ioctl.h +++ b/core/hdd/src/wlan_hdd_ioctl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2014, 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2014, 2017-2019, 2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -48,6 +48,32 @@ QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode); int hdd_set_antenna_mode(struct hdd_adapter *adapter, struct hdd_context *hdd_ctx, int mode); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * hdd_get_roam_scan_ch_cb() - roam scan channel list callback handler + * @hdd_handle: Pointer to hdd context + * @roam_ch: pointer to roam scan ch event data + * @context: cookie + * + * Callback function to processes roam scan chaanel list event. If + * command response field in the response message is set that means + * event received as a response of GETROAMSCANCHANNELS command else + * event was rasied by firmware upon disconnection. + * + * Return: none + */ +void hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle, + struct roam_scan_ch_resp *roam_ch, + void *context); +#else +static inline void +hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle, + void *roam_ch, + void *context) +{ +} +#endif + #ifdef QCA_IBSS_SUPPORT /** * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 70255bc40102..ea9ef8602a9e 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -1626,6 +1626,7 @@ static void hdd_update_tgt_services(struct hdd_context *hdd_ctx, mawc_enabled & cfg->is_fw_mawc_capable); hdd_update_tdls_config(hdd_ctx); sme_update_tgt_services(hdd_ctx->mac_handle, cfg); + hdd_ctx->roam_ch_from_fw_supported = cfg->is_roam_scan_ch_to_host; } /** @@ -13427,6 +13428,8 @@ int hdd_register_cb(struct hdd_context *hdd_ctx) hdd_common_roam_callback); sme_set_oem_data_event_handler_cb(mac_handle, hdd_oem_event_handler_cb); + sme_set_roam_scan_ch_event_cb(mac_handle, hdd_get_roam_scan_ch_cb); + hdd_exit(); return ret; diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index d29f0671a5d6..9f2dd328923e 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -191,6 +191,20 @@ struct rsn_caps { uint16_t Reserved:8; }; +/** + * struct roam_scan_ch_resp - roam scan chan list response to userspace + * @vdev_id: vdev id + * @num_channels: number of roam scan channels + * @command_resp: command response or async event + * @chan_list: list of roam scan channels + */ +struct roam_scan_ch_resp { + uint16_t vdev_id; + uint16_t num_channels; + uint32_t command_resp; + uint32_t *chan_list; +}; + /** * struct wlan_beacon_report - Beacon info to be send to userspace * @vdev_id: vdev id diff --git a/core/mac/inc/wni_api.h b/core/mac/inc/wni_api.h index 7c4101fbdafb..bea0c77eefd5 100644 --- a/core/mac/inc/wni_api.h +++ b/core/mac/inc/wni_api.h @@ -243,7 +243,9 @@ enum eWniMsgTypes { eWNI_SME_VDEV_DELETE_RSP = SIR_SME_MSG_TYPES_BEGIN + 158, eWNI_SME_ROAM_INIT_PARAM = SIR_SME_MSG_TYPES_BEGIN + 159, eWNI_SME_ROAM_SEND_PER_REQ = SIR_SME_MSG_TYPES_BEGIN + 160, - eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 161 + eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT = + SIR_SME_MSG_TYPES_BEGIN + 161, + eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 162 }; typedef struct sAniCfgTxRateCtrs { diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h index 04ce72be1393..37bbf3e02bb8 100644 --- a/core/mac/src/include/sir_params.h +++ b/core/mac/src/include/sir_params.h @@ -652,6 +652,8 @@ struct sir_cfg_action_frm_tb_ppdu { #define SIR_HAL_SET_ROAM_TRIGGERS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 413) +#define SIR_HAL_ROAM_SCAN_CH_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 414) + #define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) /* LIM message types */ diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h index db51f9d04b17..921dfc59d23e 100644 --- a/core/sme/inc/csr_api.h +++ b/core/sme/inc/csr_api.h @@ -1436,6 +1436,11 @@ static inline void csr_roam_fill_tdls_info(struct mac_context *mac_ctx, {} #endif +typedef void (*sme_get_raom_scan_ch_callback)( + hdd_handle_t hdd_handle, + struct roam_scan_ch_resp *roam_ch, + void *context); + /** * csr_packetdump_timer_stop() - stops packet dump timer * diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 4048ed79d194..cbabea63e861 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -560,6 +560,32 @@ QDF_STATUS sme_roam_get_connect_profile(mac_handle_t mac_handle, void sme_roam_free_connect_profile(tCsrRoamConnectedProfile *profile); #ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * sme_set_roam_scan_ch_event_cb() - Register roam scan ch callback + * @mac_handle: Opaque handle to the MAC context + * @cb: callback to be registered + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_set_roam_scan_ch_event_cb(mac_handle_t mac_handle, + sme_get_raom_scan_ch_callback cb); + +/** + * sme_get_roam_scan_ch() -API to get roam scan channels + * @mac_handle: Pointer to mac handle + * @sta_id: vdev id + * @pcontext: pointer to the context + * + * Extract number of frequencies and frequency list from chan_info and print + * to the logs. + * + * Return: None + */ +QDF_STATUS +sme_get_roam_scan_ch(mac_handle_t mac_handle, + uint8_t vdev_id, void *pcontext); + /** * sme_get_pmk_info(): A wrapper function to request CSR to save PMK * @mac_handle: Global structure @@ -578,6 +604,20 @@ static inline void sme_get_pmk_info(mac_handle_t mac_handle, uint8_t session_id, tPmkidCacheInfo *pmk_cache) {} + +static inline QDF_STATUS +sme_get_roam_scan_ch(mac_handle_t mac_handle, + uint8_t vdev_id, void *pcontext) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +sme_set_roam_scan_ch_event_cb(mac_handle_t mac_handle, + void *cb) +{ + return QDF_STATUS_E_FAILURE; +} #endif /** @@ -1106,6 +1146,7 @@ QDF_STATUS sme_get_roam_scan_channel_list(mac_handle_t mac_handle, uint32_t *freq_list, uint8_t *pNumChannels, uint8_t sessionId); + /** * sme_dump_freq_list() - Dump the frequencies from given chan info * @chan_info: Contains the frequency list and number of frequencies diff --git a/core/sme/inc/sme_internal.h b/core/sme/inc/sme_internal.h index cf14a882f30e..46ce736f0f30 100644 --- a/core/sme/inc/sme_internal.h +++ b/core/sme/inc/sme_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -392,6 +392,8 @@ struct sme_context { void (*oem_data_event_handler_cb) (const struct oem_data *oem_event_data); #endif + sme_get_raom_scan_ch_callback roam_scan_ch_callback; + void *roam_scan_ch_get_context; }; #endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index f628746243fd..abeb0bfc5a2e 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -1721,6 +1721,38 @@ QDF_STATUS sme_get_tsm_stats(mac_handle_t mac_handle, return status; } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS sme_get_roam_scan_ch(mac_handle_t mac_handle, + uint8_t vdev_id, void *pcontext) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + + msg.type = WMA_ROAM_SCAN_CH_REQ; + msg.bodyval = vdev_id; + mac->sme.roam_scan_ch_get_context = pcontext; + + if (scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg)) { + sme_err("Posting message %d failed", + WMA_ROAM_SCAN_CH_REQ); + mac->sme.roam_scan_ch_get_context = NULL; + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&mac->sme); + return QDF_STATUS_SUCCESS; +} +#endif + /** * sme_set_ese_roam_scan_channel_list() - To set ese roam scan channel list * @mac_handle: Opaque handle to the global MAC context @@ -1949,6 +1981,55 @@ static QDF_STATUS sme_process_dual_mac_config_resp(struct mac_context *mac, return QDF_STATUS_SUCCESS; } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS sme_set_roam_scan_ch_event_cb(mac_handle_t mac_handle, + sme_get_raom_scan_ch_callback cb) +{ + QDF_STATUS qdf_status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + + mac->sme.roam_scan_ch_callback = cb; + sme_release_global_lock(&mac->sme); + + return qdf_status; +} + +/** + * sme_process_roam_scan_ch_list_resp() - Process get roam scan ch list + * response + * @mac: Global MAC pointer + * @msgbuf: pointer to roam scan ch list response + * + * This function checks the roam scan chan list message is for command + * response or a async event and accordingly data is given to user space. + * callback to process further + */ +static void +sme_process_roam_scan_ch_list_resp(struct mac_context *mac, + struct roam_scan_ch_resp *roam_ch) +{ + sme_get_raom_scan_ch_callback callback = + mac->sme.roam_scan_ch_callback; + + if (!roam_ch) + return; + + if (callback) + callback(mac->hdd_handle, roam_ch, + mac->sme.roam_scan_ch_get_context); +} +#else +static void +sme_process_roam_scan_ch_list_resp(tpAniSirGlobal mac, + struct roam_scan_ch_resp *roam_ch) +{ +} +#endif + /** * sme_process_antenna_mode_resp() - Process set antenna mode * response @@ -2326,6 +2407,10 @@ QDF_STATUS sme_process_msg(struct mac_context *mac, struct scheduler_msg *pMsg) sme_err("Empty message for: %d", pMsg->type); } break; + case eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT: + sme_process_roam_scan_ch_list_resp(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; default: if ((pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN) diff --git a/core/wma/inc/wma_api.h b/core/wma/inc/wma_api.h index 8077276e5e52..4df5bdf840ba 100644 --- a/core/wma/inc/wma_api.h +++ b/core/wma/inc/wma_api.h @@ -295,6 +295,25 @@ void wma_process_pdev_hw_mode_trans_ind(void *wma, QDF_STATUS wma_set_cts2self_for_p2p_go(void *wma_handle, uint32_t cts2self_for_p2p_go); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_get_roam_scan_ch() - API to get roam scan channel list. + * @wma_handle: pointer to wma handle. + * @vdev_id: vdev id + * + * Return: QDF_STATUS. + */ +QDF_STATUS wma_get_roam_scan_ch(wmi_unified_t wma, + uint8_t vdev_id); +#else +static inline +QDF_STATUS wma_get_roam_scan_ch(wmi_unified_t wma, + uint8_t vdev_id) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + /** * wma_set_tx_rx_aggr_size() - set tx rx aggregation size * @vdev_id: vdev id diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index bcefb8bcadc4..be5b3ffe85ba 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -301,6 +301,27 @@ wma_roam_pmkid_request_event_handler(void *handle, } #endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_roam_scan_chan_list_event_handler() - roam scan chan list event handler + * @handle: wma handle + * @event: pointer to fw event + * @len: length of event + * + * Return: Success or Failure status + */ +int wma_roam_scan_chan_list_event_handler(WMA_HANDLE handle, + uint8_t *event, + uint32_t len); +#else +static inline int +wma_roam_scan_chan_list_event_handler(WMA_HANDLE handle, uint8_t *event, + uint32_t len) +{ + return 0; +} +#endif + /** * wma_update_per_roam_config() -per roam config parameter updation to FW * @handle: wma handle diff --git a/core/wma/inc/wma_tgt_cfg.h b/core/wma/inc/wma_tgt_cfg.h index e3304a5ed4e5..c5a09f9f20a4 100644 --- a/core/wma/inc/wma_tgt_cfg.h +++ b/core/wma/inc/wma_tgt_cfg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -43,6 +43,7 @@ * @twt_requestor: TWT requestor capability * @twt_responder: TWT responder capability * @bcn_reception_stats: Beacon Reception stats capability + * @is_roam_scan_ch_to_host: Get roam scan channels from fw supported */ struct wma_tgt_services { uint32_t sta_power_save; @@ -75,6 +76,7 @@ struct wma_tgt_services { bool twt_responder; bool obss_scan_offload; bool bcn_reception_stats; + bool is_roam_scan_ch_to_host; }; /** diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h index 37a957fcbf0b..bf33afbe9d11 100644 --- a/core/wma/inc/wma_types.h +++ b/core/wma/inc/wma_types.h @@ -165,6 +165,8 @@ #define WMA_TSM_STATS_RSP SIR_HAL_TSM_STATS_RSP #endif +#define WMA_ROAM_SCAN_CH_REQ SIR_HAL_ROAM_SCAN_CH_REQ + #define WMA_HT40_OBSS_SCAN_IND SIR_HAL_HT40_OBSS_SCAN_IND #define WMA_SET_MIMOPS_REQ SIR_HAL_SET_MIMOPS_REQ diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 7c2c8c44ac48..f2de2b508b21 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -3281,6 +3281,11 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, wma_roam_stats_event_handler, WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler( + wma_handle->wmi_handle, wmi_roam_scan_chan_list_id, + wma_roam_scan_chan_list_event_handler, + WMA_RX_SERIALIZER_CTX); + wma_register_pmkid_req_event_handler(wma_handle); #endif /* WLAN_FEATURE_ROAM_OFFLOAD */ wmi_unified_register_event_handler(wma_handle->wmi_handle, @@ -4683,6 +4688,9 @@ static inline void wma_update_target_services(struct wmi_unified *wmi_handle, if (wmi_service_enabled(wmi_handle, wmi_service_vdev_latency_config)) g_fw_wlan_feat_caps |= (1 << VDEV_LATENCY_CONFIG); + if (wmi_service_enabled(wmi_handle, + wmi_roam_scan_chan_list_to_host_support)) + cfg->is_roam_scan_ch_to_host = true; } /** @@ -8961,6 +8969,9 @@ static QDF_STATUS wma_mc_process_msg(struct scheduler_msg *msg) wma_update_roam_offload_flag(wma_handle, msg->bodyptr); qdf_mem_free(msg->bodyptr); break; + case WMA_ROAM_SCAN_CH_REQ: + wma_get_roam_scan_ch(wma_handle->wmi_handle, msg->bodyval); + break; default: WMA_LOGD("Unhandled WMA message of type %d", msg->type); if (msg->bodyptr) diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c index ddb9de23bd37..1d5c3425b6ee 100644 --- a/core/wma/src/wma_scan_roam.c +++ b/core/wma/src/wma_scan_roam.c @@ -3273,6 +3273,69 @@ int wma_roam_auth_offload_event_handler(WMA_HANDLE handle, uint8_t *event, return 0; } +int wma_roam_scan_chan_list_event_handler(WMA_HANDLE handle, + uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle)handle; + WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID_param_tlvs *param_buf; + wmi_roam_scan_channel_list_event_fixed_param *fixed_param; + uint8_t vdev_id, i = 0, num_ch = 0; + struct roam_scan_ch_resp *resp; + struct scheduler_msg sme_msg = {0}; + + param_buf = (WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID_param_tlvs *)event; + if (!param_buf) { + wma_err_rl("NULL event received from target"); + return -EINVAL; + } + + fixed_param = param_buf->fixed_param; + if (!fixed_param) { + wma_err_rl(" NULL fixed param"); + return -EINVAL; + } + + vdev_id = fixed_param->vdev_id; + if (vdev_id >= wma->max_bssid) { + wma_err_rl("Invalid vdev_id %d", vdev_id); + return -EINVAL; + } + + num_ch = (param_buf->num_channel_list < + WNI_CFG_VALID_CHANNEL_LIST_LEN) ? + param_buf->num_channel_list : + WNI_CFG_VALID_CHANNEL_LIST_LEN; + + resp = qdf_mem_malloc(sizeof(struct roam_scan_ch_resp) + + num_ch * sizeof(param_buf->channel_list[0])); + if (!resp) { + wma_err_rl("Failed to alloc resp message"); + return -EINVAL; + } + + resp->chan_list = (uint32_t *)(resp + 1); + resp->vdev_id = vdev_id; + resp->command_resp = fixed_param->command_response; + resp->num_channels = param_buf->num_channel_list; + + for (i = 0; i < num_ch; i++) + resp->chan_list[i] = param_buf->channel_list[i]; + + sme_msg.type = eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT; + sme_msg.bodyptr = resp; + + if (scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg)) { + WMA_LOGE(FL("Failed to post msg to SME")); + qdf_mem_free(sme_msg.bodyptr); + return -EINVAL; + } + + return 0; +} + #ifdef WLAN_FEATURE_ROAM_OFFLOAD /** * wma_get_trigger_detail_str - Return roam trigger string from the diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index 49baa3e0a3e7..7f3b6d83dd86 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -3777,6 +3777,47 @@ bool wma_is_p2p_lo_capable(void) } #endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS wma_get_roam_scan_ch(wmi_unified_t wmi_handle, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct roam_scan_ch_resp *roam_ch; + struct scheduler_msg sme_msg = {0}; + + if (!wma_is_vdev_valid(vdev_id)) { + wma_err("vdev_id: %d is not active", vdev_id); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_get_roam_scan_ch_list(wmi_handle, vdev_id); + if (QDF_IS_STATUS_SUCCESS(status)) + return status; + roam_ch = qdf_mem_malloc(sizeof(struct roam_scan_ch_resp)); + if (!roam_ch) { + wma_err("Failed to alloc resp"); + return QDF_STATUS_E_INVAL; + } + + roam_ch->command_resp = 1; + roam_ch->num_channels = 0; + roam_ch->chan_list = NULL; + roam_ch->vdev_id = vdev_id; + sme_msg.type = eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT; + sme_msg.bodyptr = roam_ch; + + if (scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg)) { + wma_err("Failed to post msg to SME"); + qdf_mem_free(roam_ch); + return QDF_STATUS_E_INVAL; + } + + return status; +} +#endif + bool wma_capability_enhanced_mcast_filter(void) { tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);