Quellcode durchsuchen

qcacld-3.0: Add support to parse roam frame info TLV

Add support to parse roam frame info TLV.
Add changes to send the BTM request logging event.

Change-Id: I24fab5fc0ec204fce74cf822742b5a44b0e7774f
CRs-Fixed: 3013489
Pragaspathi Thilagaraj vor 3 Jahren
Ursprung
Commit
db383df8c9

+ 4 - 0
components/mlme/dispatcher/inc/wlan_mlme_public_struct.h

@@ -2603,6 +2603,7 @@ struct wlan_mlme_sae_single_pmk {
 	struct mlme_pmk_info pmk_info;
 };
 
+#define ROAM_FRAME_INFO_FRAME_TYPE_EXT 3
 /**
  * struct mlme_roam_debug_info - Roam debug information storage structure.
  * @trigger:            Roam trigger related data
@@ -2612,6 +2613,8 @@ struct wlan_mlme_sae_single_pmk {
  * @btm_rsp:            BTM response information
  * @roam_init_info:     Roam initial info
  * @roam_msg_info:      roam related message information
+ * @frame_info:         Information related to mgmt/eapol frames exchanged
+ *                      during roaming.
  */
 struct mlme_roam_debug_info {
 	struct wmi_roam_trigger_info trigger;
@@ -2621,6 +2624,7 @@ struct mlme_roam_debug_info {
 	struct roam_btm_response_data btm_rsp;
 	struct roam_initial_data roam_init_info;
 	struct roam_msg_info roam_msg_info;
+	struct roam_frame_info frame_info[WLAN_ROAM_MAX_FRAME_INFO];
 };
 
 /**

+ 215 - 0
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c

@@ -41,6 +41,7 @@
 #include "connection_mgr/core/src/wlan_cm_main.h"
 #include "connection_mgr/core/src/wlan_cm_sm.h"
 #include "wlan_reg_ucfg_api.h"
+#include "wlan_connectivity_logging.h"
 
 #ifdef WLAN_FEATURE_SAE
 #define CM_IS_FW_FT_SAE_SUPPORTED(fw_akm_bitmap) \
@@ -4927,4 +4928,218 @@ bool cm_roam_offload_enabled(struct wlan_objmgr_psoc *psoc)
 
 	return val;
 }
+
+#ifdef WLAN_FEATURE_CONNECTIVITY_LOGGING
+static enum wlan_main_tag
+cm_roam_get_tag(enum mgmt_subtype subtype, bool is_tx)
+{
+	switch (subtype) {
+	case MGMT_SUBTYPE_ASSOC_REQ:
+		return WLAN_ASSOC_REQ;
+	case MGMT_SUBTYPE_ASSOC_RESP:
+		return WLAN_ASSOC_RSP;
+	case MGMT_SUBTYPE_REASSOC_REQ:
+		return WLAN_ASSOC_REQ;
+	case MGMT_SUBTYPE_REASSOC_RESP:
+		return WLAN_ASSOC_RSP;
+	case MGMT_SUBTYPE_DISASSOC:
+		if (is_tx)
+			return WLAN_DISASSOC_TX;
+		else
+			return WLAN_DISASSOC_RX;
+		break;
+	case MGMT_SUBTYPE_AUTH:
+		if (is_tx)
+			return WLAN_AUTH_REQ;
+		else
+			return WLAN_AUTH_RESP;
+		break;
+	case MGMT_SUBTYPE_DEAUTH:
+		if (is_tx)
+			return WLAN_DEAUTH_TX;
+		else
+			return WLAN_DEAUTH_RX;
+	default:
+		break;
+	}
+
+	return WLAN_TAG_MAX;
+}
+
+static enum wlan_main_tag
+cm_roam_get_eapol_tag(enum wlan_roam_frame_subtype subtype)
+{
+	switch (subtype) {
+	case ROAM_FRAME_SUBTYPE_M1:
+		return WLAN_EAPOL_M1;
+	case ROAM_FRAME_SUBTYPE_M2:
+		return WLAN_EAPOL_M2;
+	case ROAM_FRAME_SUBTYPE_M3:
+		return WLAN_EAPOL_M3;
+	case ROAM_FRAME_SUBTYPE_M4:
+		return WLAN_EAPOL_M4;
+	case ROAM_FRAME_SUBTYPE_GTK_M1:
+		return WLAN_GTK_M1;
+	case ROAM_FRAME_SUBTYPE_GTK_M2:
+		return WLAN_GTK_M2;
+	default:
+		break;
+	}
+
+	return WLAN_TAG_MAX;
+}
+
+QDF_STATUS
+cm_roam_btm_query_event(struct wmi_neighbor_report_data *btm_data,
+			uint8_t vdev_id)
+{
+	struct wlan_log_record *log_record = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	log_record = qdf_mem_malloc(sizeof(*log_record));
+	if (!log_record)
+		return QDF_STATUS_E_NOMEM;
+
+	log_record->log_subtype = WLAN_BTM_QUERY;
+	log_record->timestamp_us = qdf_get_time_of_the_day_ms() * 1000;
+	log_record->fw_timestamp_us = btm_data->timestamp * 1000;
+	log_record->vdev_id = vdev_id;
+
+	status = wlan_connectivity_log_enqueue(log_record);
+	qdf_mem_free(log_record);
+
+	return status;
+}
+
+QDF_STATUS
+cm_roam_btm_resp_event(struct roam_btm_response_data *btm_data,
+		       uint8_t vdev_id, bool is_wtc)
+{
+	struct wlan_log_record *log_record = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	log_record = qdf_mem_malloc(sizeof(*log_record));
+	if (!log_record)
+		return QDF_STATUS_E_NOMEM;
+
+	if (is_wtc)
+		log_record->log_subtype = WLAN_ROAM_WTC;
+	else
+		log_record->log_subtype = WLAN_BTM_RESP;
+
+	log_record->timestamp_us = qdf_get_time_of_the_day_ms() * 1000;
+	log_record->fw_timestamp_us = btm_data->timestamp * 1000;
+	log_record->vdev_id = vdev_id;
+
+	log_record->btm_info.token = btm_data->btm_resp_dialog_token;
+	log_record->btm_info.btm_status_code = btm_data->btm_status;
+	log_record->btm_info.btm_delay = btm_data->btm_delay;
+	log_record->btm_info.target_bssid = btm_data->target_bssid;
+	if (is_wtc) {
+		log_record->btm_info.reason = btm_data->vsie_reason;
+		log_record->btm_info.wtc_duration = btm_data->btm_delay;
+	}
+
+	status = wlan_connectivity_log_enqueue(log_record);
+	qdf_mem_free(log_record);
+
+	return status;
+}
+
+/**
+ * cm_roam_btm_candidate_event()  - Send BTM roam candidate logging event
+ * @btm_data: BTM data
+ * @vdev_id: Vdev id
+ *
+ * Return: QDF_STATUS
+ */
+static QDF_STATUS
+cm_roam_btm_candidate_event(struct wmi_btm_req_candidate_info *btm_data,
+			    uint8_t vdev_id)
+{
+	struct wlan_log_record *log_record = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	log_record = qdf_mem_malloc(sizeof(*log_record));
+	if (!log_record)
+		return QDF_STATUS_E_NOMEM;
+
+	log_record->log_subtype = WLAN_BTM_REQ_CANDI;
+	log_record->timestamp_us = qdf_get_time_of_the_day_ms() * 1000;
+	log_record->fw_timestamp_us = btm_data->timestamp * 1000;
+	log_record->vdev_id = vdev_id;
+	log_record->btm_cand.preference = btm_data->preference;
+	log_record->btm_cand.bssid = btm_data->candidate_bssid;
+
+	status = wlan_connectivity_log_enqueue(log_record);
+	qdf_mem_free(log_record);
+
+	return status;
+}
+
+QDF_STATUS
+cm_roam_btm_req_event(struct wmi_roam_btm_trigger_data *btm_data,
+		      uint8_t vdev_id)
+{
+	struct wlan_log_record *log_record = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	uint8_t i;
+
+	log_record = qdf_mem_malloc(sizeof(*log_record));
+	if (!log_record)
+		return QDF_STATUS_E_NOMEM;
+
+	log_record->log_subtype = WLAN_BTM_REQ;
+	log_record->timestamp_us = qdf_get_time_of_the_day_ms() * 1000;
+	log_record->fw_timestamp_us = btm_data->timestamp * 1000;
+	log_record->vdev_id = vdev_id;
+
+	log_record->btm_info.token = btm_data->token;
+	log_record->btm_info.mode = btm_data->btm_request_mode;
+	log_record->btm_info.disassoc_timer = btm_data->disassoc_timer;
+	log_record->btm_info.validity_timer = btm_data->validity_interval;
+	log_record->btm_info.candidate_list_count =
+				btm_data->candidate_list_count;
+
+	status = wlan_connectivity_log_enqueue(log_record);
+	for (i = 0; i < log_record->btm_info.candidate_list_count; i++)
+		cm_roam_btm_candidate_event(&btm_data->btm_cand[i], vdev_id);
+
+	qdf_mem_free(log_record);
+
+	return status;
+}
+
+QDF_STATUS
+cm_roam_mgmt_frame_event(struct roam_frame_info *frame_data, uint8_t vdev_id)
+{
+	struct wlan_log_record *log_record = NULL;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	log_record = qdf_mem_malloc(sizeof(*log_record));
+	if (!log_record)
+		return QDF_STATUS_E_NOMEM;
+
+	log_record->timestamp_us = qdf_get_time_of_the_day_ms() * 1000;
+	log_record->fw_timestamp_us = frame_data->timestamp * 1000;
+	log_record->vdev_id = vdev_id;
+
+	log_record->pkt_info.seq_num = frame_data->seq_num;
+	log_record->pkt_info.rssi = frame_data->rssi;
+	log_record->pkt_info.tx_status = frame_data->tx_status;
+	log_record->pkt_info.frame_status_code = frame_data->status_code;
+
+	if (frame_data->type == ROAM_FRAME_INFO_FRAME_TYPE_EXT)
+		log_record->log_subtype =
+			cm_roam_get_eapol_tag(frame_data->subtype);
+	else
+		log_record->log_subtype = cm_roam_get_tag(frame_data->subtype,
+							  frame_data->is_req);
+
+	status = wlan_connectivity_log_enqueue(log_record);
+	qdf_mem_free(log_record);
+
+	return status;
+}
+#endif /* WLAN_FEATURE_CONNECTIVITY_LOGGING */
 #endif  /* WLAN_FEATURE_ROAM_OFFLOAD */

+ 75 - 0
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h

@@ -255,4 +255,79 @@ bool cm_is_auth_type_11r(struct wlan_mlme_psoc_ext_obj *mlme_obj,
 void cm_update_owe_info(struct wlan_objmgr_vdev *vdev,
 			struct wlan_cm_connect_resp *rsp, uint8_t vdev_id);
 
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+#ifdef WLAN_FEATURE_CONNECTIVITY_LOGGING
+/**
+ * cm_roam_mgmt_frame_event() - Roam management frame event
+ * @frame_data: frame_data
+ * @vdev_id: vdev_id
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+cm_roam_mgmt_frame_event(struct roam_frame_info *frame_data, uint8_t vdev_id);
+
+/**
+ * cm_roam_btm_req_event  - Send BTM request related logging event
+ * @btm_data: BTM trigger related data
+ * @vdev_id: Vdev id
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+cm_roam_btm_req_event(struct wmi_roam_btm_trigger_data *btm_data,
+		      uint8_t vdev_id);
+
+/**
+ * cm_roam_btm_resp_event() - Send BTM response logging event
+ * @btm_data: BTM response data
+ * @vdev_id: Vdev id
+ * @is_wtc: Is WTC or BTM response
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+cm_roam_btm_resp_event(struct roam_btm_response_data *btm_data,
+		       uint8_t vdev_id, bool is_wtc);
+
+/**
+ * cm_roam_btm_query_event()  - Send BTM query logging event
+ * @btm_data: BTM data
+ * @vdev_id: Vdev id
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+cm_roam_btm_query_event(struct wmi_neighbor_report_data *btm_data,
+			uint8_t vdev_id);
+
+#else
+static inline QDF_STATUS
+cm_roam_mgmt_frame_event(struct roam_frame_info *frame_data, uint8_t vdev_id)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
+static inline QDF_STATUS
+cm_roam_btm_req_event(struct wmi_roam_btm_trigger_data *btm_data,
+		      uint8_t vdev_id)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
+static inline QDF_STATUS
+cm_roam_btm_resp_event(struct roam_btm_response_data *btm_data,
+		       uint8_t vdev_id, bool is_wtc)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
+static inline QDF_STATUS
+cm_roam_btm_query_event(struct wmi_neighbor_report_data *btm_data,
+			uint8_t vdev_id)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+#endif /* FEATURE_CONNECTIVITY_LOGGING */
+#endif /* FEATURE_ROAM_OFFLOAD */
 #endif /* _WLAN_CM_ROAM_OFFLOAD_H_ */

+ 22 - 0
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h

@@ -762,6 +762,21 @@ wlan_cm_roam_extract_roam_msg_info(wmi_unified_t wmi, void *evt_buf,
 uint32_t wlan_cm_get_roam_band_value(struct wlan_objmgr_psoc *psoc,
 				     uint8_t vdev_id);
 
+/**
+ * wlan_cm_roam_extract_frame_info  - Extract the roam frame info TLV
+ * @wmi: wmi handle
+ * @evt_buf: Pointer to the event buffer
+ * @dst: Destination buffer
+ * @idx: TLV index
+ * @num_frames: Number of frame info TLVs
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_cm_roam_extract_frame_info(wmi_unified_t wmi, void *evt_buf,
+				struct roam_frame_info *dst, uint8_t idx,
+				uint8_t num_frames);
+
 /**
  * wlan_cm_roam_activate_pcl_per_vdev() - Set the PCL command to be sent per
  * vdev instead of pdev.
@@ -1105,6 +1120,13 @@ wlan_cm_roam_extract_btm_response(wmi_unified_t wmi, void *evt_buf,
 	return QDF_STATUS_E_NOSUPPORT;
 }
 
+static inline QDF_STATUS
+wlan_cm_roam_extract_frame_info(wmi_unified_t wmi, void *evt_buf,
+				struct roam_frame_info *dst, uint8_t idx)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
 static inline QDF_STATUS
 wlan_cm_roam_extract_roam_initial_info(wmi_unified_t wmi, void *evt_buf,
 				       struct roam_initial_data *dst,

+ 86 - 0
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h

@@ -168,6 +168,60 @@
 #define MIN_RSSI_2G_TO_5G_ROAM 2
 #define CM_CFG_VALID_CHANNEL_LIST_LEN 100
 
+/**
+ * enum roam_trigger_sub_reason - Roam trigger sub reasons
+ * @ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER: Roam scan triggered due to
+ * periodic timer expiry
+ * @ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER: Roam scan triggered due to
+ * inactivity detection and connected AP RSSI falls below a certain threshold
+ * @ROAM_TRIGGER_SUB_REASON_BTM_DI_TIMER: Roam scan triggered due to BTM
+ * Disassoc Imminent timeout
+ * @ROAM_TRIGGER_SUB_REASON_FULL_SCAN: Roam scan triggered due to partial scan
+ * failure
+ * @ROAM_TRIGGER_SUB_REASON_LOW_RSSI_PERIODIC: Roam scan triggered due to Low
+ * rssi periodic timer
+ * @ROAM_TRIGGER_SUB_REASON_CU_PERIODIC: Roam scan triggered due to CU periodic
+ * timer
+ * @ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY: Roam scan
+ * triggered due to periodic timer after device inactivity after low rssi
+ * trigger
+ * @ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_CU: Roam scan
+ * triggered due to first periodic timer exiry when full scan count is not 0
+ * and roam scan trigger is CU load
+ * @ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER_CU: Roam scan triggered due to
+ * first periodic timer exiry when full scan count is 0 and roam scan trigger
+ * is CU load
+ */
+enum roam_trigger_sub_reason {
+	ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER = 1,
+	ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER_LOW_RSSI,
+	ROAM_TRIGGER_SUB_REASON_BTM_DI_TIMER,
+	ROAM_TRIGGER_SUB_REASON_FULL_SCAN,
+	ROAM_TRIGGER_SUB_REASON_LOW_RSSI_PERIODIC,
+	ROAM_TRIGGER_SUB_REASON_CU_PERIODIC,
+	ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY,
+	ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_CU,
+	ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER_CU,
+};
+
+/**
+ * enum wlan_roam_frame_subtype - Roam frame subtypes
+ * @ROAM_FRAME_SUBTYPE_M1: EAPOL M1 Frame
+ * @ROAM_FRAME_SUBTYPE_M2: EAPOL M2 Frame
+ * @ROAM_FRAME_SUBTYPE_M3: EAPOL M3 Frame
+ * @ROAM_FRAME_SUBTYPE_M4: EAPOL M4 Frame
+ * @ROAM_FRAME_SUBTYPE_GTK_M1: GTK M1 Frame
+ * @ROAM_FRAME_SUBTYPE_GTK_M2: GTK M2 Frame
+ */
+enum wlan_roam_frame_subtype {
+	ROAM_FRAME_SUBTYPE_M1 = 1,
+	ROAM_FRAME_SUBTYPE_M2,
+	ROAM_FRAME_SUBTYPE_M3,
+	ROAM_FRAME_SUBTYPE_M4,
+	ROAM_FRAME_SUBTYPE_GTK_M1,
+	ROAM_FRAME_SUBTYPE_GTK_M2,
+};
+
 /**
  * struct cm_roam_neighbor_report_offload_params - neighbor report offload
  *                                                 parameters
@@ -1638,6 +1692,8 @@ enum roam_offload_state {
  *  @target_bssid:  AP MAC address
  *  @vsie_reason:   Vsie_reason value
  *  @timestamp:     This timestamp indicates the time when btm rsp is sent
+ *  @btm_resp_dialog_token: Dialog token
+ *  @btm_delay: BTM bss termination delay
  */
 struct roam_btm_response_data {
 	bool present;
@@ -1645,6 +1701,8 @@ struct roam_btm_response_data {
 	struct qdf_mac_addr target_bssid;
 	uint32_t vsie_reason;
 	uint32_t timestamp;
+	uint16_t btm_resp_dialog_token;
+	uint8_t btm_delay;
 };
 
 /**
@@ -1682,6 +1740,34 @@ struct roam_msg_info {
 	uint32_t msg_param2;
 };
 
+/**
+ * struct roam_frame_info  - Structure to hold the mgmt frame/eapol frame
+ * related info exchanged during roaming.
+ * @present:     Flag to indicate if roam frame info TLV is present
+ * @timestamp:   Fw timestamp at which the frame was Tx/Rx'ed
+ * @type:        Frame Type
+ * @subtype:     Frame subtype
+ * @is_req:      Frame is request frame or response frame
+ * @seq_num:     Frame sequence number from the 802.11 header
+ * @status_code: Status code from 802.11 spec, section 9.4.1.9
+ * @tx_status: Frame TX status defined by enum qdf_dp_tx_rx_status
+ * applicable only for tx frames
+ * @rssi: Frame rssi
+ * @retry_count: Frame retry count
+ */
+struct roam_frame_info {
+	bool present;
+	uint32_t timestamp;
+	uint8_t type;
+	uint8_t subtype;
+	uint8_t is_req;
+	enum qdf_dp_tx_rx_status tx_status;
+	uint16_t seq_num;
+	uint16_t status_code;
+	int32_t rssi;
+	uint16_t retry_count;
+};
+
 /**
  * enum wlan_cm_rso_control_requestor - Driver disabled roaming requestor that
  * will request the roam module to disable roaming based on the mlme operation

+ 23 - 4
components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c

@@ -379,6 +379,18 @@ uint32_t wlan_cm_get_roam_band_value(struct wlan_objmgr_psoc *psoc,
 	return band_mask;
 }
 
+QDF_STATUS
+wlan_cm_roam_extract_frame_info(wmi_unified_t wmi, void *evt_buf,
+				struct roam_frame_info *dst, uint8_t idx,
+				uint8_t num_frames)
+{
+	if (wmi->ops->extract_roam_msg_info)
+		return wmi->ops->extract_roam_frame_info(wmi, evt_buf,
+							 dst, idx, num_frames);
+
+	return QDF_STATUS_E_FAILURE;
+}
+
 void wlan_cm_roam_activate_pcl_per_vdev(struct wlan_objmgr_psoc *psoc,
 					uint8_t vdev_id, bool pcl_per_vdev)
 {
@@ -2687,7 +2699,7 @@ cm_roam_stats_print_trigger_info(struct wmi_roam_trigger_info *data,
  */
 static void
 cm_roam_stats_print_btm_rsp_info(struct roam_btm_response_data *data,
-				 uint8_t vdev_id)
+				 uint8_t vdev_id, bool is_wtc)
 {
 	char time[TIME_STRING_LEN];
 
@@ -2696,6 +2708,7 @@ cm_roam_stats_print_btm_rsp_info(struct roam_btm_response_data *data,
 		       QDF_MAC_ADDR_FMT, time, vdev_id, data->btm_status,
 		       data->vsie_reason,
 		       QDF_MAC_ADDR_REF(data->target_bssid.bytes));
+	cm_roam_btm_resp_event(data, vdev_id, is_wtc);
 }
 
 /**
@@ -2993,10 +3006,16 @@ cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc,
 		    (stats_info->trigger[i].trigger_reason ==
 		     ROAM_TRIGGER_REASON_WTC_BTM ||
 		     stats_info->trigger[i].trigger_reason ==
-		     ROAM_TRIGGER_REASON_BTM)))
+		     ROAM_TRIGGER_REASON_BTM))) {
+			bool is_wtc =
+				(stats_info->trigger[i].trigger_reason ==
+				 ROAM_TRIGGER_REASON_WTC_BTM);
+
 			cm_roam_stats_print_btm_rsp_info(
-							&stats_info->btm_rsp[i],
-							stats_info->vdev_id);
+						&stats_info->btm_rsp[i],
+						stats_info->vdev_id,
+						is_wtc);
+		}
 
 		if (stats_info->roam_init_info[i].present)
 			cm_roam_stats_print_roam_initial_info(

+ 109 - 0
components/wmi/src/wmi_unified_roam_tlv.c

@@ -1618,6 +1618,8 @@ extract_roam_btm_response_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf,
 				   dst->target_bssid.bytes);
 	dst->vsie_reason = src_data->vsie_reason;
 	dst->timestamp = src_data->timestamp;
+	dst->btm_resp_dialog_token = src_data->btm_resp_dialog_token;
+	dst->btm_delay = src_data->btm_resp_bss_termination_delay;
 
 	return QDF_STATUS_SUCCESS;
 }
@@ -1690,6 +1692,112 @@ extract_roam_msg_info_tlv(wmi_unified_t wmi_handle, void *evt_buf,
 	return QDF_STATUS_SUCCESS;
 }
 
+static enum wlan_roam_frame_subtype
+wmi_get_converted_roam_eapol_subtype(
+		WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE eapol_subtype)
+{
+	switch (eapol_subtype) {
+	case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE_M1:
+		return ROAM_FRAME_SUBTYPE_M1;
+	case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE_M2:
+		return ROAM_FRAME_SUBTYPE_M2;
+	case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE_M3:
+		return ROAM_FRAME_SUBTYPE_M3;
+	case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE_M4:
+		return ROAM_FRAME_SUBTYPE_M4;
+	case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE_GTK_M1:
+		return ROAM_FRAME_SUBTYPE_GTK_M1;
+	case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE_GTK_M2:
+		return ROAM_FRAME_SUBTYPE_GTK_M2;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static enum qdf_dp_tx_rx_status
+wmi_get_converted_tx_status(
+		WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_STATUS roam_tx_status)
+{
+	switch (roam_tx_status) {
+	case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_STATUS_ACK:
+		return QDF_TX_RX_STATUS_OK;
+	case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_STATUS_NO_ACK:
+		return QDF_TX_RX_STATUS_NO_ACK;
+	case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_STATUS_TX_FAIL:
+		return QDF_TX_RX_STATUS_DROP;
+	default:
+		break;
+	}
+
+	return QDF_TX_RX_STATUS_INVALID;
+}
+
+/**
+ * extract_roam_frame_info_tlv() - Extract the frame exchanges during roaming
+ * info from the WMI_ROAM_STATS_EVENTID
+ * @wmi_handle: wmi handle
+ * @evt_buf:    Pointer to the event buffer
+ * @dst:        Pointer to destination structure to fill data
+ * @idx:        TLV id
+ * @num_frames: Number of Frame TLVs to be extracted
+ */
+static QDF_STATUS
+extract_roam_frame_info_tlv(wmi_unified_t wmi_handle, void *evt_buf,
+			    struct roam_frame_info *dst, uint8_t frame_idx,
+			    uint8_t num_frames)
+{
+	WMI_ROAM_STATS_EVENTID_param_tlvs *param_buf;
+	wmi_roam_frame_info *src_data = NULL;
+	uint8_t i, subtype;
+
+	param_buf = (WMI_ROAM_STATS_EVENTID_param_tlvs *)evt_buf;
+
+	if (!param_buf || !param_buf->roam_frame_info ||
+	    !param_buf->num_roam_frame_info ||
+	    (frame_idx + num_frames) >= param_buf->num_roam_frame_info) {
+		wmi_debug("Empty roam_frame_info param buf frame_idx:%d num_frames:%d",
+			  frame_idx, num_frames);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	src_data = &param_buf->roam_frame_info[frame_idx];
+
+	if (num_frames > WLAN_ROAM_MAX_FRAME_INFO)
+		num_frames = WLAN_ROAM_MAX_FRAME_INFO;
+
+	for (i = 0; i < num_frames; i++) {
+		dst->present = true;
+		dst->timestamp = src_data->timestamp;
+		dst->type = WMI_GET_BITS(src_data->frame_info, 0, 2);
+
+		subtype = WMI_GET_BITS(src_data->frame_info, 2, 4);
+		if (dst->type == WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT) {
+			dst->type = ROAM_FRAME_INFO_FRAME_TYPE_EXT;
+			dst->subtype =
+				wmi_get_converted_roam_eapol_subtype(subtype);
+		} else {
+			dst->subtype = subtype;
+		}
+
+		dst->is_req = WMI_GET_BITS(src_data->frame_info, 6, 1);
+		dst->seq_num = WMI_GET_BITS(src_data->frame_info, 7, 16);
+		dst->status_code = src_data->status_code;
+		if (dst->is_req)
+			dst->tx_status = wmi_get_converted_tx_status(
+							src_data->status_code);
+
+		dst->retry_count = src_data->retry_count;
+		dst->rssi = (-1) * src_data->rssi_dbm_abs;
+
+		dst++;
+		src_data++;
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+
 #ifdef ROAM_TARGET_IF_CONVERGENCE
 static void
 wmi_extract_pdev_hw_mode_trans_ind(
@@ -3145,6 +3253,7 @@ void wmi_roam_offload_attach_tlv(wmi_unified_t wmi_handle)
 				extract_roam_btm_response_stats_tlv;
 	ops->extract_roam_initial_info = extract_roam_initial_info_tlv;
 	ops->extract_roam_msg_info = extract_roam_msg_info_tlv;
+	ops->extract_roam_frame_info = extract_roam_frame_info_tlv;
 #ifdef ROAM_TARGET_IF_CONVERGENCE
 	ops->extract_roam_sync_event = extract_roam_sync_event_tlv;
 	ops->extract_roam_sync_frame_event = extract_roam_sync_frame_event_tlv;

+ 103 - 10
core/wma/src/wma_scan_roam.c

@@ -67,6 +67,7 @@
 #include "wlan_reg_services_api.h"
 #include "wlan_roam_debug.h"
 #include "wlan_mlme_public_struct.h"
+#include "wlan_mgmt_txrx_utils_api.h"
 
 /* This is temporary, should be removed */
 #include "ol_htt_api.h"
@@ -1566,7 +1567,8 @@ int wma_roam_scan_chan_list_event_handler(WMA_HANDLE handle,
  * Return: None
  */
 static void
-wma_get_trigger_detail_str(struct wmi_roam_trigger_info *roam_info, char *buf)
+wma_get_trigger_detail_str(struct wmi_roam_trigger_info *roam_info, char *buf,
+			   uint8_t vdev_id)
 {
 	uint16_t buf_cons, buf_left = MAX_ROAM_DEBUG_BUF_SIZE;
 	char *temp = buf;
@@ -1597,6 +1599,9 @@ wma_get_trigger_detail_str(struct wmi_roam_trigger_info *roam_info, char *buf)
 	case WMI_ROAM_TRIGGER_REASON_BTC:
 		return;
 	case WMI_ROAM_TRIGGER_REASON_BTM:
+		roam_info->btm_trig_data.timestamp = roam_info->timestamp;
+		cm_roam_btm_req_event(&roam_info->btm_trig_data, vdev_id);
+
 		buf_cons = qdf_snprint(temp, buf_left,
 				       "Req_mode: %d Disassoc_timer: %d",
 				       roam_info->btm_trig_data.btm_request_mode,
@@ -1696,7 +1701,7 @@ wma_rso_print_trigger_info(struct wmi_roam_trigger_info *data, uint8_t vdev_id)
 	if (!buf)
 		return;
 
-	wma_get_trigger_detail_str(data, buf);
+	wma_get_trigger_detail_str(data, buf, vdev_id);
 	mlme_get_converted_timestamp(data->timestamp, time);
 	wma_nofl_info("%s [ROAM_TRIGGER]: VDEV[%d] %s", time, vdev_id, buf);
 
@@ -1707,6 +1712,7 @@ wma_rso_print_trigger_info(struct wmi_roam_trigger_info *data, uint8_t vdev_id)
  * wma_rso_print_btm_rsp_info - BTM RSP related details
  * @data:    Pointer to the btm rsp data
  * @vdev_id: vdev id
+ * @is_wtc: is wtc or btm response frame
  *
  * Prints the vdev, btm status, target_bssid and vsie reason
  *
@@ -1714,7 +1720,7 @@ wma_rso_print_trigger_info(struct wmi_roam_trigger_info *data, uint8_t vdev_id)
  */
 static void
 wma_rso_print_btm_rsp_info(struct roam_btm_response_data *data,
-			   uint8_t vdev_id)
+			   uint8_t vdev_id, uint8_t is_wtc)
 {
 	char time[TIME_STRING_LEN];
 
@@ -1722,6 +1728,7 @@ wma_rso_print_btm_rsp_info(struct roam_btm_response_data *data,
 	wma_nofl_info("%s [BTM RSP]: VDEV[%d], Status: %d, VSIE reason: %d, BSSID: " QDF_MAC_ADDR_FMT,
 		      time, vdev_id, data->btm_status, data->vsie_reason,
 		      QDF_MAC_ADDR_REF(data->target_bssid.bytes));
+	cm_roam_btm_resp_event(data, vdev_id, is_wtc);
 }
 
 /**
@@ -1955,6 +1962,8 @@ wma_rso_print_11kv_info(struct wmi_neighbor_report_data *neigh_rpt,
 	mlme_get_converted_timestamp(neigh_rpt->req_time, time);
 	wma_nofl_info("%s [%s] VDEV[%d]", time,
 		      (type == 1) ? "BTM_QUERY" : "NEIGH_RPT_REQ", vdev_id);
+	if (type == 1)
+		cm_roam_btm_query_event(neigh_rpt, vdev_id);
 
 	if (neigh_rpt->resp_time) {
 		mlme_get_converted_timestamp(neigh_rpt->resp_time, time1);
@@ -1969,6 +1978,47 @@ wma_rso_print_11kv_info(struct wmi_neighbor_report_data *neigh_rpt,
 	qdf_mem_free(buf);
 }
 
+static char *
+wma_get_frame_subtype_str(enum mgmt_subtype frame_subtype)
+{
+	switch (frame_subtype) {
+	case MGMT_SUBTYPE_ASSOC_REQ:
+		return "ASSOC";
+	case MGMT_SUBTYPE_ASSOC_RESP:
+		return "ASSOC";
+	case MGMT_SUBTYPE_REASSOC_REQ:
+		return "REASSOC";
+	case MGMT_SUBTYPE_REASSOC_RESP:
+		return "REASSOC";
+	case MGMT_SUBTYPE_DISASSOC:
+		return "DISASSOC";
+	case MGMT_SUBTYPE_AUTH:
+		return "AUTH";
+	case MGMT_SUBTYPE_DEAUTH:
+		return "DEAUTH";
+	default:
+		break;
+	}
+
+	return "Invalid frm";
+}
+
+static void
+wma_rso_print_frame_info(struct roam_frame_info *frame_data, uint8_t vdev_id)
+{
+	char time[TIME_STRING_LEN];
+
+	if (!frame_data->present)
+		return;
+
+	mlme_get_converted_timestamp(frame_data->timestamp, time);
+	wma_nofl_info("%s [%s %s] VDEV[%d] status:%d seq_num:%d", time,
+		      wma_get_frame_subtype_str(frame_data->subtype),
+		      frame_data->is_req ? "REQ" : "RESP", vdev_id,
+		      frame_data->status_code, frame_data->seq_num);
+	cm_roam_mgmt_frame_event(frame_data, vdev_id);
+}
+
 int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event,
 				 uint32_t len)
 {
@@ -1976,8 +2026,9 @@ int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event,
 	WMI_ROAM_STATS_EVENTID_param_tlvs *param_buf;
 	wmi_roam_stats_event_fixed_param *fixed_param;
 	struct mlme_roam_debug_info *roam_info = NULL;
-	uint8_t vdev_id, i;
+	uint8_t vdev_id, i, k;
 	uint8_t num_tlv = 0, num_chan = 0, num_ap = 0, num_rpt = 0, rem_tlv = 0;
+	uint8_t num_frames = 0, num_btm = 0;
 	uint32_t rem_len;
 	QDF_STATUS status;
 
@@ -2079,6 +2130,14 @@ int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event,
 		goto err;
 	}
 
+	rem_len -= param_buf->num_roam_msg_info *
+			sizeof(wmi_roam_msg_info);
+	if (rem_len < param_buf->num_roam_frame_info *
+			sizeof(wmi_roam_frame_info)) {
+		wma_err_rl("Invalid roam frm info");
+		goto err;
+	}
+
 	for (i = 0; i < num_tlv; i++) {
 		roam_info = qdf_mem_malloc(sizeof(*roam_info));
 		if (!roam_info)
@@ -2090,7 +2149,8 @@ int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event,
 		 */
 		status = wmi_unified_extract_roam_trigger_stats(
 						wma->wmi_handle, event,
-						&roam_info->trigger, i);
+						&roam_info->trigger, i,
+						num_btm);
 		if (QDF_IS_STATUS_ERROR(status)) {
 			wma_debug_rl("Extract roam trigger stats failed vdev %d at %d iteration",
 				     vdev_id, i);
@@ -2098,6 +2158,10 @@ int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event,
 			return -EINVAL;
 		}
 
+		if (roam_info->trigger.trigger_reason ==
+		    WMI_ROAM_TRIGGER_REASON_BTM)
+			num_btm += roam_info->trigger.btm_trig_data.candidate_list_count;
+
 		if (roam_info->trigger.present) {
 			wma_rso_print_trigger_info(&roam_info->trigger,
 						   vdev_id);
@@ -2141,6 +2205,26 @@ int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event,
 						roam_info->result.fail_reason,
 						ROAM_FAIL_REASON);
 		}
+
+		status = wlan_cm_roam_extract_frame_info(
+				wma->wmi_handle, event,
+				roam_info->frame_info, num_frames,
+				roam_info->scan.frame_info_count);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			wma_debug_rl("Roam frame extract failed vdev %d at %d iteration",
+				     vdev_id, i);
+			qdf_mem_free(roam_info);
+			return -EINVAL;
+		}
+		num_frames += roam_info->scan.frame_info_count;
+
+		if (roam_info->scan.frame_info_count) {
+			for (k = 0; k <= roam_info->scan.frame_info_count; k++)
+				wma_rso_print_frame_info(
+						&roam_info->frame_info[k],
+						vdev_id);
+		}
+
 		/* BTM resp info */
 		status = wlan_cm_roam_extract_btm_response(wma->wmi_handle,
 							   event,
@@ -2163,9 +2247,13 @@ int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event,
 		    (roam_info->trigger.trigger_reason ==
 		     WMI_ROAM_TRIGGER_REASON_WTC_BTM ||
 		     roam_info->trigger.trigger_reason ==
-		     WMI_ROAM_TRIGGER_REASON_BTM)))
+		     WMI_ROAM_TRIGGER_REASON_BTM))) {
+			bool is_wtc =
+				(roam_info->trigger.trigger_reason ==
+				 ROAM_TRIGGER_REASON_WTC_BTM);
 			wma_rso_print_btm_rsp_info(&roam_info->btm_rsp,
-						   vdev_id);
+						   vdev_id, is_wtc);
+		}
 
 		/* Initial Roam info */
 		status = wlan_cm_roam_extract_roam_initial_info(
@@ -2234,7 +2322,7 @@ int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event,
 
 		status = wmi_unified_extract_roam_trigger_stats(
 						wma->wmi_handle, event,
-						&roam_info->trigger, 0);
+						&roam_info->trigger, 0, 0);
 		if (QDF_IS_STATUS_ERROR(status)) {
 			wma_debug_rl("Extract roam trigger stats failed vdev %d",
 				     vdev_id);
@@ -2273,9 +2361,14 @@ int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event,
 			return -EINVAL;
 		}
 
-		if (roam_info->btm_rsp.present)
+		if (roam_info->btm_rsp.present) {
+			bool is_wtc =
+				(roam_info->trigger.present &&
+				 roam_info->trigger.trigger_reason ==
+				 ROAM_TRIGGER_REASON_WTC_BTM);
 			wma_rso_print_btm_rsp_info(&roam_info->btm_rsp,
-						   vdev_id);
+						   vdev_id, is_wtc);
+		}
 
 		qdf_mem_free(roam_info);
 	}