diff --git a/components/cmn_services/interface_mgr/src/wlan_if_mgr_roam.c b/components/cmn_services/interface_mgr/src/wlan_if_mgr_roam.c index 1b68fc9f58c2..b713b256415f 100644 --- a/components/cmn_services/interface_mgr/src/wlan_if_mgr_roam.c +++ b/components/cmn_services/interface_mgr/src/wlan_if_mgr_roam.c @@ -750,14 +750,10 @@ QDF_STATUS if_mgr_validate_candidate(struct wlan_objmgr_vdev *vdev, * Do not allow STA to connect on 6Ghz or indoor channel for non dbs * hardware if SAP and skip_6g_and_indoor_freq_scan ini are present */ - if (wlan_scan_cfg_skip_6g_and_indoor_freq(psoc) && - !policy_mgr_is_hw_dbs_capable(psoc) && - (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq) || - wlan_reg_is_freq_indoor(pdev, chan_freq)) && - op_mode == QDF_STA_MODE && - policy_mgr_mode_specific_connection_count( - psoc, PM_SAP_MODE, NULL)) { - ifmgr_debug("STA connection not allowed on bssid: "QDF_MAC_ADDR_FMT" with freq: %d (6Ghz or indoor(%d)), as SAP is present", + if (op_mode == QDF_STA_MODE && + !policy_mgr_is_sta_chan_valid_for_connect_and_roam(pdev, + chan_freq)) { + ifmgr_debug("STA connection not allowed on bssid: "QDF_MAC_ADDR_FMT" with freq: %d (6Ghz or indoor(%d)), as not valid for connection", QDF_MAC_ADDR_REF(candidate_info->peer_addr.bytes), chan_freq, wlan_reg_is_freq_indoor(pdev, chan_freq)); diff --git a/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h b/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h index 2aff4dfdcf71..bb354d1e6631 100644 --- a/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h +++ b/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 @@ -3729,4 +3730,16 @@ bool policy_mgr_is_sta_mon_concurrency(struct wlan_objmgr_psoc *psoc); * */ QDF_STATUS policy_mgr_check_mon_concurrency(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_sta_chan_valid_for_connect_and_roam - Check if given + * channel is valid for STA connection/roam pcl channels + * @pdev: pdev + * @freq: frequency + * + * Return: true if channel is valid else false + */ +bool policy_mgr_is_sta_chan_valid_for_connect_and_roam( + struct wlan_objmgr_pdev *pdev, + qdf_freq_t freq); #endif /* __WLAN_POLICY_MGR_API_H */ diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c index 9f68499914c5..4785a580def7 100644 --- a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c +++ b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c index c1bb04c28958..3a5c07f982fe 100644 --- a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c +++ b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 diff --git a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c index d162693fdf54..9c940ef8d8f1 100644 --- a/components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c +++ b/components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c @@ -35,6 +35,7 @@ #include "wlan_utility.h" #include "wlan_mlme_ucfg_api.h" #include "csr_neighbor_roam.h" +#include "wlan_scan_api.h" /** * first_connection_pcl_table - table which provides PCL for the @@ -2755,3 +2756,34 @@ QDF_STATUS policy_mgr_filter_passive_ch(struct wlan_objmgr_pdev *pdev, return QDF_STATUS_SUCCESS; } + +bool policy_mgr_is_sta_chan_valid_for_connect_and_roam( + struct wlan_objmgr_pdev *pdev, + qdf_freq_t freq) +{ + struct wlan_objmgr_psoc *psoc; + uint32_t sap_count; + bool skip_6g_and_indoor_freq; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return true; + + skip_6g_and_indoor_freq = + wlan_scan_cfg_skip_6g_and_indoor_freq(psoc); + sap_count = + policy_mgr_mode_specific_connection_count(psoc, PM_SAP_MODE, + NULL); + /* + * Do not allow STA to connect/roam on 6Ghz or indoor channel for + * non-dbs hardware if SAP is present and skip_6g_and_indoor_freq_scan + * ini is enabled + */ + if (skip_6g_and_indoor_freq && sap_count && + !policy_mgr_is_hw_dbs_capable(psoc) && + (WLAN_REG_IS_6GHZ_CHAN_FREQ(freq) || + wlan_reg_is_freq_indoor(pdev, freq))) + return false; + + return true; +} diff --git a/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h b/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h index a41fc7cf5d1a..847819985444 100644 --- a/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h +++ b/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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 @@ -385,6 +386,12 @@ QDF_STATUS ucfg_send_big_data_stats_request(struct wlan_objmgr_vdev *vdev, { return QDF_STATUS_SUCCESS; } + +static inline void +ucfg_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev *vdev, + int *dbm) +{} + #endif /* QCA_SUPPORT_CP_STATS */ #endif /* __WLAN_CP_STATS_MC_UCFG_API_H__ */ diff --git a/components/mlme/dispatcher/inc/cfg_mlme_reg.h b/components/mlme/dispatcher/inc/cfg_mlme_reg.h index c28c119db46b..24c6f54a4d0f 100644 --- a/components/mlme/dispatcher/inc/cfg_mlme_reg.h +++ b/components/mlme/dispatcher/inc/cfg_mlme_reg.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 @@ -292,7 +293,7 @@ * enable_pending_list_req - Sets Pending channel List Req. * @Min: 0 * @Max: 1 - * @Default: 0 + * @Default: 1 * * This option enables/disables SCAN_CHAN_LIST_CMDID channel list command to FW * till the current scan is complete. @@ -307,7 +308,7 @@ */ #define CFG_ENABLE_PENDING_CHAN_LIST_REQ CFG_INI_BOOL( \ "enable_pending_list_req", \ - 0, \ + 1, \ "Enable Pending list req") /* diff --git a/components/pkt_capture/core/inc/wlan_pkt_capture_priv.h b/components/pkt_capture/core/inc/wlan_pkt_capture_priv.h index ce37798894ed..93ab1eac698b 100644 --- a/components/pkt_capture/core/inc/wlan_pkt_capture_priv.h +++ b/components/pkt_capture/core/inc/wlan_pkt_capture_priv.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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 @@ -63,6 +63,8 @@ struct pkt_capture_cb_context { * @ppdu_stats_q: list used for storing smu related ppdu stats * @lock_q: spinlock for ppdu_stats q * @tx_nss: nss of tx data packets received from ppdu stats + * @last_freq: Last connected freq + * @curr_freq: current connected freq */ struct pkt_capture_vdev_priv { struct wlan_objmgr_vdev *vdev; @@ -74,6 +76,8 @@ struct pkt_capture_vdev_priv { qdf_list_t ppdu_stats_q; qdf_spinlock_t lock_q; uint8_t tx_nss; + qdf_freq_t last_freq; + qdf_freq_t curr_freq; }; /** diff --git a/components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c b/components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c index 014a4b383e47..b67f30909bcc 100644 --- a/components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c +++ b/components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c @@ -1467,10 +1467,6 @@ void pkt_capture_datapkt_process( if (QDF_IS_STATUS_ERROR(ret)) goto drop_rx_buf; - pkt = pkt_capture_alloc_mon_pkt(vdev); - if (!pkt) - goto drop_rx_buf; - switch (type) { case TXRX_PROCESS_TYPE_DATA_RX: callback = pkt_capture_rx_data_cb; @@ -1480,7 +1476,14 @@ void pkt_capture_datapkt_process( callback = pkt_capture_tx_data_cb; break; default: - return; + pkt_capture_vdev_put_ref(vdev); + goto drop_rx_buf; + } + + pkt = pkt_capture_alloc_mon_pkt(vdev); + if (!pkt) { + pkt_capture_vdev_put_ref(vdev); + goto drop_rx_buf; } pkt->callback = callback; diff --git a/components/pkt_capture/core/src/wlan_pkt_capture_main.c b/components/pkt_capture/core/src/wlan_pkt_capture_main.c index 5233107b9f09..5d1e3ee2b7d8 100644 --- a/components/pkt_capture/core/src/wlan_pkt_capture_main.c +++ b/components/pkt_capture/core/src/wlan_pkt_capture_main.c @@ -268,7 +268,7 @@ pkt_capture_process_tx_data(void *soc, void *log_data, u_int16_t vdev_id, { struct dp_soc *psoc = soc; uint8_t tid = 0; - uint8_t bssid[QDF_MAC_ADDR_SIZE]; + uint8_t bssid[QDF_MAC_ADDR_SIZE] = {0}; struct pkt_capture_tx_hdr_elem_t *ptr_pktcapture_hdr; struct pkt_capture_tx_hdr_elem_t pktcapture_hdr = {0}; struct hal_tx_completion_status tx_comp_status = {0}; @@ -482,7 +482,7 @@ pkt_capture_is_frame_filter_set(qdf_nbuf_t buf, void pkt_capture_callback(void *soc, enum WDI_EVENT event, void *log_data, u_int16_t peer_id, uint32_t status) { - uint8_t bssid[QDF_MAC_ADDR_SIZE]; + uint8_t bssid[QDF_MAC_ADDR_SIZE] = {0}; struct wlan_objmgr_vdev *vdev; struct pkt_capture_vdev_priv *vdev_priv; struct pkt_capture_frame_filter *frame_filter; @@ -754,6 +754,8 @@ pkt_capture_register_callbacks(struct wlan_objmgr_vdev *vdev, target_if_pkt_capture_register_rx_ops(&psoc_priv->rx_ops); pkt_capture_wdi_event_subscribe(psoc); pkt_capture_record_channel(vdev); + vdev_priv->curr_freq = vdev->vdev_mlme.des_chan->ch_freq; + vdev_priv->last_freq = vdev_priv->curr_freq; status = tgt_pkt_capture_register_ev_handler(vdev); if (QDF_IS_STATUS_ERROR(status)) diff --git a/components/pkt_capture/core/src/wlan_pkt_capture_mgmt_txrx.c b/components/pkt_capture/core/src/wlan_pkt_capture_mgmt_txrx.c index a56d5f3de791..1e3aea3a5a38 100644 --- a/components/pkt_capture/core/src/wlan_pkt_capture_mgmt_txrx.c +++ b/components/pkt_capture/core/src/wlan_pkt_capture_mgmt_txrx.c @@ -594,6 +594,7 @@ pkt_capture_mgmt_rx_data_cb(struct wlan_objmgr_psoc *psoc, buf_len + RESERVE_BYTES, 4), RESERVE_BYTES, 4, false); if (!nbuf) { + pkt_capture_vdev_put_ref(vdev); qdf_nbuf_free(wbuf); return QDF_STATUS_E_FAILURE; } diff --git a/components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c b/components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c index 599edf22d261..be99be8ee939 100644 --- a/components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c +++ b/components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 @@ -25,6 +26,7 @@ #include "wlan_mgmt_txrx_utils_api.h" #include "cdp_txrx_ctrl.h" #include "cfg_ucfg_api.h" +#include "wlan_mgmt_txrx_utils_api.h" void pkt_capture_mon(struct pkt_capture_cb_context *cb_ctx, qdf_nbuf_t msdu, struct wlan_objmgr_vdev *vdev, uint16_t ch_freq) @@ -35,6 +37,9 @@ void pkt_capture_mon(struct pkt_capture_cb_context *cb_ctx, qdf_nbuf_t msdu, void *soc = cds_get_context(QDF_MODULE_ID_SOC); struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); cdp_config_param_type val; + uint16_t status; + tSirMacAuthFrameBody *auth; + struct pkt_capture_vdev_priv *vdev_priv; rthdr = (struct radiotap_header *)qdf_nbuf_data(msdu); rtlen = rthdr->it_len; @@ -42,17 +47,79 @@ void pkt_capture_mon(struct pkt_capture_cb_context *cb_ctx, qdf_nbuf_t msdu, type = (wh)->i_fc[0] & IEEE80211_FC0_TYPE_MASK; sub_type = (wh)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + return; + } + + /* + * Update channel only if successful AUTH Resp is received. + * This is done so that EAPOL M1 data frame have correct + * channel + */ if ((type == IEEE80211_FC0_TYPE_MGT) && (sub_type == MGMT_SUBTYPE_AUTH)) { uint8_t chan = wlan_freq_to_chan(ch_freq); - val.cdp_pdev_param_monitor_chan = chan; - cdp_txrx_set_pdev_param(soc, wlan_objmgr_pdev_get_pdev_id(pdev), + auth = (tSirMacAuthFrameBody *)(qdf_nbuf_data(msdu) + rtlen + + sizeof(tSirMacMgmtHdr)); + + if (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_2 || + auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_4) { + if (auth->authStatusCode == STATUS_SUCCESS) { + val.cdp_pdev_param_monitor_chan = chan; + cdp_txrx_set_pdev_param( + soc, wlan_objmgr_pdev_get_pdev_id(pdev), CDP_MONITOR_CHANNEL, val); - val.cdp_pdev_param_mon_freq = ch_freq; - cdp_txrx_set_pdev_param(soc, wlan_objmgr_pdev_get_pdev_id(pdev), + val.cdp_pdev_param_mon_freq = ch_freq; + cdp_txrx_set_pdev_param( + soc, wlan_objmgr_pdev_get_pdev_id(pdev), CDP_MONITOR_FREQUENCY, val); + } + } + } + + /* + * Update channel to last connected channel in case of assoc/reassoc + * response failure and save current chan in case of success + */ + if ((type == IEEE80211_FC0_TYPE_MGT) && + ((sub_type == MGMT_SUBTYPE_ASSOC_RESP) || + (sub_type == MGMT_SUBTYPE_REASSOC_RESP))) { + if (qdf_nbuf_len(msdu) < (rtlen + sizeof(tSirMacMgmtHdr) + + SIR_MAC_ASSOC_RSP_STATUS_CODE_OFFSET)) { + pkt_capture_err("Packet length is less than expected"); + qdf_nbuf_free(msdu); + return; + } + + status = (uint16_t)(*(qdf_nbuf_data(msdu) + rtlen + + sizeof(tSirMacMgmtHdr) + + SIR_MAC_ASSOC_RSP_STATUS_CODE_OFFSET)); + + if (status == STATUS_SUCCESS) { + vdev_priv->last_freq = vdev_priv->curr_freq; + vdev_priv->curr_freq = ch_freq; + } else { + uint8_t chan_num; + + chan_num = wlan_reg_freq_to_chan(pdev, + vdev_priv->last_freq); + + val.cdp_pdev_param_monitor_chan = chan_num; + cdp_txrx_set_pdev_param( + soc, wlan_objmgr_pdev_get_pdev_id(pdev), + CDP_MONITOR_CHANNEL, val); + + val.cdp_pdev_param_mon_freq = vdev_priv->last_freq; + cdp_txrx_set_pdev_param( + soc, wlan_objmgr_pdev_get_pdev_id(pdev), + CDP_MONITOR_FREQUENCY, val); + + vdev_priv->curr_freq = vdev_priv->last_freq; + } } if (cb_ctx->mon_cb(cb_ctx->mon_ctx, msdu) != QDF_STATUS_SUCCESS) { diff --git a/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_tgt_if_tx_api.c b/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_tgt_if_tx_api.c index 76ecef7a8baf..7b556f9b0d9c 100644 --- a/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_tgt_if_tx_api.c +++ b/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_tgt_if_tx_api.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 above @@ -62,9 +63,11 @@ wlan_cm_roam_send_set_vdev_pcl(struct wlan_objmgr_psoc *psoc, struct fw_scan_channels *freq_list; struct wlan_objmgr_vdev *vdev; struct wmi_pcl_chan_weights *weights; + struct wlan_objmgr_pdev *pdev; QDF_STATUS status = QDF_STATUS_E_FAILURE; uint32_t band_capability; uint16_t i; + bool is_channel_allowed; /* * If vdev_id is WLAN_UMAC_VDEV_ID_MAX, then PDEV pcl command @@ -85,6 +88,13 @@ wlan_cm_roam_send_set_vdev_pcl(struct wlan_objmgr_psoc *psoc, return status; } + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err("pdev object is NULL"); + status = QDF_STATUS_E_FAILURE; + return status; + } + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); if (!roam_tx_ops || !roam_tx_ops->send_vdev_set_pcl_cmd) { mlme_err("send_vdev_set_pcl_cmd is NULL"); @@ -133,6 +143,13 @@ wlan_cm_roam_send_set_vdev_pcl(struct wlan_objmgr_psoc *psoc, !WLAN_REG_IS_24GHZ_CH_FREQ(weights->saved_chan_list[i])) weights->weighed_valid_list[i] = WEIGHT_OF_DISALLOWED_CHANNELS; + + is_channel_allowed = + policy_mgr_is_sta_chan_valid_for_connect_and_roam( + pdev, weights->saved_chan_list[i]); + if (!is_channel_allowed) + weights->weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; } if (QDF_IS_STATUS_ERROR(status)) { diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c index 816562e2043a..011f235bbfc6 100644 --- a/core/cds/src/cds_api.c +++ b/core/cds/src/cds_api.c @@ -958,10 +958,13 @@ QDF_STATUS cds_dp_open(struct wlan_objmgr_psoc *psoc) cds_debug("CDS successfully Opened"); - if (cdp_cfg_get(gp_cds_context->dp_soc, cfg_dp_force_gro_enable)) - hdd_ctx->dp_agg_param.force_gro_enable = true; + if (cdp_cfg_get(gp_cds_context->dp_soc, cfg_dp_tc_based_dyn_gro_enable)) + hdd_ctx->dp_agg_param.tc_based_dyn_gro = true; else - hdd_ctx->dp_agg_param.force_gro_enable = false; + hdd_ctx->dp_agg_param.tc_based_dyn_gro = false; + + hdd_ctx->dp_agg_param.tc_ingress_prio = + cdp_cfg_get(gp_cds_context->dp_soc, cfg_dp_tc_ingress_prio); return 0; diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 3f0c8a18cea2..5d74543caefc 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1198,6 +1198,20 @@ struct rcpi_info { struct hdd_context; +#ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION +/** + * enum qdisc_filter_status - QDISC filter status + * @QDISC_FILTER_RTNL_LOCK_FAIL: rtnl lock acquire failed + * @QDISC_FILTER_PRIO_MATCH: qdisc filter with priority match + * @QDISC_FILTER_PRIO_MISMATCH: no filter match with configured priority + */ +enum qdisc_filter_status { + QDISC_FILTER_RTNL_LOCK_FAIL, + QDISC_FILTER_PRIO_MATCH, + QDISC_FILTER_PRIO_MISMATCH, +}; +#endif + /** * struct hdd_adapter - hdd vdev/net_device context * @vdev: object manager vdev context @@ -1532,7 +1546,7 @@ struct hdd_adapter { void *cookie; bool response_expected; #endif - uint8_t gro_disallowed[DP_MAX_RX_THREADS]; + qdf_atomic_t gro_disallowed; uint8_t gro_flushed[DP_MAX_RX_THREADS]; bool handle_feature_update; /* Indicate if TSO and checksum offload features are enabled or not */ @@ -1865,7 +1879,8 @@ struct hdd_adapter_ops_history { * @country_change_work: work for updating vdev when country changes * @rx_aggregation: rx aggregation enable or disable state * @gro_force_flush: gro force flushed indication flag - * @force_gro_enable: force GRO enable or disable flag + * @tc_based_dyn_gro: TC based dynamic GRO enable/disable flag + * @tc_ingress_prio: TC ingress priority * @current_pcie_gen_speed: current pcie gen speed * @pm_qos_req: pm_qos request for all cpu cores * @qos_cpu_mask: voted cpu core mask @@ -2206,7 +2221,8 @@ struct hdd_context { struct { qdf_atomic_t rx_aggregation; uint8_t gro_force_flush[DP_MAX_RX_THREADS]; - bool force_gro_enable; + bool tc_based_dyn_gro; + uint32_t tc_ingress_prio; } dp_agg_param; int current_pcie_gen_speed; qdf_workqueue_t *adapter_ops_wq; diff --git a/core/hdd/inc/wlan_hdd_tx_rx.h b/core/hdd/inc/wlan_hdd_tx_rx.h index 93e336c96961..c96ab216b26f 100644 --- a/core/hdd/inc/wlan_hdd_tx_rx.h +++ b/core/hdd/inc/wlan_hdd_tx_rx.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c index 454a4b716103..08b6ed22fc77 100644 --- a/core/hdd/src/wlan_hdd_cfg80211.c +++ b/core/hdd/src/wlan_hdd_cfg80211.c @@ -15714,7 +15714,8 @@ __wlan_hdd_cfg80211_set_monitor_mode(struct wiphy *wiphy, return -EPERM; } - if (!ucfg_pkt_capture_get_mode(hdd_ctx->psoc)) + if (!ucfg_pkt_capture_get_mode(hdd_ctx->psoc) || + !hdd_is_pkt_capture_mon_enable(adapter)) return -EPERM; errno = hdd_validate_adapter(adapter); @@ -17433,12 +17434,15 @@ static void wlan_hdd_update_lfr_wiphy(struct hdd_context *hdd_ctx) bool fast_transition_enabled; bool lfr_enabled; bool ese_enabled; + bool roam_offload; ucfg_mlme_is_fast_transition_enabled(hdd_ctx->psoc, &fast_transition_enabled); ucfg_mlme_is_lfr_enabled(hdd_ctx->psoc, &lfr_enabled); ucfg_mlme_is_ese_enabled(hdd_ctx->psoc, &ese_enabled); - if (fast_transition_enabled || lfr_enabled || ese_enabled) + ucfg_mlme_get_roaming_offload(hdd_ctx->psoc, &roam_offload); + if (fast_transition_enabled || lfr_enabled || ese_enabled || + roam_offload) hdd_ctx->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; } #else @@ -17446,11 +17450,13 @@ static void wlan_hdd_update_lfr_wiphy(struct hdd_context *hdd_ctx) { bool fast_transition_enabled; bool lfr_enabled; + bool roam_offload; ucfg_mlme_is_fast_transition_enabled(hdd_ctx->psoc, &fast_transition_enabled); ucfg_mlme_is_lfr_enabled(hdd_ctx->psoc, &lfr_enabled); - if (fast_transition_enabled || lfr_enabled) + ucfg_mlme_get_roaming_offload(hdd_ctx->psoc, &roam_offload); + if (fast_transition_enabled || lfr_enabled || roam_offload) hdd_ctx->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; } #endif diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c index 6a0822a8c41b..7f782feffdb9 100644 --- a/core/hdd/src/wlan_hdd_driver_ops.c +++ b/core/hdd/src/wlan_hdd_driver_ops.c @@ -754,7 +754,6 @@ static int __hdd_soc_recovery_reinit(struct device *dev, } hdd_soc_load_unlock(dev); - hdd_start_complete(0); return 0; @@ -811,6 +810,7 @@ static int hdd_soc_recovery_reinit(struct device *dev, osif_psoc_sync_trans_stop(psoc_sync); + hdd_start_complete(0); return errno; } diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 5b737abd06de..6d89f88084d1 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -198,6 +198,9 @@ #include #include "qdf_lock.h" #include "wlan_hdd_thermal.h" +#ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION +#include +#endif #ifdef MODULE #ifdef WLAN_WEAR_CHIPSET @@ -6996,6 +6999,7 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio qdf_event_create(&adapter->peer_cleanup_done); hdd_sta_info_init(&adapter->sta_info_list); hdd_sta_info_init(&adapter->cache_sta_info_list); + qdf_atomic_init(&adapter->gro_disallowed); for (i = 0; i < NET_DEV_HOLD_ID_MAX; i++) qdf_atomic_init( @@ -10574,6 +10578,168 @@ void hdd_send_mscs_action_frame(struct hdd_context *hdd_ctx, } #endif +#ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) +static enum qdisc_filter_status +__hdd_check_for_prio_filter_in_clsact_qdisc(struct tcf_block *block, + uint32_t prio) +{ + struct tcf_chain *chain; + struct tcf_proto *tp; + struct tcf_proto *tp_next; + enum qdisc_filter_status ret = QDISC_FILTER_PRIO_MISMATCH; + + if (!rtnl_trylock()) + return QDISC_FILTER_RTNL_LOCK_FAIL; + + mutex_lock(&block->lock); + list_for_each_entry(chain, &block->chain_list, list) { + mutex_lock(&chain->filter_chain_lock); + tp = tcf_chain_dereference(chain->filter_chain, chain); + while (tp) { + tp_next = rcu_dereference_protected(tp->next, 1); + if (tp->prio == (prio << 16)) { + ret = QDISC_FILTER_PRIO_MATCH; + break; + } + tp = tp_next; + } + mutex_unlock(&chain->filter_chain_lock); + + if (ret == QDISC_FILTER_PRIO_MATCH) + break; + } + mutex_unlock(&block->lock); + rtnl_unlock(); + + return ret; +} +#else +static enum qdisc_filter_status +__hdd_check_for_prio_filter_in_clsact_qdisc(struct tcf_block *block, + uint32_t prio) +{ + struct tcf_chain *chain; + struct tcf_proto *tp; + enum qdisc_filter_status ret = QDISC_FILTER_PRIO_MISMATCH; + + if (!rtnl_trylock()) + return QDISC_FILTER_RTNL_LOCK_FAIL; + + list_for_each_entry(chain, &block->chain_list, list) { + for (tp = rtnl_dereference(chain->filter_chain); tp; + tp = rtnl_dereference(tp->next)) { + if (tp->prio == (prio << 16)) + ret = QDISC_FILTER_PRIO_MATCH; + } + } + rtnl_unlock(); + + return ret; +} +#endif + +/** + * hdd_check_for_prio_filter_in_clsact_qdisc() - Check if priority 3 filter + * is configured in the ingress clsact qdisc + * @qdisc: pointer to clsact qdisc + * + * Return: true if priority 3 filter is present else false + */ +static enum qdisc_filter_status +hdd_check_for_prio_filter_in_clsact_qdisc(struct Qdisc *qdisc, uint32_t prio) +{ + const struct Qdisc_class_ops *cops; + struct tcf_block *ingress_block; + + cops = qdisc->ops->cl_ops; + if (qdf_unlikely(!cops || !cops->tcf_block)) + return QDISC_FILTER_PRIO_MISMATCH; + + ingress_block = cops->tcf_block(qdisc, TC_H_MIN_INGRESS, NULL); + if (qdf_unlikely(!ingress_block)) + return QDISC_FILTER_PRIO_MISMATCH; + + return __hdd_check_for_prio_filter_in_clsact_qdisc(ingress_block, prio); +} + +/** + * hdd_rx_check_qdisc_for_adapter() - Check if any ingress qdisc is configured + * for given adapter + * @adapter: pointer to HDD adapter context + * @rx_ctx_id: Rx context id + * + * The function checks if ingress qdisc is registered for a given + * net device. + * + * Return: None + */ +static void +hdd_rx_check_qdisc_for_adapter(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + struct netdev_queue *ingress_q; + struct Qdisc *ingress_qdisc; + bool disable_gro = false; + enum qdisc_filter_status ret; + + if (!adapter->dev->ingress_queue) + goto reset_wl; + + rcu_read_lock(); + + ingress_q = rcu_dereference(adapter->dev->ingress_queue); + if (qdf_unlikely(!ingress_q)) + goto reset; + + ingress_qdisc = rcu_dereference(ingress_q->qdisc); + if (qdf_unlikely(!ingress_qdisc)) + goto reset; + + if (qdf_str_eq(ingress_qdisc->ops->id, "ingress")) { + disable_gro = true; + } else if (qdf_str_eq(ingress_qdisc->ops->id, "clsact")) { + ret = hdd_check_for_prio_filter_in_clsact_qdisc(ingress_qdisc, + hdd_ctx->dp_agg_param.tc_ingress_prio); + + if (ret == QDISC_FILTER_RTNL_LOCK_FAIL) { + rcu_read_unlock(); + return; + } else if (ret == QDISC_FILTER_PRIO_MISMATCH) { + goto reset; + } + + disable_gro = true; + } + + if (disable_gro) { + rcu_read_unlock(); + + if (qdf_likely(qdf_atomic_read(&adapter->gro_disallowed))) + return; + + hdd_debug("ingress qdisc/filter configured disable GRO"); + qdf_atomic_set(&adapter->gro_disallowed, 1); + + return; + } + +reset: + rcu_read_unlock(); + +reset_wl: + if (qdf_unlikely(qdf_atomic_read(&adapter->gro_disallowed))) { + hdd_debug("ingress qdisc/filter removed enable GRO"); + qdf_atomic_set(&adapter->gro_disallowed, 0); + } +} +#else +static inline void +hdd_rx_check_qdisc_for_adapter(struct hdd_adapter *adapter) +{ +} +#endif + static void __hdd_bus_bw_work_handler(struct hdd_context *hdd_ctx) { struct hdd_adapter *adapter = NULL, *next_adapter = NULL, @@ -10630,6 +10796,9 @@ static void __hdd_bus_bw_work_handler(struct hdd_context *hdd_ctx) continue; } + if (hdd_ctx->dp_agg_param.tc_based_dyn_gro) + hdd_rx_check_qdisc_for_adapter(adapter); + tx_packets += HDD_BW_GET_DIFF(adapter->stats.tx_packets, adapter->prev_tx_packets); rx_packets += HDD_BW_GET_DIFF(adapter->stats.rx_packets, @@ -11759,6 +11928,7 @@ static void hdd_init_channel_avoidance(struct hdd_context *hdd_ctx) { uint16_t unsafe_channel_count; int index; + qdf_freq_t *unsafe_freq_list; pld_get_wlan_unsafe_channel(hdd_ctx->parent_dev, hdd_ctx->unsafe_channel_list, @@ -11771,16 +11941,25 @@ static void hdd_init_channel_avoidance(struct hdd_context *hdd_ctx) unsafe_channel_count = QDF_MIN((uint16_t)hdd_ctx->unsafe_channel_count, (uint16_t)NUM_CHANNELS); + unsafe_freq_list = qdf_mem_malloc( + unsafe_channel_count * sizeof(*unsafe_freq_list)); + + if (!unsafe_freq_list) + return; + for (index = 0; index < unsafe_channel_count; index++) { hdd_debug("channel frequency %d is not safe", hdd_ctx->unsafe_channel_list[index]); - + unsafe_freq_list[index] = + (qdf_freq_t)hdd_ctx->unsafe_channel_list[index]; } ucfg_policy_mgr_init_chan_avoidance( hdd_ctx->psoc, - (qdf_freq_t *)hdd_ctx->unsafe_channel_list, - hdd_ctx->unsafe_channel_count); + unsafe_freq_list, + unsafe_channel_count); + + qdf_mem_free(unsafe_freq_list); } static void hdd_lte_coex_restart_sap(struct hdd_adapter *adapter, @@ -16627,6 +16806,36 @@ void hdd_init_start_completion(void) INIT_COMPLETION(wlan_start_comp); } +#if defined CFG80211_USER_HINT_CELL_BASE_SELF_MANAGED || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)) +static void hdd_inform_wifi_on(void) +{ + int ret; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct osif_psoc_sync *psoc_sync; + + hdd_nofl_debug("inform regdomain for wifi on"); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return; + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return; + if (!hdd_ctx->wiphy) + return; + ret = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + if (ret) + return; + if (hdd_ctx->wiphy->registered) + hdd_send_wiphy_regd_sync_event(hdd_ctx); + + osif_psoc_sync_op_stop(psoc_sync); +} +#else +static void hdd_inform_wifi_on(void) +{ +} +#endif + static ssize_t wlan_hdd_state_ctrl_param_write(struct file *filp, const char __user *user_buf, size_t count, @@ -16638,6 +16847,7 @@ static ssize_t wlan_hdd_state_ctrl_param_write(struct file *filp, int ret; unsigned long rc; struct hdd_context *hdd_ctx; + bool turning_on = false; if (copy_from_user(buf, user_buf, 3)) { pr_err("Failed to read buffer\n"); @@ -16645,13 +16855,15 @@ static ssize_t wlan_hdd_state_ctrl_param_write(struct file *filp, } if (strncmp(buf, wlan_off_str, strlen(wlan_off_str)) == 0) { - pr_debug("Wifi turning off from UI\n"); + hdd_info("Wifi turning off from UI\n"); hdd_inform_wifi_off(); goto exit; } - if (strncmp(buf, wlan_on_str, strlen(wlan_on_str)) == 0) - pr_info("Wifi Turning On from UI\n"); + if (strncmp(buf, wlan_on_str, strlen(wlan_on_str)) == 0) { + hdd_info("Wifi Turning On from UI\n"); + turning_on = true; + } if (strncmp(buf, wlan_on_str, strlen(wlan_on_str)) != 0) { pr_err("Invalid value received from framework"); @@ -16675,8 +16887,10 @@ static ssize_t wlan_hdd_state_ctrl_param_write(struct file *filp, hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); if (hdd_ctx) hdd_psoc_idle_timer_stop(hdd_ctx); - exit: + if (turning_on) + hdd_inform_wifi_on(); + return count; } diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index 8aaf52f32abb..45266d6e689d 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -88,6 +88,7 @@ #include "wlan_hdd_object_manager.h" #include #include "qdf_types.h" +#include /* Preprocessor definitions and constants */ #ifdef QCA_WIFI_NAPIER_EMULATION #define HDD_SSR_BRING_UP_TIME 3000000 @@ -2916,6 +2917,7 @@ static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, int status; struct hdd_station_ctx *sta_ctx; static bool is_rate_limited; + struct wlan_objmgr_vdev *vdev; hdd_enter_dev(ndev); @@ -2967,7 +2969,13 @@ static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, is_rate_limited) { hdd_debug("Modules not enabled/rate limited, use cached stats"); /* Send cached data to upperlayer*/ - *dbm = adapter->hdd_stats.class_a_stat.max_pwr; + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) { + hdd_err("vdev is NULL"); + return -EINVAL; + } + ucfg_mc_cp_stats_get_tx_power(vdev, dbm); + hdd_objmgr_put_vdev(vdev); return 0; } diff --git a/core/hdd/src/wlan_hdd_twt.c b/core/hdd/src/wlan_hdd_twt.c index 05977120b16e..14a03fcced35 100644 --- a/core/hdd/src/wlan_hdd_twt.c +++ b/core/hdd/src/wlan_hdd_twt.c @@ -2728,22 +2728,25 @@ static int hdd_twt_pause_session(struct hdd_adapter *adapter, qdf_mem_copy(params.peer_macaddr, hdd_sta_ctx->conn_info.bssid.bytes, QDF_MAC_ADDR_SIZE); params.vdev_id = adapter->vdev_id; + params.dialog_id = 0; - ret = wlan_cfg80211_nla_parse_nested(tb, + if (twt_param_attr) { + ret = wlan_cfg80211_nla_parse_nested(tb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, twt_param_attr, qca_wlan_vendor_twt_add_dialog_policy); - if (ret) { - hdd_debug("command parsing failed"); - return ret; - } + if (ret) { + hdd_debug("command parsing failed"); + return ret; + } - id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; - if (tb[id]) { - params.dialog_id = nla_get_u8(tb[id]); + id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (tb[id]) + params.dialog_id = nla_get_u8(tb[id]); + else + hdd_debug("TWT: FLOW_ID not specified. set to zero"); } else { - params.dialog_id = 0; - hdd_debug("TWT: FLOW_ID not specified. set to zero"); + hdd_debug("TWT param not present. flow id set to zero"); } status = hdd_twt_check_all_twt_support(adapter->hdd_ctx->psoc, @@ -3877,7 +3880,8 @@ static int hdd_twt_configure(struct hdd_adapter *adapter, twt_param_attr = tb[id]; if (!twt_param_attr && - twt_oper != QCA_WLAN_TWT_GET_CAPABILITIES) { + twt_oper != QCA_WLAN_TWT_GET_CAPABILITIES && + twt_oper != QCA_WLAN_TWT_SUSPEND) { hdd_err("TWT parameters NOT specified"); return -EINVAL; } diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c index f7e49376ac57..f4ffa2002ce9 100644 --- a/core/hdd/src/wlan_hdd_tx_rx.c +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -1678,8 +1678,10 @@ static QDF_STATUS hdd_gro_rx_bh_disable(struct hdd_adapter *adapter, gro_result_t gro_ret; uint32_t rx_aggregation; uint8_t rx_ctx_id = QDF_NBUF_CB_RX_CTX_ID(skb); + int32_t gro_disallowed; rx_aggregation = qdf_atomic_read(&hdd_ctx->dp_agg_param.rx_aggregation); + gro_disallowed = qdf_atomic_read(&adapter->gro_disallowed); skb_set_hash(skb, QDF_NBUF_CB_RX_FLOW_ID(skb), PKT_HASH_TYPE_L4); @@ -1687,7 +1689,7 @@ static QDF_STATUS hdd_gro_rx_bh_disable(struct hdd_adapter *adapter, gro_ret = napi_gro_receive(napi_to_use, skb); if (hdd_get_current_throughput_level(hdd_ctx) == PLD_BUS_WIDTH_IDLE || - !rx_aggregation || adapter->gro_disallowed[rx_ctx_id]) { + !rx_aggregation || gro_disallowed) { if (HDD_IS_EXTRA_GRO_FLUSH_NECESSARY(gro_ret)) { adapter->hdd_stats.tx_rx_stats. rx_gro_low_tput_flush++; @@ -1696,7 +1698,7 @@ static QDF_STATUS hdd_gro_rx_bh_disable(struct hdd_adapter *adapter, } if (!rx_aggregation) hdd_ctx->dp_agg_param.gro_force_flush[rx_ctx_id] = 1; - if (adapter->gro_disallowed[rx_ctx_id]) + if (gro_disallowed) adapter->gro_flushed[rx_ctx_id] = 1; } local_bh_enable(); @@ -2153,6 +2155,7 @@ QDF_STATUS hdd_rx_deliver_to_stack(struct hdd_adapter *adapter, } #else +#ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION #if defined(WLAN_SUPPORT_RX_FISA) /** * hdd_set_fisa_disallowed_for_vdev() - Set fisa disallowed bit for a vdev @@ -2179,97 +2182,6 @@ void hdd_set_fisa_disallowed_for_vdev(ol_txrx_soc_handle soc, uint8_t vdev_id, } #endif -#ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION -/** - * hdd_is_chain_list_non_empty_for_clsact_qdisc() - Check if chain_list in - * ingress block is non-empty for a clsact qdisc. - * @qdisc: pointer to clsact qdisc - * - * Return: true if chain_list is not empty else false - */ -static bool -hdd_is_chain_list_non_empty_for_clsact_qdisc(struct Qdisc *qdisc) -{ - const struct Qdisc_class_ops *cops; - struct tcf_block *ingress_block; - - cops = qdisc->ops->cl_ops; - if (qdf_unlikely(!cops || !cops->tcf_block)) - return false; - - ingress_block = cops->tcf_block(qdisc, TC_H_MIN_INGRESS, NULL); - if (qdf_unlikely(!ingress_block)) - return false; - - if (list_empty(&ingress_block->chain_list)) - return false; - else - return true; -} - -/** - * hdd_rx_check_qdisc_for_adapter() - Check if any ingress qdisc is configured - * for given adapter - * @adapter: pointer to HDD adapter context - * @rx_ctx_id: Rx context id - * - * The function checks if ingress qdisc is registered for a given - * net device. - * - * Return: None - */ -static void -hdd_rx_check_qdisc_for_adapter(struct hdd_adapter *adapter, uint8_t rx_ctx_id) -{ - ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); - struct netdev_queue *ingress_q; - struct Qdisc *ingress_qdisc; - - if (qdf_unlikely(!soc)) - return; - - if (!adapter->dev->ingress_queue) - goto reset_wl; - - rcu_read_lock(); - - ingress_q = rcu_dereference(adapter->dev->ingress_queue); - if (qdf_unlikely(!ingress_q)) - goto reset; - - ingress_qdisc = rcu_dereference(ingress_q->qdisc); - if (qdf_unlikely(!ingress_qdisc)) - goto reset; - - if (!(qdf_str_eq(ingress_qdisc->ops->id, "ingress") || - (qdf_str_eq(ingress_qdisc->ops->id, "clsact") && - hdd_is_chain_list_non_empty_for_clsact_qdisc(ingress_qdisc)))) - goto reset; - - rcu_read_unlock(); - - if (qdf_likely(adapter->gro_disallowed[rx_ctx_id])) - return; - - hdd_debug("ingress qdisc/filter configured disable GRO"); - adapter->gro_disallowed[rx_ctx_id] = 1; - hdd_set_fisa_disallowed_for_vdev(soc, adapter->vdev_id, rx_ctx_id, 1); - - return; - -reset: - rcu_read_unlock(); - -reset_wl: - if (qdf_unlikely(adapter->gro_disallowed[rx_ctx_id])) { - hdd_debug("ingress qdisc/filter removed enable GRO"); - hdd_set_fisa_disallowed_for_vdev(soc, adapter->vdev_id, - rx_ctx_id, 0); - adapter->gro_disallowed[rx_ctx_id] = 0; - adapter->gro_flushed[rx_ctx_id] = 0; - } -} - QDF_STATUS hdd_rx_deliver_to_stack(struct hdd_adapter *adapter, struct sk_buff *skb) { @@ -2278,15 +2190,25 @@ QDF_STATUS hdd_rx_deliver_to_stack(struct hdd_adapter *adapter, int netif_status; bool skb_receive_offload_ok = false; uint8_t rx_ctx_id = QDF_NBUF_CB_RX_CTX_ID(skb); - - if (!hdd_ctx->dp_agg_param.force_gro_enable) - /* rx_ctx_id is already verified for out-of-range */ - hdd_rx_check_qdisc_for_adapter(adapter, rx_ctx_id); + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); if (QDF_NBUF_CB_RX_TCP_PROTO(skb) && !QDF_NBUF_CB_RX_PEER_CACHED_FRM(skb)) skb_receive_offload_ok = true; + if (qdf_atomic_read(&adapter->gro_disallowed) == 0 && + adapter->gro_flushed[rx_ctx_id] != 0) { + if (qdf_likely(soc)) + hdd_set_fisa_disallowed_for_vdev(soc, adapter->vdev_id, + rx_ctx_id, 0); + adapter->gro_flushed[rx_ctx_id] = 0; + } else if (qdf_atomic_read(&adapter->gro_disallowed) && + adapter->gro_flushed[rx_ctx_id] == 0) { + if (qdf_likely(soc)) + hdd_set_fisa_disallowed_for_vdev(soc, adapter->vdev_id, + rx_ctx_id, 1); + } + if (skb_receive_offload_ok && hdd_ctx->receive_offload_cb && !hdd_ctx->dp_agg_param.gro_force_flush[rx_ctx_id] && !adapter->gro_flushed[rx_ctx_id] && diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h index 0dd5d8d1ecad..c10903319e19 100644 --- a/core/mac/inc/qwlan_version.h +++ b/core/mac/inc/qwlan_version.h @@ -32,9 +32,9 @@ #define QWLAN_VERSION_MAJOR 2 #define QWLAN_VERSION_MINOR 0 #define QWLAN_VERSION_PATCH 8 -#define QWLAN_VERSION_EXTRA "J" -#define QWLAN_VERSION_BUILD 30 +#define QWLAN_VERSION_EXTRA "" +#define QWLAN_VERSION_BUILD 31 -#define QWLAN_VERSIONSTR "2.0.8.30J" +#define QWLAN_VERSIONSTR "2.0.8.31" #endif /* QWLAN_VERSION_H */ diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index 07bfe3bb0e91..a595bb0f2cec 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -482,6 +482,9 @@ struct sme_ready_req { uint16_t deauth_disassoc_frame_len, uint16_t reason_code); csr_roam_pmkid_req_fn_t csr_roam_pmkid_req_cb; + QDF_STATUS (*csr_roam_candidate_event_cb)(struct mac_context *mac, + uint8_t *frame, + uint32_t len); }; /** @@ -2929,6 +2932,18 @@ struct roam_offload_synch_ind { enum wlan_phymode phy_mode; /*phy mode sent by fw */ }; +/* + * struct roam_scan_candidate_frame Roam candidate scan entry + * vdev_id : vdev id + * frame_len : Length of the beacon/probe rsp frame + * frame : Pointer to the frame + */ +struct roam_scan_candidate_frame { + uint8_t vdev_id; + uint32_t frame_length; + uint8_t *frame; +}; + #ifdef WLAN_FEATURE_ROAM_OFFLOAD struct handoff_failure_ind { uint8_t vdev_id; diff --git a/core/mac/src/pe/lim/lim_api.c b/core/mac/src/pe/lim/lim_api.c index 4872771f9eee..7433c5275baa 100644 --- a/core/mac/src/pe/lim/lim_api.c +++ b/core/mac/src/pe/lim/lim_api.c @@ -1356,7 +1356,8 @@ void pe_register_callbacks_with_wma(struct mac_context *mac, ready_req->csr_roam_auth_event_handle_cb, ready_req->pe_roam_synch_cb, ready_req->pe_disconnect_cb, - ready_req->csr_roam_pmkid_req_cb); + ready_req->csr_roam_pmkid_req_cb, + ready_req->csr_roam_candidate_event_cb); if (status != QDF_STATUS_SUCCESS) pe_err("Registering roaming callbacks with WMA failed"); } diff --git a/core/mac/src/pe/lim/lim_process_action_frame.c b/core/mac/src/pe/lim/lim_process_action_frame.c index 5fc20c00966a..1a683db31d7d 100644 --- a/core/mac/src/pe/lim/lim_process_action_frame.c +++ b/core/mac/src/pe/lim/lim_process_action_frame.c @@ -1552,7 +1552,7 @@ static void lim_process_delba_req(struct mac_context *mac_ctx, uint8_t *rx_pkt_i body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); - QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, body_ptr, frame_len); delba_req = qdf_mem_malloc(sizeof(*delba_req)); @@ -1576,7 +1576,7 @@ static void lim_process_delba_req(struct mac_context *mac_ctx, uint8_t *rx_pkt_i delba_req->delba_param_set.tid, delba_req->Reason.code); if (QDF_STATUS_SUCCESS != qdf_status) - pe_err("Failed to process delba request"); + pe_err_rl("Failed to process delba request"); error: qdf_mem_free(delba_req); diff --git a/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/core/mac/src/pe/lim/lim_process_sme_req_messages.c index ce80d5eafa6b..dc64531f28ca 100644 --- a/core/mac/src/pe/lim/lim_process_sme_req_messages.c +++ b/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -2081,6 +2081,12 @@ void lim_calculate_tpc(struct mac_context *mac, session->ch_width); } + if (num_pwr_levels > MAX_NUM_PWR_LEVELS) { + pe_debug("reset num_pwr_levels %d to MAX_NUM_PWR_LEVELS %d", + num_pwr_levels, MAX_NUM_PWR_LEVELS); + num_pwr_levels = MAX_NUM_PWR_LEVELS; + } + ch_params.ch_width = CH_WIDTH_20MHZ; for (i = 0; i < num_pwr_levels; i++) { diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h index 93921bdf09db..6126ac888c27 100644 --- a/core/mac/src/pe/lim/lim_utils.h +++ b/core/mac/src/pe/lim/lim_utils.h @@ -105,6 +105,12 @@ typedef enum { #define MAX_WAIT_FOR_BCN_TX_COMPLETE 4000 #define MAX_WAKELOCK_FOR_CSA 5000 +#ifdef WLAN_FEATURE_11BE +#define MAX_NUM_PWR_LEVELS 16 +#else +#define MAX_NUM_PWR_LEVELS 8 +#endif + #ifdef WLAN_FEATURE_11W typedef union uPmfSaQueryTimerId { struct { diff --git a/core/mac/src/pe/sch/sch_api.c b/core/mac/src/pe/sch/sch_api.c index ecbd7ae692ed..7b51fae0dcca 100644 --- a/core/mac/src/pe/sch/sch_api.c +++ b/core/mac/src/pe/sch/sch_api.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 @@ -364,52 +365,51 @@ uint32_t lim_send_probe_rsp_template_to_hal(struct mac_context *mac, * @timestamp_offset: return for the offset of the timestamp field * @time_value_offset: return for the time_value field in the TA IE * - * Return: the length of the buffer. + * Return: the length of the buffer on success and error code on failure. */ int sch_gen_timing_advert_frame(struct mac_context *mac_ctx, tSirMacAddr self_addr, uint8_t **buf, uint32_t *timestamp_offset, uint32_t *time_value_offset) { - tDot11fTimingAdvertisementFrame frame; + tDot11fTimingAdvertisementFrame frame = {}; uint32_t payload_size, buf_size; - int status; + QDF_STATUS status; + uint32_t ret; struct qdf_mac_addr wildcard_bssid = { {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, }; - qdf_mem_zero((uint8_t *)&frame, sizeof(tDot11fTimingAdvertisementFrame)); - /* Populate the TA fields */ status = populate_dot11f_timing_advert_frame(mac_ctx, &frame); - if (status) { + if (!QDF_IS_STATUS_SUCCESS(status)) { pe_err("Error populating TA frame %x", status); - return status; + return qdf_status_to_os_return(status); } - status = dot11f_get_packed_timing_advertisement_frame_size(mac_ctx, + ret = dot11f_get_packed_timing_advertisement_frame_size(mac_ctx, &frame, &payload_size); - if (DOT11F_FAILED(status)) { - pe_err("Error getting packed frame size %x", status); - return status; - } else if (DOT11F_WARNED(status)) { - pe_warn("Warning getting packed frame size"); + if (DOT11F_FAILED(ret)) { + pe_err("Error getting packed frame size %x", ret); + return -EINVAL; } + if (DOT11F_WARNED(ret)) + pe_warn("Warning getting packed frame size"); buf_size = sizeof(tSirMacMgmtHdr) + payload_size; *buf = qdf_mem_malloc(buf_size); if (!*buf) - return QDF_STATUS_E_FAILURE; + return -ENOMEM; payload_size = 0; - status = dot11f_pack_timing_advertisement_frame(mac_ctx, &frame, + ret = dot11f_pack_timing_advertisement_frame(mac_ctx, &frame, *buf + sizeof(tSirMacMgmtHdr), buf_size - sizeof(tSirMacMgmtHdr), &payload_size); - pe_err("TA payload size2 = %d", payload_size); - if (DOT11F_FAILED(status)) { - pe_err("Error packing frame %x", status); + pe_debug("TA payload size2 = %d", payload_size); + if (DOT11F_FAILED(ret)) { + pe_err("Error packing frame %x", ret); goto fail; - } else if (DOT11F_WARNED(status)) { - pe_warn("Warning packing frame"); } + if (DOT11F_WARNED(ret)) + pe_warn("Warning packing frame"); lim_populate_mac_header(mac_ctx, *buf, SIR_MAC_MGMT_FRAME, SIR_MAC_MGMT_TIME_ADVERT, wildcard_bssid.bytes, self_addr); @@ -436,7 +436,7 @@ int sch_gen_timing_advert_frame(struct mac_context *mac_ctx, tSirMacAddr self_ad return payload_size + sizeof(tSirMacMgmtHdr); fail: - if (*buf) - qdf_mem_free(*buf); - return status; + qdf_mem_free(*buf); + *buf = NULL; + return -EINVAL; } diff --git a/core/sme/inc/csr_neighbor_roam.h b/core/sme/inc/csr_neighbor_roam.h index b2d6df7da07b..9c1b0e2cb8bf 100644 --- a/core/sme/inc/csr_neighbor_roam.h +++ b/core/sme/inc/csr_neighbor_roam.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 @@ -380,6 +381,7 @@ QDF_STATUS csr_process_roam_pmkid_req_callback(struct mac_context *mac_ctx, uint8_t vdev_id, struct roam_pmkid_req_event *roam_bsslist); + #else static inline QDF_STATUS csr_roam_pmkid_req_callback(uint8_t vdev_id, @@ -388,7 +390,9 @@ csr_roam_pmkid_req_callback(uint8_t vdev_id, return QDF_STATUS_SUCCESS; } #endif /* WLAN_FEATURE_FIPS */ - +QDF_STATUS +csr_roam_candidate_event_handle_callback(struct mac_context *mac_ctx, + uint8_t *frame, uint32_t len); #else static inline QDF_STATUS csr_roam_synch_callback(struct mac_context *mac, struct roam_offload_synch_ind *roam_synch_data, @@ -420,6 +424,13 @@ csr_roam_pmkid_req_callback(uint8_t vdev_id, { return QDF_STATUS_E_NOSUPPORT; } + +QDF_STATUS +csr_roam_candidate_event_handle_callback(struct mac_context *mac_ctx, + uint8_t *frame, uint32_t len) +{ + return QDF_STATUS_SUCCESS; +} #endif void csr_neighbor_roam_state_transition(struct mac_context *mac_ctx, uint8_t newstate, uint8_t session); diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index cef5746de8bf..45317a06e359 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -1185,6 +1185,8 @@ QDF_STATUS sme_hdd_ready_ind(mac_handle_t mac_handle) msg->csr_roam_auth_event_handle_cb = csr_roam_auth_offload_callback; msg->csr_roam_pmkid_req_cb = csr_roam_pmkid_req_callback; + msg->csr_roam_candidate_event_cb = + csr_roam_candidate_event_handle_callback; status = u_mac_post_ctrl_msg(mac_handle, (tSirMbMsg *)msg); if (QDF_IS_STATUS_ERROR(status)) { @@ -8669,7 +8671,7 @@ void sme_get_command_q_status(mac_handle_t mac_handle) * @timestamp_offset: return for the offset of the timestamp field * @time_value_offset: return for the time_value field in the TA IE * - * Return: the length of the buffer. + * Return: the length of the buffer on success and error code on failure. */ int sme_ocb_gen_timing_advert_frame(mac_handle_t mac_handle, tSirMacAddr self_addr, uint8_t **buf, diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index 185db6359ad4..2d5aaeb43567 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -5028,10 +5028,16 @@ QDF_STATUS csr_roam_stop_network(struct mac_context *mac, uint32_t sessionId, ssid_match = csr_is_ssid_equal( mac, pSession->pConnectBssDesc, bss_desc, pIes); - if (bss_desc && !ssid_match) - status = csr_roam_issue_disassociate(mac, - sessionId, substate, false); - else if (bss_desc) + if (bss_desc && !ssid_match) { + csr_roam_issue_disassociate(mac, + sessionId, substate, + false); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(pBssConfig); + + return status; + + } else if (bss_desc) { /* * In an infra & going to an infra network with * the same SSID. This calls for a reassoc seq. @@ -5042,6 +5048,7 @@ QDF_STATUS csr_roam_stop_network(struct mac_context *mac, uint32_t sessionId, mac, sessionId, roam_profile, bss_desc, pBssConfig, pIes, false); + } } else if (bss_desc || CSR_IS_INFRA_AP(roam_profile)) { /* * Not in Infra. We can go ahead and set @@ -15706,6 +15713,17 @@ QDF_STATUS csr_send_join_req_msg(struct mac_context *mac, uint32_t sessionId, bss_freq, mac->mlme_cfg->ht_caps. ht_cap_info.adv_coding_cap); + + if (pProfile->csrPersona == QDF_STA_MODE) { + if (pSession->ht_config.ht_sgi20) + pSession->ht_config.ht_sgi20 = + pIes->HTCaps.shortGI20MHz; + + if (pSession->ht_config.ht_sgi40) + pSession->ht_config.ht_sgi40 = + pIes->HTCaps.shortGI40MHz; + } + csr_join_req->ht_config = pSession->ht_config; csr_join_req->vht_config = pSession->vht_config; sme_debug("ht capability 0x%x VHT capability 0x%x", @@ -21938,6 +21956,128 @@ csr_roam_auth_offload_callback(struct mac_context *mac_ctx, return status; } + +static +void csr_inform_bcn_probe(struct mac_context *mac_ctx, + uint8_t *frame, uint32_t len, + qdf_freq_t freq) +{ + qdf_nbuf_t buf; + uint8_t *data, i; + struct mgmt_rx_event_params rx_param = {0}; + struct wlan_frame_hdr *hdr; + enum mgmt_frame_type frm_type = MGMT_BEACON; + + hdr = (struct wlan_frame_hdr *)frame; + + if ((hdr->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_MASK) == + MGMT_SUBTYPE_PROBE_RESP) + frm_type = MGMT_PROBE_RESP; + + rx_param.pdev_id = 0; + rx_param.chan_freq = freq; + /* Real RSSI will be filled after roam sync */ + rx_param.rssi = 0; + + /* Set all per chain rssi as invalid */ + for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++) + rx_param.rssi_ctl[i] = WLAN_INVALID_PER_CHAIN_RSSI; + + buf = qdf_nbuf_alloc(NULL, qdf_roundup(len, 4), 0, 4, false); + if (!buf) + return; + + qdf_nbuf_put_tail(buf, len); + qdf_nbuf_set_protocol(buf, ETH_P_CONTROL); + + data = qdf_nbuf_data(buf); + qdf_mem_copy(data, frame, len); + /* buf will be freed by scan module in error or success case */ + wlan_scan_process_bcn_probe_rx_sync(wlan_pdev_get_psoc(mac_ctx->pdev), + buf, &rx_param, frm_type); +} + +QDF_STATUS +csr_roam_candidate_event_handle_callback(struct mac_context *mac_ctx, + uint8_t *frame, uint32_t len) +{ + uint32_t ie_offset, ie_len; + uint8_t *ie_ptr = NULL; + uint8_t *extracted_ie = NULL; + uint8_t primary_channel, band; + qdf_freq_t op_freq; + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLME, QDF_TRACE_LEVEL_DEBUG, + frame, len); + + /* Fixed parameters offset */ + ie_offset = sizeof(struct wlan_frame_hdr) + SIR_MAC_B_PR_SSID_OFFSET; + + if (len <= ie_offset) { + mlme_err("Invalid frame length"); + return QDF_STATUS_E_FAILURE; + } + + ie_ptr = frame + ie_offset; + ie_len = len - ie_offset; + + /* For 2.4GHz,5GHz get channel from DS IE */ + extracted_ie = (uint8_t *)wlan_get_ie_ptr_from_eid(WLAN_ELEMID_DSPARMS, + ie_ptr, ie_len); + + if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_DSPARMS && + extracted_ie[1] == WLAN_DS_PARAM_IE_MAX_LEN) { + band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G); + primary_channel = *(extracted_ie + 2); + sme_debug("Extracted primary channel from DS : %d", + primary_channel); + goto update_beacon; + } + + /* For HT, VHT and non-6GHz HE, get channel from HTINFO IE */ + extracted_ie = (uint8_t *) + wlan_get_ie_ptr_from_eid(WLAN_ELEMID_HTINFO_ANA, + ie_ptr, ie_len); + if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_HTINFO_ANA && + extracted_ie[1] == sizeof(struct wlan_ie_htinfo_cmn)) { + band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G); + primary_channel = + ((struct wlan_ie_htinfo *)extracted_ie)-> + hi_ie.hi_ctrlchannel; + sme_debug("Extracted primary channel from HT INFO : %d", + primary_channel); + goto update_beacon; + } + + /* For 6GHz, get channel from HE OP IE */ + extracted_ie = (uint8_t *) + wlan_get_ext_ie_ptr_from_ext_id(WLAN_HEOP_OUI_TYPE, + (uint8_t) + WLAN_HEOP_OUI_SIZE, + ie_ptr, ie_len); + + if (extracted_ie && + !qdf_mem_cmp(&extracted_ie[2], WLAN_HEOP_OUI_TYPE, + WLAN_HEOP_OUI_SIZE) && + extracted_ie[1] <= WLAN_MAX_HEOP_IE_LEN) { + band = BIT(REG_BAND_6G); + primary_channel = util_scan_get_6g_oper_channel(extracted_ie); + sme_debug("Extracted primary channel from HE OP : %d", + primary_channel); + if (primary_channel) + goto update_beacon; + } + + mlme_err("Primary channel was not found in the candidate scan entry"); + return QDF_STATUS_E_FAILURE; + +update_beacon: + op_freq = wlan_reg_chan_band_to_freq(mac_ctx->pdev, + primary_channel, band); + sme_debug("Roaming candidate frequency : %d", op_freq); + csr_inform_bcn_probe(mac_ctx, frame, len, op_freq); + return QDF_STATUS_SUCCESS; +} #endif QDF_STATUS csr_update_owe_info(struct mac_context *mac, diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 8821fa6995a0..5474fe767d0f 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -1012,6 +1012,9 @@ typedef struct { uint16_t reason_code); QDF_STATUS (*csr_roam_pmkid_req_cb)(uint8_t vdev_id, struct roam_pmkid_req_event *bss_list); + QDF_STATUS (*csr_roam_candidate_event_cb)(struct mac_context *mac, + uint8_t *frame, + uint32_t len); qdf_wake_lock_t wmi_cmd_rsp_wake_lock; qdf_runtime_lock_t wmi_cmd_rsp_runtime_lock; qdf_runtime_lock_t sap_prevent_runtime_pm_lock; diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index 40fda877feca..1d7f88d5392c 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -312,6 +312,17 @@ void wma_report_real_time_roam_stats(struct wlan_objmgr_psoc *psoc, enum roam_rt_stats_type events, struct mlme_roam_debug_info *roam_info, uint32_t value, uint32_t reason); + +/** + * wma_roam_candidate_frame_event_handler - Handles wma roam frame event id + * @handle: wma_handle + * @event: event data + * @len: length of the data + * + *Return: Success or Failure status + */ +int wma_roam_candidate_frame_event_handler(void *handle, uint8_t *event, + uint32_t len); #else static inline int wma_mlme_roam_synch_event_handler_cb(void *handle, uint8_t *event, diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h index 7a298bf070b7..62b4c204756c 100644 --- a/core/wma/inc/wma_types.h +++ b/core/wma/inc/wma_types.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. 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 @@ -738,7 +738,10 @@ QDF_STATUS wma_register_roaming_callbacks( uint8_t *deauth_disassoc_frame, uint16_t deauth_disassoc_frame_len, uint16_t reason_code), - csr_roam_pmkid_req_fn_t csr_roam_pmkid_req_cb); + csr_roam_pmkid_req_fn_t csr_roam_pmkid_req_cb, + QDF_STATUS (*csr_roam_candidate_event_cb)(struct mac_context *mac, + uint8_t *frame, + uint32_t len)); #else static inline QDF_STATUS wma_register_roaming_callbacks( csr_roam_synch_fn_t csr_roam_synch_cb, @@ -752,7 +755,10 @@ static inline QDF_STATUS wma_register_roaming_callbacks( uint8_t *deauth_disassoc_frame, uint16_t deauth_disassoc_frame_len, uint16_t reason_code), - csr_roam_pmkid_req_fn_t csr_roam_pmkid_req_cb) + csr_roam_pmkid_req_fn_t csr_roam_pmkid_req_cb, + QDF_STATUS (*csr_roam_candidate_event_cb)(struct mac_context *mac, + uint8_t *frame, + uint32_t len)) { return QDF_STATUS_E_NOSUPPORT; } diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 9261497cbdf6..dbe8e0275ca2 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -3413,6 +3413,11 @@ QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, wma_roam_vdev_disconnect_event_handler, WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_roam_frame_event_id, + wma_roam_candidate_frame_event_handler, + WMA_RX_SERIALIZER_CTX); + #endif /* WLAN_FEATURE_ROAM_OFFLOAD */ wmi_unified_register_event_handler(wma_handle->wmi_handle, wmi_rssi_breach_event_id, @@ -9296,6 +9301,7 @@ QDF_STATUS wma_send_set_pcl_cmd(tp_wma_handle wma_handle, { uint32_t i; QDF_STATUS status; + bool is_channel_allowed; if (!wma_handle) { wma_err("WMA handle is NULL. Cannot issue command"); @@ -9338,6 +9344,14 @@ QDF_STATUS wma_send_set_pcl_cmd(tp_wma_handle wma_handle, msg->chan_weights.saved_chan_list[i])) msg->chan_weights.weighed_valid_list[i] = WEIGHT_OF_DISALLOWED_CHANNELS; + + is_channel_allowed = + policy_mgr_is_sta_chan_valid_for_connect_and_roam( + wma_handle->pdev, + msg->chan_weights.saved_chan_list[i]); + if (!is_channel_allowed) + msg->chan_weights.weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; } if (!QDF_IS_STATUS_SUCCESS(status)) { diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c index aa3b23e4087d..e6136508c682 100644 --- a/core/wma/src/wma_mgmt.c +++ b/core/wma/src/wma_mgmt.c @@ -3699,6 +3699,8 @@ QDF_STATUS wma_de_register_mgmt_frm_client(void) * @pe_roam_synch_cb: PE roam synch callback routine pointer * @csr_roam_auth_event_handle_cb: CSR callback routine pointer * @csr_roam_pmkid_req_cb: CSR roam pmkid callback routine pointer + * @csr_roam_candidate_event_handle_cb: CSR roam candidate callback + * routine pointer * * Register the SME and PE callback routines with WMA for * handling roaming @@ -3716,7 +3718,9 @@ QDF_STATUS wma_register_roaming_callbacks( uint8_t *deauth_disassoc_frame, uint16_t deauth_disassoc_frame_len, uint16_t reason_code), - csr_roam_pmkid_req_fn_t csr_roam_pmkid_req_cb) + csr_roam_pmkid_req_fn_t csr_roam_pmkid_req_cb, + QDF_STATUS (*csr_roam_candidate_event_cb)(struct mac_context *mac, + uint8_t *frame, uint32_t len)) { tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); @@ -3729,6 +3733,8 @@ QDF_STATUS wma_register_roaming_callbacks( wma->csr_roam_auth_event_handle_cb = csr_roam_auth_event_handle_cb; wma->pe_roam_synch_cb = pe_roam_synch_cb; wma->pe_disconnect_cb = pe_disconnect_cb; + wma->csr_roam_candidate_event_cb = + csr_roam_candidate_event_cb; wma_debug("Registered roam synch callbacks with WMA successfully"); wma->csr_roam_pmkid_req_cb = csr_roam_pmkid_req_cb; diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c index ce2d886c0e6d..63cc777ef924 100644 --- a/core/wma/src/wma_scan_roam.c +++ b/core/wma/src/wma_scan_roam.c @@ -2611,6 +2611,72 @@ int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event, err: return -EINVAL; } + +int wma_roam_candidate_frame_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_ROAM_FRAME_EVENTID_param_tlvs *param_buf = NULL; + wmi_roam_frame_event_fixed_param *frame_params = NULL; + struct roam_scan_candidate_frame *data; + struct mac_context *mac_ctx; + QDF_STATUS status; + + if (!event || !len) { + wma_err("Empty roam candidate frame event"); + return QDF_STATUS_E_FAILURE; + } + + param_buf = (WMI_ROAM_FRAME_EVENTID_param_tlvs *)event; + if (!param_buf) { + wma_err("Received null buf from target"); + return -EINVAL; + } + + frame_params = + (wmi_roam_frame_event_fixed_param *)param_buf->fixed_param; + + if (!wma_is_vdev_valid(frame_params->vdev_id)) { + wma_err("Invalid vdev id %d", frame_params->vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (frame_params->frame_length > param_buf->num_frame) { + wma_err("Invalid frame length %d expected : %d", + frame_params->frame_length, + param_buf->num_frame); + return QDF_STATUS_E_FAILURE; + } + + if (!param_buf->frame) { + wmi_err("Frame pointer is Null"); + return QDF_STATUS_E_FAILURE; + } + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac_ctx) { + wma_err("NULL mac ptr"); + QDF_ASSERT(0); + return -EINVAL; + } + + data = qdf_mem_malloc(sizeof(*data)); + + if (!data) + return -ENOMEM; + + data->vdev_id = frame_params->vdev_id; + data->frame_length = frame_params->frame_length; + data->frame = (uint8_t *)param_buf->frame; + + status = wma->csr_roam_candidate_event_cb(mac_ctx, data->frame, + data->frame_length); + qdf_mem_free(data); + + return QDF_STATUS_SUCCESS; +} + #endif /**