summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorRobin Peng <robinpeng@google.com>2020-06-08 13:10:27 +0800
committerRobin Peng <robinpeng@google.com>2020-06-08 13:10:27 +0800
commit4743fca20a5011d480d8792cdf512e756ef431c0 (patch)
tree2e99b04408a194f52755ba755ca3c2eea5fd4529 /core
parent96195f87fc0f7df78d63386e6f3b8a9000774420 (diff)
parent0707871c9476b0e3bf4b231fc345e2654ca6721e (diff)
downloadqcacld-4743fca20a5011d480d8792cdf512e756ef431c0.tar.gz
Merge branch 'LA.UM.9.12.R2.10.00.00.685.014' into qcom-msm-4.19-7250-wlan-cld3.driver.lnx.2.0.5.r10
Change-Id: Ie2ab17b84ae91170a7cfa29d09464b492a673aad
Diffstat (limited to 'core')
-rw-r--r--core/hdd/inc/wlan_hdd_main.h13
-rw-r--r--core/hdd/src/wlan_hdd_cfg80211.c6
-rw-r--r--core/hdd/src/wlan_hdd_driver_ops.c78
-rw-r--r--core/hdd/src/wlan_hdd_hostapd.c33
-rw-r--r--core/hdd/src/wlan_hdd_main.c48
-rw-r--r--core/hdd/src/wlan_hdd_stats.c410
-rw-r--r--core/mac/inc/qwlan_version.h6
-rw-r--r--core/mac/inc/sir_api.h1
-rw-r--r--core/mac/src/pe/lim/lim_process_action_frame.c3
-rw-r--r--core/pld/src/pld_pcie.c13
-rw-r--r--core/sap/src/sap_ch_select.c16
-rw-r--r--core/sap/src/sap_fsm.c7
-rw-r--r--core/sap/src/sap_module.c16
-rw-r--r--core/sme/src/csr/csr_api_roam.c114
-rw-r--r--core/sme/src/csr/csr_api_scan.c3
-rw-r--r--core/wma/src/wma_scan_roam.c17
16 files changed, 574 insertions, 210 deletions
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index cec3be1d59..ef5226d9bc 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -1208,8 +1208,17 @@ struct hdd_adapter {
/* estimated link speed */
uint32_t estimated_linkspeed;
- /* QDF event for session close */
- qdf_event_t qdf_session_close_event;
+ /**
+ * vdev_destroy_event is moved from the qdf_event to linux event
+ * consciously, Lets take example when sap interface is waiting on the
+ * session_close event and then there is a SSR the wait event is
+ * completed the interface down is returned and the next command to the
+ * driver will hdd_hostapd_uinit-->vhdd_deinit_ap_mode-->
+ * hdd_hostapd_deinit_sap_session where in the sap_ctx would be freed.
+ * During the SSR if the same sap context is used it would result
+ * in null pointer de-reference.
+ */
+ struct completion vdev_destroy_event;
/* QDF event for session open */
qdf_event_t qdf_session_open_event;
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index 6c349b0e78..d8f793d5dd 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -20212,6 +20212,12 @@ wlan_hdd_get_cfg80211_disconnect_reason(struct hdd_adapter *adapter,
if (reason >= eSIR_MAC_REASON_PROP_START) {
adapter->last_disconnect_reason =
wlan_hdd_sir_mac_to_qca_reason(reason);
+ /*
+ * Applications expect reason code as 0 for beacon miss failure
+ * due to backward compatibility. So send ieee80211_reason as 0.
+ */
+ if (reason == eSIR_MAC_BEACON_MISSED)
+ ieee80211_reason = 0;
} else {
ieee80211_reason = (enum ieee80211_reasoncode)reason;
adapter->last_disconnect_reason =
diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c
index 809bb32575..1f01bf20a1 100644
--- a/core/hdd/src/wlan_hdd_driver_ops.c
+++ b/core/hdd/src/wlan_hdd_driver_ops.c
@@ -55,6 +55,9 @@
#define SSR_MAX_FAIL_CNT 3
static uint8_t re_init_fail_cnt, probe_fail_cnt;
+/* An atomic flag to check if SSR cleanup has been done or not */
+static qdf_atomic_t is_recovery_cleanup_done;
+
/*
* In BMI Phase we are only sending small chunk (256 bytes) of the FW image at
* a time, and wait for the completion interrupt to start the next transfer.
@@ -762,13 +765,18 @@ static void hdd_psoc_shutdown_notify(struct hdd_context *hdd_ctx)
hdd_send_hang_reason();
}
-static void __hdd_soc_recovery_shutdown(void)
+/**
+ * hdd_soc_recovery_cleanup() - Perform SSR related cleanup activities.
+ *
+ * This function will perform cleanup activities related to when driver
+ * undergoes SSR. Activities inclues stopping idle timer and invoking shutdown
+ * notifier.
+ *
+ * Return: None
+ */
+static void hdd_soc_recovery_cleanup(void)
{
struct hdd_context *hdd_ctx;
- void *hif_ctx;
-
- /* recovery starts via firmware down indication; ensure we got one */
- QDF_BUG(cds_is_driver_recovering());
hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
if (!hdd_ctx) {
@@ -791,6 +799,35 @@ static void __hdd_soc_recovery_shutdown(void)
return;
}
+ hdd_psoc_shutdown_notify(hdd_ctx);
+}
+
+static void __hdd_soc_recovery_shutdown(void)
+{
+ struct hdd_context *hdd_ctx;
+ void *hif_ctx;
+
+ /* recovery starts via firmware down indication; ensure we got one */
+ QDF_BUG(cds_is_driver_recovering());
+
+ hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+ if (!hdd_ctx) {
+ hdd_err("hdd_ctx is null");
+ return;
+ }
+
+ /*
+ * Perform SSR related cleanup if it has not already been done as a
+ * part of receiving the uevent.
+ */
+ if (!qdf_atomic_read(&is_recovery_cleanup_done))
+ hdd_soc_recovery_cleanup();
+ else
+ qdf_atomic_set(&is_recovery_cleanup_done, 0);
+
+ if (!hdd_wait_for_debugfs_threads_completion())
+ hdd_err("Debufs threads are still pending, attempting SSR anyway");
+
hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
if (!hif_ctx) {
hdd_err("Failed to get HIF context, ignore SSR shutdown");
@@ -800,11 +837,6 @@ static void __hdd_soc_recovery_shutdown(void)
/* mask the host controller interrupts */
hif_mask_interrupt_call(hif_ctx);
- hdd_psoc_shutdown_notify(hdd_ctx);
-
- if (!hdd_wait_for_debugfs_threads_completion())
- hdd_err("Debufs threads are still pending, attempting SSR anyway");
-
if (!QDF_IS_EPPING_ENABLED(cds_get_conparam())) {
hif_disable_isr(hif_ctx);
hdd_wlan_shutdown();
@@ -1434,7 +1466,7 @@ static int wlan_hdd_runtime_resume(struct device *dev)
hdd_err("PMO Runtime resume failed: %d", status);
} else {
if (policy_mgr_get_connection_count(hdd_ctx->psoc))
- hdd_bus_bw_compute_timer_start(hdd_ctx);
+ hdd_bus_bw_compute_timer_try_start(hdd_ctx);
}
hdd_debug("Runtime resume done");
@@ -1728,21 +1760,23 @@ wlan_hdd_pld_uevent(struct device *dev, struct pld_uevent_data *event_data)
case PLD_FW_DOWN:
hdd_info("Received firmware down indication");
- /* NOTE! SSR cleanup logic goes in pld shutdown, not here */
-
cds_set_target_ready(false);
cds_set_recovery_in_progress(true);
- /* SSR cleanup happens in pld shutdown, which is serialized by
- * the platform driver. Other operations are also serialized by
- * platform driver, such as probe, remove, and reinit. If the
- * firmware goes down during one of these operations, the driver
- * would normally have to wait for a timeout before shutdown
- * could begin. Instead, forcefully complete events waiting on
- * firmware with a "reset" status to avoid waiting to time out
- * on a firmware we already know is down.
+ /*
+ * In case of some platforms, uevent will come to the driver in
+ * process context. In that case, it is safe to complete the
+ * SSR cleanup activities in the same context. In case of
+ * other platforms, it will be invoked in interrupt context.
+ * Performing the cleanup in interrupt context is not ideal,
+ * thus defer the cleanup to be done during
+ * hdd_soc_recovery_shutdown
*/
- qdf_complete_wait_events();
+ if (qdf_in_interrupt())
+ break;
+
+ hdd_soc_recovery_cleanup();
+ qdf_atomic_set(&is_recovery_cleanup_done, 1);
break;
default:
diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c
index f11ced880d..2fa5719100 100644
--- a/core/hdd/src/wlan_hdd_hostapd.c
+++ b/core/hdd/src/wlan_hdd_hostapd.c
@@ -3562,13 +3562,7 @@ struct hdd_adapter *hdd_wlan_create_ap_dev(struct hdd_context *hdd_ctx,
return NULL;
}
- qdf_status = qdf_event_create(
- &adapter->qdf_session_close_event);
- if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
- hdd_err("failed to create session close QDF event!");
- free_netdev(adapter->dev);
- return NULL;
- }
+ init_completion(&adapter->vdev_destroy_event);
SET_NETDEV_DEV(dev, hdd_ctx->parent_dev);
spin_lock_init(&adapter->pause_map_lock);
@@ -5770,21 +5764,21 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy,
* interval in not reset.
*/
if (ret)
- return 0;
+ goto exit;
if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
hdd_err("Command not allowed in FTM mode");
- return 0;
+ goto exit;
}
if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) {
hdd_err("Driver module is closed; dropping request");
- return 0;
+ goto exit;
}
if (wlan_hdd_validate_vdev_id(adapter->vdev_id)) {
hdd_err("vdev is invalid. Hence return");
- return 0;
+ goto exit;
}
qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD,
@@ -5794,7 +5788,7 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy,
if (!(adapter->device_mode == QDF_SAP_MODE ||
adapter->device_mode == QDF_P2P_GO_MODE)) {
hdd_err("stop ap is given on device modes other than SAP/GO. Hence return");
- return 0;
+ goto exit;
}
/* Clear SOFTAP_INIT_DONE flag to mark stop_ap deinit. So that we do
@@ -5880,7 +5874,7 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy,
} else {
hdd_debug("SAP already down");
mutex_unlock(&hdd_ctx->sap_lock);
- return 0;
+ goto exit;
}
mutex_unlock(&hdd_ctx->sap_lock);
@@ -5891,7 +5885,7 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy,
if (status != QDF_STATUS_SUCCESS) {
hdd_err("Stopping the BSS");
- return -EINVAL;
+ goto exit;
}
qdf_copy_macaddr(&update_ie.bssid, &adapter->mac_addr);
@@ -5917,9 +5911,15 @@ static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy,
ucfg_p2p_status_stop_bss(adapter->vdev);
+exit:
+ if (adapter->session.ap.beacon) {
+ qdf_mem_free(adapter->session.ap.beacon);
+ adapter->session.ap.beacon = NULL;
+ }
+
hdd_exit();
- return ret;
+ return 0;
}
/**
@@ -6520,7 +6520,8 @@ static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy,
sizeof(*sta_inactivity_timer));
if (!sta_inactivity_timer) {
hdd_err("Failed to allocate Memory");
- return QDF_STATUS_E_FAILURE;
+ status = QDF_STATUS_E_FAILURE;
+ goto err_start_bss;
}
sta_inactivity_timer->session_id = adapter->vdev_id;
sta_inactivity_timer->sta_inactivity_timeout =
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index dba90ab752..5adbcff853 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -3803,7 +3803,7 @@ static int hdd_open(struct net_device *net_dev)
int errno;
struct osif_vdev_sync *vdev_sync;
- errno = osif_vdev_sync_trans_start_wait(net_dev, &vdev_sync);
+ errno = osif_vdev_sync_trans_start(net_dev, &vdev_sync);
if (errno)
return errno;
@@ -4504,9 +4504,7 @@ hdd_alloc_station_adapter(struct hdd_context *hdd_ctx, tSirMacAddr mac_addr,
if (QDF_IS_STATUS_ERROR(qdf_status))
goto free_net_dev;
- qdf_status = qdf_event_create(&adapter->qdf_session_close_event);
- if (QDF_IS_STATUS_ERROR(qdf_status))
- goto free_net_dev;
+ init_completion(&adapter->vdev_destroy_event);
qdf_status = hdd_monitor_mode_qdf_create_event(adapter, session_type);
if (QDF_IS_STATUS_ERROR(qdf_status)) {
@@ -4658,7 +4656,7 @@ QDF_STATUS hdd_sme_close_session_callback(uint8_t vdev_id)
* valid, before signaling completion
*/
if (WLAN_HDD_ADAPTER_MAGIC == adapter->magic)
- qdf_event_set(&adapter->qdf_session_close_event);
+ complete(&adapter->vdev_destroy_event);
return QDF_STATUS_SUCCESS;
}
@@ -4716,6 +4714,7 @@ int hdd_vdev_destroy(struct hdd_adapter *adapter)
struct hdd_context *hdd_ctx;
uint8_t vdev_id;
struct wlan_objmgr_vdev *vdev;
+ long rc;
vdev_id = adapter->vdev_id;
hdd_nofl_debug("destroying vdev %d", vdev_id);
@@ -4751,7 +4750,7 @@ int hdd_vdev_destroy(struct hdd_adapter *adapter)
hdd_objmgr_put_vdev(vdev);
/* close sme session (destroy vdev in firmware via legacy API) */
- qdf_event_reset(&adapter->qdf_session_close_event);
+ INIT_COMPLETION(adapter->vdev_destroy_event);
status = sme_close_session(hdd_ctx->mac_handle, adapter->vdev_id);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("failed to close sme session; status:%d", status);
@@ -4759,11 +4758,9 @@ int hdd_vdev_destroy(struct hdd_adapter *adapter)
}
/* block on a completion variable until sme session is closed */
- status = qdf_wait_for_event_completion(
- &adapter->qdf_session_close_event,
- SME_CMD_VDEV_CREATE_DELETE_TIMEOUT);
-
- if (QDF_IS_STATUS_ERROR(status)) {
+ rc = wait_for_completion_timeout(&adapter->vdev_destroy_event,
+ SME_CMD_VDEV_CREATE_DELETE_TIMEOUT);
+ if (rc) {
clear_bit(SME_SESSION_OPENED, &adapter->event_flags);
if (adapter->device_mode == QDF_NDI_MODE)
@@ -4772,11 +4769,6 @@ int hdd_vdev_destroy(struct hdd_adapter *adapter)
if (status == QDF_STATUS_E_TIMEOUT) {
hdd_err("timed out waiting for sme close session");
sme_cleanup_session(hdd_ctx->mac_handle, vdev_id);
- } else if (adapter->qdf_session_close_event.force_set) {
- hdd_info("SSR occurred during sme close session");
- } else {
- hdd_err("failed to wait for sme close session; status:%u",
- status);
}
}
@@ -9046,7 +9038,11 @@ void hdd_bus_bandwidth_deinit(struct hdd_context *hdd_ctx)
{
hdd_enter();
+ /* it is expecting the timer has been stopped or not started
+ * when coming deinit.
+ */
QDF_BUG(!qdf_periodic_work_stop_sync(&hdd_ctx->bus_bw_work));
+
qdf_periodic_work_destroy(&hdd_ctx->bus_bw_work);
hdd_pm_qos_remove_request(hdd_ctx);
qdf_spinlock_destroy(&hdd_ctx->bus_bw_lock);
@@ -15075,6 +15071,20 @@ static void hdd_driver_unload(void)
pr_info("%s: Unloading driver v%s\n", WLAN_MODULE_NAME,
QWLAN_VERSIONSTR);
+ /*
+ * Wait for any trans to complete and then start the driver trans
+ * for the unload. This will ensure that the driver trans proceeds only
+ * after all trans have been completed. As a part of this trans, set
+ * the driver load/unload flag to further ensure that any upcoming
+ * trans are rejected via wlan_hdd_validate_context.
+ */
+ status = osif_driver_sync_trans_start_wait(&driver_sync);
+ QDF_BUG(QDF_IS_STATUS_SUCCESS(status));
+ if (QDF_IS_STATUS_ERROR(status)) {
+ hdd_err("Unable to unload wlan; status:%u", status);
+ return;
+ }
+
hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
if (hif_ctx) {
/*
@@ -15096,6 +15106,12 @@ static void hdd_driver_unload(void)
hdd_bus_bw_compute_timer_stop(hdd_ctx);
}
+ /*
+ * Stop the trans before calling unregister_driver as that involves a
+ * call to pld_remove which in itself is a psoc transaction
+ */
+ osif_driver_sync_trans_stop(driver_sync);
+
/* trigger SoC remove */
wlan_hdd_unregister_driver();
diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c
index 2c7d592579..a1e286c715 100644
--- a/core/hdd/src/wlan_hdd_stats.c
+++ b/core/hdd/src/wlan_hdd_stats.c
@@ -77,6 +77,8 @@
#define HDD_INFO_CONNECTED_TIME BIT(NL80211_STA_INFO_CONNECTED_TIME)
#endif /* kernel version less than 4.0.0 && no_backport */
+#define HDD_LINK_STATS_MAX 5
+
/* 11B, 11G Rate table include Basic rate and Extended rate
* The IDX field is the rate index
* The HI field is the rate when RSSI is strong or being ignored
@@ -170,13 +172,38 @@ static int rssi_mcs_tbl[][12] = {
#ifdef WLAN_FEATURE_LINK_LAYER_STATS
/**
+ * struct hdd_ll_stats - buffered hdd link layer stats
+ * @ll_stats_node: pointer to next stats buffered in scheduler thread context
+ * @result_param_id: Received link layer stats ID
+ * @result: received stats from FW
+ * @more_data: if more stats are pending
+ * @no_of_radios: no of radios
+ * @no_of_peers: no of peers
+ */
+struct hdd_ll_stats {
+ qdf_list_node_t ll_stats_node;
+ u32 result_param_id;
+ void *result;
+ u32 more_data;
+ union {
+ u32 no_of_radios;
+ u32 no_of_peers;
+ } stats_nradio_npeer;
+};
+
+/**
* struct hdd_ll_stats_priv - hdd link layer stats private
+ * @ll_stats: head to different link layer stats received in scheduler
+ * thread context
* @request_id: userspace-assigned link layer stats request id
* @request_bitmap: userspace-assigned link layer stats request bitmap
+ * @ll_stats_lock: Lock to serially access request_bitmap
*/
struct hdd_ll_stats_priv {
+ qdf_list_t ll_stats_q;
uint32_t request_id;
uint32_t request_bitmap;
+ qdf_spinlock_t ll_stats_lock;
};
/*
@@ -905,15 +932,22 @@ static int hdd_llstats_post_radio_stats(struct hdd_adapter *adapter,
QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS,
radiostat->num_channels)) {
hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
+
goto failure;
}
if (radiostat->total_num_tx_power_levels) {
- if (nla_put(vendor_event,
+ ret =
+ nla_put(vendor_event,
QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL,
sizeof(u32) *
radiostat->total_num_tx_power_levels,
- radiostat->tx_time_per_power_level)) {
+ radiostat->tx_time_per_power_level);
+ qdf_mem_free(radiostat->tx_time_per_power_level);
+ radiostat->tx_time_per_power_level = NULL;
+ if (ret) {
+ qdf_mem_free(radiostat->channels);
+ radiostat->channels = NULL;
hdd_err("nla_put fail");
goto failure;
}
@@ -922,6 +956,8 @@ static int hdd_llstats_post_radio_stats(struct hdd_adapter *adapter,
if (radiostat->num_channels) {
ret = hdd_llstats_radio_fill_channels(adapter, radiostat,
vendor_event);
+ qdf_mem_free(radiostat->channels);
+ radiostat->channels = NULL;
if (ret)
goto failure;
}
@@ -995,72 +1031,188 @@ hdd_link_layer_process_radio_stats(struct hdd_adapter *adapter,
}
-/**
- * hdd_ll_process_radio_stats() - Wrapper function for cfg80211/debugfs
- * @adapter: Pointer to device adapter
- * @more_data: More data
- * @data: Pointer to stats data
- * @num_radios: Number of radios
- * @resp_id: Response ID from FW
- *
- * Receiving Link Layer Radio statistics from FW. This function is a wrapper
- * function which calls cfg80211/debugfs functions based on the response ID.
- *
- * Return: None
- */
-static void hdd_ll_process_radio_stats(struct hdd_adapter *adapter,
- uint32_t more_data, void *data, uint32_t num_radio,
- uint32_t resp_id)
+static void hdd_process_ll_stats(tSirLLStatsResults *results,
+ struct osif_request *request)
{
- if (DEBUGFS_LLSTATS_REQID == resp_id)
- hdd_debugfs_process_radio_stats(adapter, more_data,
- (struct wifi_radio_stats *)data, num_radio);
- else
- hdd_link_layer_process_radio_stats(adapter, more_data,
- (struct wifi_radio_stats *)data, num_radio);
-}
+ struct hdd_ll_stats_priv *priv = osif_request_priv(request);
+ struct hdd_ll_stats *stats = NULL;
+ size_t stat_size = 0;
-/**
- * hdd_ll_process_iface_stats() - Wrapper function for cfg80211/debugfs
- * @adapter: Pointer to device adapter
- * @data: Pointer to stats data
- * @num_peers: Number of peers
- * @resp_id: Response ID from FW
- *
- * Receiving Link Layer Radio statistics from FW. This function is a wrapper
- * function which calls cfg80211/debugfs functions based on the response ID.
- *
- * Return: None
- */
-static void hdd_ll_process_iface_stats(struct hdd_adapter *adapter,
- void *data, uint32_t num_peers,
- uint32_t resp_id)
-{
- if (DEBUGFS_LLSTATS_REQID == resp_id)
- hdd_debugfs_process_iface_stats(adapter, data, num_peers);
- else
- hdd_link_layer_process_iface_stats(adapter, data, num_peers);
+ if (!(priv->request_bitmap & results->paramId))
+ return;
+
+ if (results->paramId & WMI_LINK_STATS_RADIO) {
+ struct wifi_radio_stats *rs_results, *stat_result;
+ u64 channel_size = 0, pwr_lvl_size = 0;
+ int i;
+ stats = qdf_mem_malloc(sizeof(*stats));
+ if (!stats)
+ goto exit;
+
+ stat_size = sizeof(struct wifi_radio_stats) *
+ results->num_radio;
+ stats->result_param_id = WMI_LINK_STATS_RADIO;
+ stat_result = qdf_mem_malloc(stat_size);
+ if (!stat_result) {
+ qdf_mem_free(stats);
+ goto exit;
+ }
+ stats->result = stat_result;
+ rs_results = (struct wifi_radio_stats *)results->results;
+ qdf_mem_copy(stats->result, results->results, stat_size);
+ for (i = 0; i < results->num_radio; i++) {
+ channel_size = rs_results->num_channels *
+ sizeof(struct wifi_channel_stats);
+ pwr_lvl_size = sizeof(uint32_t) *
+ rs_results->total_num_tx_power_levels;
+
+ if (rs_results->total_num_tx_power_levels &&
+ rs_results->tx_time_per_power_level) {
+ stat_result->tx_time_per_power_level =
+ qdf_mem_malloc(pwr_lvl_size);
+ if (!stat_result->tx_time_per_power_level) {
+ while (i-- > 0) {
+ stat_result--;
+ qdf_mem_free(stat_result->
+ tx_time_per_power_level);
+ qdf_mem_free(stat_result->
+ channels);
+ }
+ qdf_mem_free(stat_result);
+ qdf_mem_free(stats);
+ goto exit;
+ }
+ qdf_mem_copy(stat_result->tx_time_per_power_level,
+ rs_results->tx_time_per_power_level,
+ pwr_lvl_size);
+ }
+ if (channel_size) {
+ stat_result->channels =
+ qdf_mem_malloc(channel_size);
+ if (!stat_result->channels) {
+ qdf_mem_free(stat_result->
+ tx_time_per_power_level);
+ while (i-- > 0) {
+ stat_result--;
+ qdf_mem_free(stat_result->
+ tx_time_per_power_level);
+ qdf_mem_free(stat_result->
+ channels);
+ }
+ qdf_mem_free(stats->result);
+ qdf_mem_free(stats);
+ goto exit;
+ }
+ qdf_mem_copy(stat_result->channels,
+ rs_results->channels,
+ channel_size);
+ }
+ rs_results++;
+ stat_result++;
+ }
+ stats->stats_nradio_npeer.no_of_radios = results->num_radio;
+ stats->more_data = results->moreResultToFollow;
+ if (!results->moreResultToFollow)
+ priv->request_bitmap &= ~stats->result_param_id;
+ } else if (results->paramId & WMI_LINK_STATS_IFACE) {
+ stats = qdf_mem_malloc(sizeof(*stats));
+ if (!stats)
+ goto exit;
+
+ stats->result_param_id = WMI_LINK_STATS_IFACE;
+ stats->stats_nradio_npeer.no_of_peers = results->num_peers;
+ stats->result = qdf_mem_malloc(sizeof(struct
+ wifi_interface_stats));
+ if (!stats->result) {
+ qdf_mem_free(stats);
+ goto exit;
+ }
+ qdf_mem_copy(stats->result, results->results,
+ sizeof(struct wifi_interface_stats));
+ if (!results->num_peers)
+ priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
+ priv->request_bitmap &= ~stats->result_param_id;
+ } else if (results->paramId & WMI_LINK_STATS_ALL_PEER) {
+ struct wifi_peer_stat *peer_stat = (struct wifi_peer_stat *)
+ results->results;
+ struct wifi_peer_info *peer_info = NULL;
+ u64 num_rate = 0, peers, rates;
+ int i;
+ stats = qdf_mem_malloc(sizeof(*stats));
+ if (!stats)
+ goto exit;
+
+ peer_info = (struct wifi_peer_info *)peer_stat->peer_info;
+ for (i = 1; i <= peer_stat->num_peers; i++) {
+ num_rate += peer_info->num_rate;
+ peer_info = (struct wifi_peer_info *)((uint8_t *)
+ peer_info + sizeof(struct wifi_peer_info) +
+ (peer_info->num_rate *
+ sizeof(struct wifi_rate_stat)));
+ }
+
+ peers = sizeof(struct wifi_peer_info) * peer_stat->num_peers;
+ rates = sizeof(struct wifi_rate_stat) * num_rate;
+ stat_size = sizeof(struct wifi_peer_stat) + peers + rates;
+ stats->result_param_id = WMI_LINK_STATS_ALL_PEER;
+
+ stats->result = qdf_mem_malloc(stat_size);
+ if (!stats->result) {
+ qdf_mem_free(stats);
+ goto exit;
+ }
+
+ qdf_mem_copy(stats->result, results->results, stat_size);
+ stats->more_data = results->moreResultToFollow;
+ if (!results->moreResultToFollow)
+ priv->request_bitmap &= ~stats->result_param_id;
+ } else {
+ hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
+ }
+ /* send indication to caller thread */
+ if (stats)
+ qdf_list_insert_back(&priv->ll_stats_q, &stats->ll_stats_node);
+
+ if (!priv->request_bitmap)
+exit:
+ osif_request_complete(request);
}
-/**
- * hdd_ll_process_peer_stats() - Wrapper function for cfg80211/debugfs
- * @adapter: Pointer to device adapter
- * @more_data: More data
- * @data: Pointer to stats data
- * @resp_id: Response ID from FW
- *
- * Receiving Link Layer Radio statistics from FW. This function is a wrapper
- * function which calls cfg80211/debugfs functions based on the response ID.
- *
- * Return: None
- */
-static void hdd_ll_process_peer_stats(struct hdd_adapter *adapter,
- uint32_t more_data, void *data, uint32_t resp_id)
+static void hdd_debugfs_process_ll_stats(struct hdd_adapter *adapter,
+ tSirLLStatsResults *results,
+ struct osif_request *request)
{
- if (DEBUGFS_LLSTATS_REQID == resp_id)
- hdd_debugfs_process_peer_stats(adapter, data);
- else
- hdd_link_layer_process_peer_stats(adapter, more_data, data);
+ struct hdd_ll_stats_priv *priv = osif_request_priv(request);
+
+ if (results->paramId & WMI_LINK_STATS_RADIO) {
+ hdd_debugfs_process_radio_stats(adapter,
+ results->moreResultToFollow,
+ results->results,
+ results->num_radio);
+ if (!results->moreResultToFollow)
+ priv->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
+ } else if (results->paramId & WMI_LINK_STATS_IFACE) {
+ hdd_debugfs_process_iface_stats(adapter, results->results,
+ results->num_peers);
+
+ /* Firmware doesn't send peerstats event if no peers are
+ * connected. HDD should not wait for any peerstats in
+ * this case and return the status to middleware after
+ * receiving iface stats
+ */
+
+ if (!results->num_peers)
+ priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
+ } else if (results->paramId & WMI_LINK_STATS_ALL_PEER) {
+ hdd_debugfs_process_peer_stats(adapter, results->results);
+ if (!results->moreResultToFollow)
+ priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER);
+ } else {
+ hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
+ }
+
+ if (!priv->request_bitmap)
+ osif_request_complete(request);
}
void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,
@@ -1104,8 +1256,7 @@ void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,
priv = osif_request_priv(request);
/* validate response received from target */
- if ((priv->request_id != results->rspId) ||
- !(priv->request_bitmap & results->paramId)) {
+ if (priv->request_id != results->rspId) {
hdd_err("Request id %d response id %d request bitmap 0x%x response bitmap 0x%x",
priv->request_id, results->rspId,
priv->request_bitmap, results->paramId);
@@ -1113,52 +1264,15 @@ void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle,
return;
}
- if (results->paramId & WMI_LINK_STATS_RADIO) {
- hdd_ll_process_radio_stats(adapter,
- results->moreResultToFollow,
- results->results,
- results->num_radio,
- results->rspId);
-
- if (!results->moreResultToFollow)
- priv->request_bitmap &= ~(WMI_LINK_STATS_RADIO);
-
- } else if (results->paramId &
- WMI_LINK_STATS_IFACE) {
- hdd_ll_process_iface_stats(adapter,
- results->results,
- results->num_peers,
- results->rspId);
-
- /* Firmware doesn't send peerstats event if no peers are
- * connected. HDD should not wait for any peerstats in
- * this case and return the status to middleware after
- * receiving iface stats
- */
- if (!results->num_peers)
- priv->request_bitmap &=
- ~(WMI_LINK_STATS_ALL_PEER);
- priv->request_bitmap &= ~(WMI_LINK_STATS_IFACE);
-
- } else if (results->
- paramId & WMI_LINK_STATS_ALL_PEER) {
- hdd_ll_process_peer_stats(adapter,
- results->moreResultToFollow,
- results->results,
- results->rspId);
-
- if (!results->moreResultToFollow)
- priv->request_bitmap &=
- ~(WMI_LINK_STATS_ALL_PEER);
-
- } else {
- hdd_err("INVALID LL_STATS_NOTIFY RESPONSE");
+ if (results->rspId == DEBUGFS_LLSTATS_REQID) {
+ hdd_debugfs_process_ll_stats(adapter, results, request);
+ } else {
+ qdf_spin_lock(&priv->ll_stats_lock);
+ if (priv->request_bitmap)
+ hdd_process_ll_stats(results, request);
+ qdf_spin_unlock(&priv->ll_stats_lock);
}
- /* complete response event if all requests are completed */
- if (!priv->request_bitmap)
- osif_request_complete(request);
-
osif_request_put(request);
break;
}
@@ -1339,12 +1453,56 @@ nla_policy
[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32}
};
-static int wlan_hdd_send_ll_stats_req(struct hdd_context *hdd_ctx,
+static void wlan_hdd_handle_ll_stats(struct hdd_adapter *adapter,
+ struct hdd_ll_stats *stats,
+ int ret)
+{
+ switch (stats->result_param_id) {
+ case WMI_LINK_STATS_RADIO:
+ {
+ struct wifi_radio_stats *radio_stat = stats->result;
+ int i, num_radio = stats->stats_nradio_npeer.no_of_radios;
+
+ if (ret == -ETIMEDOUT) {
+ for (i = 0; i < num_radio; i++) {
+ if (radio_stat->num_channels)
+ qdf_mem_free(radio_stat->channels);
+ if (radio_stat->total_num_tx_power_levels)
+ qdf_mem_free(radio_stat->
+ tx_time_per_power_level);
+ radio_stat++;
+ }
+ return;
+ }
+ hdd_link_layer_process_radio_stats(adapter, stats->more_data,
+ radio_stat, num_radio);
+ }
+ break;
+ case WMI_LINK_STATS_IFACE:
+ hdd_link_layer_process_iface_stats(adapter, stats->result,
+ stats->stats_nradio_npeer.
+ no_of_peers);
+ break;
+ case WMI_LINK_STATS_ALL_PEER:
+ hdd_link_layer_process_peer_stats(adapter,
+ stats->more_data,
+ stats->result);
+ break;
+ default:
+ hdd_err("not requested event");
+ }
+}
+
+static int wlan_hdd_send_ll_stats_req(struct hdd_adapter *adapter,
tSirLLStatsGetReq *req)
{
- int ret;
+ int ret = 0;
struct hdd_ll_stats_priv *priv;
+ struct hdd_ll_stats *stats = NULL;
struct osif_request *request;
+ qdf_list_node_t *ll_node;
+ QDF_STATUS status;
+ struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
void *cookie;
static const struct osif_request_params params = {
.priv_size = sizeof(*priv),
@@ -1365,6 +1523,8 @@ static int wlan_hdd_send_ll_stats_req(struct hdd_context *hdd_ctx,
priv->request_id = req->reqId;
priv->request_bitmap = req->paramIdMask;
+ qdf_spinlock_create(&priv->ll_stats_lock);
+ qdf_list_create(&priv->ll_stats_q, HDD_LINK_STATS_MAX);
if (QDF_STATUS_SUCCESS !=
sme_ll_stats_get_req(hdd_ctx->mac_handle, req,
@@ -1373,18 +1533,33 @@ static int wlan_hdd_send_ll_stats_req(struct hdd_context *hdd_ctx,
ret = -EINVAL;
goto exit;
}
-
ret = osif_request_wait_for_response(request);
if (ret) {
hdd_err("Target response timed out request id %d request bitmap 0x%x",
priv->request_id, priv->request_bitmap);
+ qdf_spin_lock(&priv->ll_stats_lock);
+ priv->request_bitmap = 0;
+ qdf_spin_unlock(&priv->ll_stats_lock);
ret = -ETIMEDOUT;
- goto exit;
}
- hdd_exit();
-
+ qdf_spin_lock(&priv->ll_stats_lock);
+ status = qdf_list_remove_front(&priv->ll_stats_q, &ll_node);
+ qdf_spin_unlock(&priv->ll_stats_lock);
+ while (QDF_IS_STATUS_SUCCESS(status)) {
+ stats = qdf_container_of(ll_node, struct hdd_ll_stats,
+ ll_stats_node);
+ wlan_hdd_handle_ll_stats(adapter, stats, ret);
+ qdf_mem_free(stats->result);
+ qdf_mem_free(stats);
+ qdf_spin_lock(&priv->ll_stats_lock);
+ status = qdf_list_remove_front(&priv->ll_stats_q, &ll_node);
+ qdf_spin_unlock(&priv->ll_stats_lock);
+ }
+ qdf_list_destroy(&priv->ll_stats_q);
exit:
+ hdd_exit();
osif_request_put(request);
+
return ret;
}
@@ -1394,7 +1569,6 @@ int wlan_hdd_ll_stats_get(struct hdd_adapter *adapter, uint32_t req_id,
int errno;
tSirLLStatsGetReq get_req;
struct hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
- struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
hdd_enter();
@@ -1418,7 +1592,7 @@ int wlan_hdd_ll_stats_get(struct hdd_adapter *adapter, uint32_t req_id,
get_req.staId = adapter->vdev_id;
rtnl_lock();
- errno = wlan_hdd_send_ll_stats_req(hdd_ctx, &get_req);
+ errno = wlan_hdd_send_ll_stats_req(adapter, &get_req);
rtnl_unlock();
if (errno)
hdd_err("Send LL stats req failed, id:%u, mask:%d, session:%d",
@@ -1504,7 +1678,7 @@ __wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy,
if (wlan_hdd_validate_vdev_id(adapter->vdev_id))
return -EINVAL;
- ret = wlan_hdd_send_ll_stats_req(hdd_ctx, &LinkLayerStatsGetReq);
+ ret = wlan_hdd_send_ll_stats_req(adapter, &LinkLayerStatsGetReq);
if (0 != ret) {
hdd_err("Failed to send LL stats request (id:%u)",
LinkLayerStatsGetReq.reqId);
diff --git a/core/mac/inc/qwlan_version.h b/core/mac/inc/qwlan_version.h
index fa47db010b..666b785f86 100644
--- a/core/mac/inc/qwlan_version.h
+++ b/core/mac/inc/qwlan_version.h
@@ -32,9 +32,9 @@
#define QWLAN_VERSION_MAJOR 5
#define QWLAN_VERSION_MINOR 2
#define QWLAN_VERSION_PATCH 05
-#define QWLAN_VERSION_EXTRA "N"
-#define QWLAN_VERSION_BUILD 20
+#define QWLAN_VERSION_EXTRA ""
+#define QWLAN_VERSION_BUILD 21
-#define QWLAN_VERSIONSTR "5.2.05.20N"
+#define QWLAN_VERSIONSTR "5.2.05.21"
#endif /* QWLAN_VERSION_H */
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 2fd55f241f..596cc99dd7 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -724,6 +724,7 @@ struct bss_description {
#endif
uint32_t assoc_disallowed;
uint32_t adaptive_11r_ap;
+ uint32_t mbo_oce_enabled_ap;
#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD)
uint32_t is_single_pmk;
#endif
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 ce5c87da39..d251afe338 100644
--- a/core/mac/src/pe/lim/lim_process_action_frame.c
+++ b/core/mac/src/pe/lim/lim_process_action_frame.c
@@ -1650,8 +1650,7 @@ static void lim_process_addba_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,
- body_ptr, frame_len);
+ QDF_TRACE_HEX_DUMP_DEBUG_RL(QDF_MODULE_ID_PE, body_ptr, frame_len);
addba_req = qdf_mem_malloc(sizeof(*addba_req));
if (!addba_req)
diff --git a/core/pld/src/pld_pcie.c b/core/pld/src/pld_pcie.c
index c6b272c52c..ab91ddb083 100644
--- a/core/pld/src/pld_pcie.c
+++ b/core/pld/src/pld_pcie.c
@@ -490,11 +490,22 @@ static int pld_pcie_pm_resume_noirq(struct device *dev)
#endif
static struct pci_device_id pld_pcie_id_table[] = {
- { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID },
+#ifdef CONFIG_AR6320_SUPPORT
{ 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID },
+#elif defined(QCA_WIFI_QCA6290)
+ { 0x17cb, 0x1100, PCI_ANY_ID, PCI_ANY_ID },
+#elif defined(QCA_WIFI_QCA6390)
+ { 0x17cb, 0x1101, PCI_ANY_ID, PCI_ANY_ID },
+#elif defined(QCA_WIFI_QCA6490)
+ { 0x17cb, 0x1103, PCI_ANY_ID, PCI_ANY_ID },
+#elif defined(QCN7605_SUPPORT)
+ { 0x17cb, 0x1102, PCI_ANY_ID, PCI_ANY_ID },
+#else
+ { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID },
{ 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID },
{ 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID },
{ 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID },
+#endif
{ 0 }
};
diff --git a/core/sap/src/sap_ch_select.c b/core/sap/src/sap_ch_select.c
index 4d6a3088fb..9502332b4c 100644
--- a/core/sap/src/sap_ch_select.c
+++ b/core/sap/src/sap_ch_select.c
@@ -1377,6 +1377,8 @@ static void sap_compute_spect_weight(tSapChSelSpectInfo *pSpectInfoParams,
pSpectInfoParams->numSpectChans;
qdf_list_node_t *cur_lst = NULL, *next_lst = NULL;
struct scan_cache_node *cur_node = NULL;
+ uint32_t normalized_weight;
+ uint8_t normalize_factor;
bcn_struct = qdf_mem_malloc(sizeof(tSirProbeRespBeacon));
if (!bcn_struct)
@@ -1555,6 +1557,20 @@ static void sap_compute_spect_weight(tSapChSelSpectInfo *pSpectInfoParams,
pSpectCh->bssCount = SOFTAP_MIN_COUNT;
}
+ if (wlan_reg_is_dfs_ch(mac->pdev,
+ pSpectCh->chNum)) {
+ normalize_factor =
+ MLME_GET_DFS_CHAN_WEIGHT(
+ mac->mlme_cfg->acs.np_chan_weightage);
+ normalized_weight =
+ ((SAP_ACS_WEIGHT_MAX - pSpectCh->weight) *
+ (100 - normalize_factor)) / 100;
+ sap_debug("DFS ch %d old weight %d new weight %d",
+ pSpectCh->chNum, pSpectCh->weight,
+ pSpectCh->weight + normalized_weight);
+ pSpectCh->weight += normalized_weight;
+
+ }
if (pSpectCh->weight > SAP_ACS_WEIGHT_MAX)
pSpectCh->weight = SAP_ACS_WEIGHT_MAX;
pSpectCh->weight_copy = pSpectCh->weight;
diff --git a/core/sap/src/sap_fsm.c b/core/sap/src/sap_fsm.c
index bafbb09d3b..99e7403788 100644
--- a/core/sap/src/sap_fsm.c
+++ b/core/sap/src/sap_fsm.c
@@ -3383,6 +3383,13 @@ static QDF_STATUS sap_get_channel_list(struct sap_context *sap_ctx,
WLAN_REG_CH_NUM(loop_count)))
continue;
+ if (wlan_reg_is_dfs_ch(mac_ctx->pdev,
+ WLAN_REG_CH_NUM(loop_count)) &&
+ !MLME_GET_DFS_CHAN_WEIGHT(
+ mac_ctx->mlme_cfg->acs.np_chan_weightage)) {
+ sap_debug("DFS ch with np weight 0, skipping");
+ continue;
+ }
#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE
uint8_t ch;
diff --git a/core/sap/src/sap_module.c b/core/sap/src/sap_module.c
index d7eabeb67e..51e16a38d8 100644
--- a/core/sap/src/sap_module.c
+++ b/core/sap/src/sap_module.c
@@ -1211,10 +1211,22 @@ wlansap_update_csa_channel_params(struct sap_context *sap_context,
if (sap_context->csr_roamProfile.phyMode ==
eCSR_DOT11_MODE_11ac ||
sap_context->csr_roamProfile.phyMode ==
- eCSR_DOT11_MODE_11ac_ONLY)
+ eCSR_DOT11_MODE_11ac_ONLY ||
+ sap_context->csr_roamProfile.phyMode ==
+ eCSR_DOT11_MODE_11ax ||
+ sap_context->csr_roamProfile.phyMode ==
+ eCSR_DOT11_MODE_11ax_ONLY) {
bw = BW80;
- else
+ } else if (sap_context->csr_roamProfile.phyMode ==
+ eCSR_DOT11_MODE_11n ||
+ sap_context->csr_roamProfile.phyMode ==
+ eCSR_DOT11_MODE_11n_ONLY) {
bw = BW40_HIGH_PRIMARY;
+ } else {
+ /* For legacy 11a mode return 20MHz */
+ mac_ctx->sap.SapDfsInfo.new_chanWidth = CH_WIDTH_20MHZ;
+ return QDF_STATUS_SUCCESS;
+ }
for (; bw >= BW20; bw--) {
uint16_t op_class;
diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c
index 49fb001274..e381671f54 100644
--- a/core/sme/src/csr/csr_api_roam.c
+++ b/core/sme/src/csr/csr_api_roam.c
@@ -3538,20 +3538,10 @@ QDF_STATUS csr_roam_call_callback(struct mac_context *mac, uint32_t sessionId,
csr_dump_connection_stats(mac, pSession, roam_info, u1, u2);
if (pSession->callback) {
- if (roam_info) {
+ if (roam_info)
roam_info->sessionId = (uint8_t) sessionId;
- /*
- * the reasonCode will be passed to supplicant by
- * cfg80211_disconnected. Based on the document,
- * the reason code passed to supplicant needs to set
- * to 0 if unknown. eSIR_BEACON_MISSED reason code is
- * not recognizable so that we set to 0 instead.
- */
- if (roam_info->reasonCode == eSIR_MAC_BEACON_MISSED)
- roam_info->reasonCode = 0;
- }
status = pSession->callback(pSession->pContext, roam_info,
- roamId, u1, u2);
+ roamId, u1, u2);
}
/*
* EVENT_WLAN_STATUS_V2: eCSR_ROAM_ASSOCIATION_COMPLETION,
@@ -5339,6 +5329,8 @@ static bool csr_roam_select_bss(struct mac_context *mac_ctx,
enum policy_mgr_con_mode mode;
uint8_t chan_id;
QDF_STATUS qdf_status;
+ eCsrPhyMode self_phymode = mac_ctx->roam.configParam.phyMode;
+ tDot11fBeaconIEs *bcn_ies;
vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev,
vdev_id,
@@ -5361,6 +5353,29 @@ static bool csr_roam_select_bss(struct mac_context *mac_ctx,
* sessions exempted
*/
result = &scan_result->Result;
+ bcn_ies = result->pvIes;
+ /*
+ * If phymode is configured to DOT11 Only profile.
+ * Don't connect to profile which is less than them.
+ */
+ if (bcn_ies && ((self_phymode == eCSR_DOT11_MODE_11n_ONLY &&
+ !bcn_ies->HTCaps.present) ||
+ (self_phymode == eCSR_DOT11_MODE_11ac_ONLY &&
+ !bcn_ies->VHTCaps.present) ||
+ (self_phymode == eCSR_DOT11_MODE_11ax_ONLY &&
+ !bcn_ies->he_cap.present))) {
+ sme_info("self_phymode %d mismatch HT %d VHT %d HE %d",
+ self_phymode, bcn_ies->HTCaps.present,
+ bcn_ies->VHTCaps.present,
+ bcn_ies->he_cap.present);
+ *roam_state = eCsrStopRoamingDueToConcurrency;
+ status = true;
+ *roam_bss_entry = csr_ll_next(&bss_list->List,
+ *roam_bss_entry,
+ LL_ACCESS_LOCK);
+ continue;
+ }
+
/*
* Ignore the BSS if any other vdev is already connected
* to it.
@@ -19257,22 +19272,38 @@ void csr_rso_command_fill_11w_params(struct mac_context *mac_ctx,
#endif
/**
- * csr_get_peer_pmf_status() - Get the PMF capability of peer
+ * csr_update_btm_offload_config() - Update btm config param to fw
* @mac_ctx: Global mac ctx
+ * @command: Roam offload command
+ * @req_buf: roam offload scan request
* @session: roam session
*
- * Return: True if PMF is enabled, false otherwise.
+ * Return: None
*/
-static bool csr_get_peer_pmf_status(struct mac_context *mac_ctx,
- struct csr_roam_session *session)
+static void csr_update_btm_offload_config(struct mac_context *mac_ctx,
+ uint8_t command,
+ struct roam_offload_scan_req *req_buf,
+ struct csr_roam_session *session)
{
struct wlan_objmgr_peer *peer;
bool is_pmf_enabled;
+ req_buf->btm_offload_config =
+ mac_ctx->mlme_cfg->btm.btm_offload_config;
+
+ /* Return if INI is disabled */
+ if (!req_buf->btm_offload_config)
+ return;
+
+ /* For RSO Stop Disable BTM offload to firmware */
+ if (command == ROAM_SCAN_OFFLOAD_STOP) {
+ req_buf->btm_offload_config = 0;
+ return;
+ }
if (!session->pConnectBssDesc) {
sme_err("Connected Bss Desc is NULL");
- return false;
+ return;
}
peer = wlan_objmgr_get_peer(mac_ctx->psoc,
@@ -19282,7 +19313,7 @@ static bool csr_get_peer_pmf_status(struct mac_context *mac_ctx,
if (!peer) {
sme_debug("Peer of peer_mac %pM not found",
session->pConnectBssDesc->bssId);
- return false;
+ return;
}
is_pmf_enabled = mlme_get_peer_pmf_status(peer);
@@ -19290,7 +19321,12 @@ static bool csr_get_peer_pmf_status(struct mac_context *mac_ctx,
sme_debug("get is_pmf_enabled %d for %pM", is_pmf_enabled,
session->pConnectBssDesc->bssId);
- return is_pmf_enabled;
+ /* If peer does not support PMF in case of OCE/MBO
+ * Connection, Disable BTM offload to firmware.
+ */
+ if (session->pConnectBssDesc->mbo_oce_enabled_ap &&
+ !is_pmf_enabled)
+ req_buf->btm_offload_config = 0;
}
/**
@@ -19564,15 +19600,7 @@ csr_create_roam_scan_offload_request(struct mac_context *mac_ctx,
req_buf->lca_config_params.num_disallowed_aps =
mac_ctx->mlme_cfg->lfr.lfr3_num_disallowed_aps;
- /* For RSO Stop or if peer does not support PMF, Disable BTM offload
- * to firmware.
- */
- if (command == ROAM_SCAN_OFFLOAD_STOP ||
- !csr_get_peer_pmf_status(mac_ctx, session))
- req_buf->btm_offload_config = 0;
- else
- req_buf->btm_offload_config =
- mac_ctx->mlme_cfg->btm.btm_offload_config;
+ csr_update_btm_offload_config(mac_ctx, command, req_buf, session);
req_buf->btm_solicited_timeout =
mac_ctx->mlme_cfg->btm.btm_solicited_timeout;
@@ -22712,6 +22740,7 @@ static QDF_STATUS csr_process_roam_sync_callback(struct mac_context *mac_ctx,
struct wlan_objmgr_vdev *vdev;
struct mlme_roam_after_data_stall *vdev_roam_params;
uint32_t chan_id;
+ struct wlan_crypto_pmksa *pmksa;
vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, session_id,
WLAN_LEGACY_SME_ID);
@@ -22970,6 +22999,35 @@ static QDF_STATUS csr_process_roam_sync_callback(struct mac_context *mac_ctx,
} else {
sme_debug("PMKID Not found in cache for " QDF_MAC_ADDR_STR,
QDF_MAC_ADDR_ARRAY(pmkid_cache->BSSID.bytes));
+ if (roam_synch_data->pmk_len) {
+ pmksa = qdf_mem_malloc(sizeof(*pmksa));
+ if (!pmksa) {
+ status = QDF_STATUS_E_NOMEM;
+ goto end;
+ }
+
+ session->pmk_len = roam_synch_data->pmk_len;
+ qdf_mem_zero(session->psk_pmk,
+ sizeof(session->psk_pmk));
+ qdf_mem_copy(session->psk_pmk,
+ roam_synch_data->pmk,
+ session->pmk_len);
+
+ qdf_copy_macaddr(&pmksa->bssid,
+ &session->
+ connectedProfile.bssid);
+ qdf_mem_copy(pmksa->pmkid,
+ roam_synch_data->pmkid, PMKID_LEN);
+ qdf_mem_copy(pmksa->pmk, roam_synch_data->pmk,
+ roam_synch_data->pmk_len);
+ pmksa->pmk_len = roam_synch_data->pmk_len;
+
+ if (wlan_crypto_set_del_pmksa(vdev, pmksa, true)
+ != QDF_STATUS_SUCCESS) {
+ qdf_mem_zero(pmksa, sizeof(*pmksa));
+ qdf_mem_free(pmksa);
+ }
+ }
}
qdf_mem_zero(pmkid_cache, sizeof(*pmkid_cache));
qdf_mem_free(pmkid_cache);
diff --git a/core/sme/src/csr/csr_api_scan.c b/core/sme/src/csr/csr_api_scan.c
index 27605006b9..396be9e389 100644
--- a/core/sme/src/csr/csr_api_scan.c
+++ b/core/sme/src/csr/csr_api_scan.c
@@ -2652,6 +2652,9 @@ static QDF_STATUS csr_fill_bss_from_scan_entry(struct mac_context *mac_ctx,
scan_entry);
bss_desc->adaptive_11r_ap = scan_entry->adaptive_11r_ap;
+ bss_desc->mbo_oce_enabled_ap =
+ util_scan_entry_mbo_oce(scan_entry) ? true : false;
+
csr_fill_single_pmk_ap_cap_from_scan_entry(bss_desc, scan_entry);
qdf_mem_copy(&bss_desc->mbssid_info, &scan_entry->mbssid_info,
diff --git a/core/wma/src/wma_scan_roam.c b/core/wma/src/wma_scan_roam.c
index b35066bf49..8bc1db0c6a 100644
--- a/core/wma/src/wma_scan_roam.c
+++ b/core/wma/src/wma_scan_roam.c
@@ -2415,6 +2415,7 @@ static int wma_fill_roam_synch_buffer(tp_wma_handle wma,
wmi_key_material_ext *key_ft;
struct wma_txrx_node *iface = NULL;
wmi_roam_fils_synch_tlv_param *fils_info;
+ wmi_roam_pmk_cache_synch_tlv_param *pmk_cache_info;
int status = -EINVAL;
uint8_t kck_len;
uint8_t kek_len;
@@ -2555,6 +2556,22 @@ static int wma_fill_roam_synch_buffer(tp_wma_handle wma,
roam_synch_ind_ptr->update_erp_next_seq_num,
roam_synch_ind_ptr->next_erp_seq_num);
}
+
+ pmk_cache_info = param_buf->roam_pmk_cache_synch_info;
+ if (pmk_cache_info && (pmk_cache_info->pmk_len)) {
+ if (pmk_cache_info->pmk_len > SIR_PMK_LEN) {
+ WMA_LOGE("%s: Invalid pmk_len %d", __func__,
+ pmk_cache_info->pmk_len);
+ wma_free_roam_synch_frame_ind(iface);
+ return status;
+ }
+
+ roam_synch_ind_ptr->pmk_len = pmk_cache_info->pmk_len;
+ qdf_mem_copy(roam_synch_ind_ptr->pmk,
+ pmk_cache_info->pmk, pmk_cache_info->pmk_len);
+ qdf_mem_copy(roam_synch_ind_ptr->pmkid,
+ pmk_cache_info->pmkid, PMKID_LEN);
+ }
wma_free_roam_synch_frame_ind(iface);
return 0;
}