Jelajahi Sumber

qcacld-3.0: Fix ROAM/NO_ROAM print conditions

As part of the Roam candidate result logging, the
driver prints ROAM if reassociation is successful and
NO_ROAM if candidate is found and roaming is successful.
But the expectation is to print ROAM even if candidate
is found and roaming has failed.

Change the logic to print ROAM/NO_ROAM based on below condition:
1. Roam result successful -> ROAM
2. Roam result failure && candidate is found -> ROAM
3. ROam result failure && candidate is not found -> NO_ROAM

Fix the authentication/association missing frame print
in the roam logging, also cleanup the unused API's.

Change-Id: I43e0cea007890f4796b421b0a42cc71b8ca1a600
CRs-Fixed: 3146630
Pragaspathi Thilagaraj 3 tahun lalu
induk
melakukan
4648e9fece

+ 77 - 23
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c

@@ -5343,8 +5343,14 @@ void cm_roam_result_info_event(struct wmi_roam_result *res,
 {
 	struct wlan_log_record *log_record = NULL;
 	uint8_t i;
+	bool ap_found_in_roam_scan = false;
 	bool roam_abort = (res->fail_reason == ROAM_FAIL_REASON_SYNC ||
-			   res->fail_reason == ROAM_FAIL_REASON_INTERNAL_ABORT);
+			   res->fail_reason == ROAM_FAIL_REASON_DISCONNECT ||
+			   res->fail_reason == ROAM_FAIL_REASON_HOST ||
+			   res->fail_reason ==
+					ROAM_FAIL_REASON_INTERNAL_ABORT ||
+			   res->fail_reason ==
+				ROAM_FAIL_REASON_UNABLE_TO_START_ROAM_HO);
 
 	log_record = qdf_mem_malloc(sizeof(*log_record));
 	if (!log_record)
@@ -5352,33 +5358,65 @@ void cm_roam_result_info_event(struct wmi_roam_result *res,
 
 	log_record->vdev_id = vdev_id;
 	log_record->timestamp_us = qdf_get_time_of_the_day_us();
+	log_record->fw_timestamp_us = (uint64_t)res->timestamp * 1000;
+
+	for (i = 0; i < scan_data->num_ap && scan_data->present; i++) {
+		if (i >= MAX_ROAM_CANDIDATE_AP)
+			break;
+
+		if (scan_data->ap[i].type == WLAN_ROAM_SCAN_ROAMED_AP ||
+		    scan_data->ap[i].type == WLAN_ROAM_SCAN_CANDIDATE_AP) {
+			ap_found_in_roam_scan = true;
+			break;
+		}
+	}
+
+	log_record->log_subtype = WLAN_ROAM_RESULT;
+	log_record->roam_result.roam_fail_reason = res->fail_reason;
+	/*
+	 * Print ROAM if:
+	 * 1. Roaming is successful to AP
+	 * 2. Atleast one candidate AP found during scan
+	 *
+	 * Print NO_ROAM only if:
+	 * 1. No candidate AP found(eventhough other APs are found in scan)
+	 */
+	log_record->roam_result.is_roam_successful =
+		(res->status == 0) ||
+		(ap_found_in_roam_scan &&
+		 res->fail_reason != ROAM_FAIL_REASON_NO_CAND_AP_FOUND);
+
+	for (i = 0; i < scan_data->num_ap; i++) {
+		if (i >= MAX_ROAM_CANDIDATE_AP)
+			break;
+
+		if (scan_data->ap[i].type == WLAN_ROAM_SCAN_ROAMED_AP &&
+		    log_record->roam_result.is_roam_successful) {
+			log_record->bssid = scan_data->ap[i].bssid;
+			break;
+		} else if (scan_data->ap[i].type ==
+			   WLAN_ROAM_SCAN_CURRENT_AP &&
+			   !log_record->roam_result.is_roam_successful) {
+			log_record->bssid = scan_data->ap[i].bssid;
+			break;
+		}
+	}
+
+	wlan_connectivity_log_enqueue(log_record);
+	qdf_mem_zero(log_record, sizeof(*log_record));
+
 	if (roam_abort) {
+		log_record->vdev_id = vdev_id;
+		log_record->timestamp_us = qdf_get_time_of_the_day_us();
+		log_record->fw_timestamp_us = (uint64_t)res->timestamp * 1000;
+
 		log_record->log_subtype = WLAN_ROAM_CANCEL;
 		log_record->fw_timestamp_us = log_record->timestamp_us;
 		log_record->roam_result.roam_fail_reason = res->fail_reason;
-	} else {
-		log_record->log_subtype = WLAN_ROAM_RESULT;
-		log_record->fw_timestamp_us = (uint64_t)res->timestamp * 1000;
-		log_record->roam_result.roam_fail_reason = res->fail_reason;
-		log_record->roam_result.is_roam_successful = (res->status == 0);
-		for (i = 0; i < scan_data->num_ap; i++) {
-			if (i >= MAX_ROAM_CANDIDATE_AP)
-				break;
 
-			if (scan_data->ap[i].type == WLAN_ROAM_SCAN_ROAMED_AP &&
-			    log_record->roam_result.is_roam_successful) {
-				log_record->bssid = scan_data->ap[i].bssid;
-				break;
-			} else if (scan_data->ap[i].type ==
-				   WLAN_ROAM_SCAN_CURRENT_AP &&
-				   !log_record->roam_result.is_roam_successful) {
-				log_record->bssid = scan_data->ap[i].bssid;
-				break;
-			}
-		}
+		wlan_connectivity_log_enqueue(log_record);
 	}
 
-	wlan_connectivity_log_enqueue(log_record);
 	qdf_mem_free(log_record);
 }
 #endif  /* WLAN_FEATURE_CONNECTIVITY_LOGGING */
@@ -5825,10 +5863,12 @@ cm_roam_btm_req_event(struct wmi_roam_btm_trigger_data *btm_data,
 }
 
 QDF_STATUS
-cm_roam_mgmt_frame_event(struct roam_frame_info *frame_data, uint8_t vdev_id)
+cm_roam_mgmt_frame_event(struct roam_frame_info *frame_data,
+			 struct wmi_roam_scan_data *scan_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)
@@ -5843,12 +5883,26 @@ cm_roam_mgmt_frame_event(struct roam_frame_info *frame_data, uint8_t vdev_id)
 	log_record->pkt_info.tx_status = frame_data->tx_status;
 	log_record->pkt_info.frame_status_code = frame_data->status_code;
 
+	if (scan_data->present) {
+		for (i = 0; i < scan_data->num_ap; i++) {
+			if (i >= MAX_ROAM_CANDIDATE_AP)
+				break;
+
+			if (scan_data->ap[i].type == WLAN_ROAM_SCAN_ROAMED_AP) {
+				log_record->pkt_info.rssi =
+					(-1) * scan_data->ap[i].rssi;
+				log_record->bssid = scan_data->ap[i].bssid;
+				break;
+			}
+		}
+	}
+
 	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);
+							  !frame_data->is_rsp);
 
 	status = wlan_connectivity_log_enqueue(log_record);
 	qdf_mem_free(log_record);

+ 5 - 2
components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h

@@ -393,12 +393,14 @@ cm_handle_mlo_rso_state_change(struct wlan_objmgr_pdev *pdev,
 /**
  * cm_roam_mgmt_frame_event() - Roam management frame event
  * @frame_data: frame_data
+ * @scan_data: Roam scan 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_mgmt_frame_event(struct roam_frame_info *frame_data,
+			 struct wmi_roam_scan_data *scan_data, uint8_t vdev_id);
 
 /**
  * cm_roam_btm_req_event  - Send BTM request related logging event
@@ -450,7 +452,8 @@ cm_roam_beacon_loss_disconnect_event(struct qdf_mac_addr bssid, int32_t rssi,
 				     uint8_t vdev_id);
 #else
 static inline QDF_STATUS
-cm_roam_mgmt_frame_event(struct roam_frame_info *frame_data, uint8_t vdev_id)
+cm_roam_mgmt_frame_event(struct roam_frame_info *frame_data,
+			 struct wmi_roam_scan_data *scan_data, uint8_t vdev_id)
 {
 	return QDF_STATUS_E_NOSUPPORT;
 }

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

@@ -715,47 +715,6 @@ static inline QDF_STATUS wlan_cm_host_roam_start(struct scheduler_msg *msg)
 QDF_STATUS
 wlan_cm_fw_roam_abort_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id);
 
-/**
- * wlan_cm_roam_extract_btm_response() - Extract BTM rsp stats
- * @wmi:       wmi handle
- * @evt_buf:   Pointer to the event buffer
- * @dst:       Pointer to destination structure to fill data
- * @idx:       TLV id
- *
- * Return: QDF_STATUS
- */
-QDF_STATUS
-wlan_cm_roam_extract_btm_response(wmi_unified_t wmi, void *evt_buf,
-				  struct roam_btm_response_data *dst,
-				  uint8_t idx);
-
-/**
- * wlan_cm_roam_extract_roam_initial_info() - Extract Roam Initial stats
- * @wmi:       wmi handle
- * @evt_buf:   Pointer to the event buffer
- * @dst:       Pointer to destination structure to fill data
- * @idx:       TLV id
- *
- * Return: QDF_STATUS
- */
-QDF_STATUS
-wlan_cm_roam_extract_roam_initial_info(wmi_unified_t wmi, void *evt_buf,
-				       struct roam_initial_data *dst,
-				       uint8_t idx);
-
-/**
- * wlan_cm_roam_extract_roam_msg_info() - Extract Roam msg stats
- * @wmi:       wmi handle
- * @evt_buf:   Pointer to the event buffer
- * @dst:       Pointer to destination structure to fill data
- * @idx:       TLV id
- *
- * Return: QDF_STATUS
- */
-QDF_STATUS
-wlan_cm_roam_extract_roam_msg_info(wmi_unified_t wmi, void *evt_buf,
-				   struct roam_msg_info *dst, uint8_t idx);
-
 /**
  * wlan_cm_get_roam_band_value  - Get roam band value from RSO config
  * @psoc: psoc pointer
@@ -766,21 +725,6 @@ 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,
 				     struct wlan_objmgr_vdev *vdev);
 
-/**
- * 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.

+ 14 - 2
components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h

@@ -1894,7 +1894,7 @@ enum roam_rt_stats_type {
  * @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
+ * @is_rsp:      True if frame is response frame else false
  * @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
@@ -1907,7 +1907,7 @@ struct roam_frame_info {
 	uint32_t timestamp;
 	uint8_t type;
 	uint8_t subtype;
-	uint8_t is_req;
+	uint8_t is_rsp;
 	enum qdf_dp_tx_rx_status tx_status;
 	uint16_t seq_num;
 	uint16_t status_code;
@@ -2158,6 +2158,16 @@ struct roam_offload_roam_event {
 	bool rso_timer_stopped;
 };
 
+/**
+ * struct roam_frame_stats  - Roam frame stats
+ * @num_frame: number of frames
+ * @frame_info: Roam frame info
+ */
+struct roam_frame_stats {
+	uint8_t num_frame;
+	struct roam_frame_info frame_info[WLAN_ROAM_MAX_FRAME_INFO];
+};
+
 /**
  * struct roam_stats_event - Data carried by stats event
  * @vdev_id: vdev id
@@ -2166,6 +2176,7 @@ struct roam_offload_roam_event {
  * @trigger: Roam trigger related details
  * @scan: Roam scan event details
  * @result: Roam result related info
+ * @frame_stats: Info on frame exchange during roaming
  * @data_11kv: Neighbor report/BTM request related data
  * @btm_rsp: BTM response related data
  * @roam_init_info: Roam initial related data
@@ -2179,6 +2190,7 @@ struct roam_stats_event {
 	struct wmi_roam_trigger_info trigger[MAX_ROAM_SCAN_STATS_TLV];
 	struct wmi_roam_scan_data scan[MAX_ROAM_SCAN_STATS_TLV];
 	struct wmi_roam_result result[MAX_ROAM_SCAN_STATS_TLV];
+	struct roam_frame_stats frame_stats[MAX_ROAM_SCAN_STATS_TLV];
 	struct wmi_neighbor_report_data data_11kv[MAX_ROAM_SCAN_STATS_TLV];
 	struct roam_btm_response_data btm_rsp[MAX_ROAM_SCAN_STATS_TLV];
 	struct roam_initial_data roam_init_info[MAX_ROAM_SCAN_STATS_TLV];

+ 60 - 46
components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c

@@ -322,40 +322,6 @@ wlan_cm_fw_roam_abort_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
 	return cm_fw_roam_abort_req(psoc, vdev_id);
 }
 
-QDF_STATUS
-wlan_cm_roam_extract_btm_response(wmi_unified_t wmi, void *evt_buf,
-				  struct roam_btm_response_data *dst,
-				  uint8_t idx)
-{
-	if (wmi->ops->extract_roam_btm_response_stats)
-		return wmi->ops->extract_roam_btm_response_stats(wmi, evt_buf,
-								 dst, idx);
-
-	return QDF_STATUS_E_FAILURE;
-}
-
-QDF_STATUS
-wlan_cm_roam_extract_roam_initial_info(wmi_unified_t wmi, void *evt_buf,
-				       struct roam_initial_data *dst,
-				       uint8_t idx)
-{
-	if (wmi->ops->extract_roam_initial_info)
-		return wmi->ops->extract_roam_initial_info(wmi, evt_buf,
-							   dst, idx);
-
-	return QDF_STATUS_E_FAILURE;
-}
-
-QDF_STATUS
-wlan_cm_roam_extract_roam_msg_info(wmi_unified_t wmi, void *evt_buf,
-				   struct roam_msg_info *dst, uint8_t idx)
-{
-	if (wmi->ops->extract_roam_msg_info)
-		return wmi->ops->extract_roam_msg_info(wmi, evt_buf, dst, idx);
-
-	return QDF_STATUS_E_FAILURE;
-}
-
 uint32_t wlan_cm_get_roam_band_value(struct wlan_objmgr_psoc *psoc,
 				     struct wlan_objmgr_vdev *vdev)
 {
@@ -370,18 +336,6 @@ 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)
 {
@@ -3062,6 +3016,61 @@ cm_roam_stats_print_11kv_info(struct wmi_neighbor_report_data *neigh_rpt,
 	qdf_mem_free(buf);
 }
 
+static char *
+cm_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
+cm_roam_print_frame_info(struct roam_frame_stats *frame_data,
+			 struct wmi_roam_scan_data *scan_data, uint8_t vdev_id)
+{
+	struct roam_frame_info *frame_info;
+	char time[TIME_STRING_LEN];
+	uint8_t i;
+
+	if (!frame_data->num_frame)
+		return;
+
+	for (i = 0; i < frame_data->num_frame; i++) {
+		frame_info = &frame_data->frame_info[i];
+		qdf_mem_zero(time, TIME_STRING_LEN);
+		mlme_get_converted_timestamp(frame_info->timestamp, time);
+
+		if (frame_info->type != ROAM_FRAME_INFO_FRAME_TYPE_EXT)
+			mlme_nofl_info("%s [%s%s] VDEV[%d] status:%d seq_num:%d",
+				       time,
+				       cm_get_frame_subtype_str(frame_info->subtype),
+				       frame_info->subtype ==  MGMT_SUBTYPE_AUTH ?
+				       (frame_info->is_rsp ? " RX" : " TX") : "",
+				       vdev_id,
+				       frame_info->status_code,
+				       frame_info->seq_num);
+
+		cm_roam_mgmt_frame_event(frame_info, scan_data, vdev_id);
+	}
+}
+
 void cm_report_roam_rt_stats(struct wlan_objmgr_psoc *psoc,
 			     uint8_t vdev_id,
 			     enum roam_rt_stats_type events,
@@ -3172,6 +3181,11 @@ cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc,
 				goto err;
 		}
 
+		if (stats_info->frame_stats[i].num_frame)
+			cm_roam_print_frame_info(&stats_info->frame_stats[i],
+						 &stats_info->scan[i],
+						 stats_info->vdev_id);
+
 		if (stats_info->data_11kv[i].present)
 			cm_roam_stats_print_11kv_info(&stats_info->data_11kv[i],
 						      stats_info->vdev_id);

+ 16 - 0
components/wmi/inc/wmi_unified_roam_api.h

@@ -382,6 +382,22 @@ wmi_extract_roam_stats_event(wmi_unified_t wmi_handle,
 			     uint8_t *event, uint32_t data_len,
 			     struct roam_stats_event **stats_info);
 
+/**
+ * wmi_unified_extract_roam_extract_frame_info() - Extract the roam frame
+ * info TLV from roam stats event
+ * @wmi:        wmi handle
+ * @evt_buf:    Pointer to the event buffer
+ * @dst:        Pointer to destination structure to fill data
+ * @idx:        Index of the TLV to read
+ * @num_frames: Number of TLV to read
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wmi_unified_extract_roam_extract_frame_info(wmi_unified_t wmi, void *evt_buf,
+					    struct roam_frame_stats *dst,
+					    uint8_t idx, uint8_t num_frames);
+
 /**
  * wmi_extract_auth_offload_event  - Extract auth offload event
  * @wmi_handle: WMI handle

+ 12 - 0
components/wmi/src/wmi_unified_roam_api.c

@@ -449,6 +449,18 @@ wmi_unified_extract_roam_msg_info(wmi_unified_t wmi, void *evt_buf,
 	return QDF_STATUS_E_FAILURE;
 }
 
+QDF_STATUS
+wmi_unified_extract_roam_extract_frame_info(wmi_unified_t wmi, void *evt_buf,
+					    struct roam_frame_stats *dst,
+					    uint8_t idx, uint8_t num_frames)
+{
+	if (wmi->ops->extract_roam_frame_info)
+		return wmi->ops->extract_roam_frame_info(wmi, evt_buf,
+							 dst, idx, num_frames);
+
+	return QDF_STATUS_E_FAILURE;
+}
+
 QDF_STATUS
 wmi_extract_roam_stats_event(wmi_unified_t wmi_handle,
 			     uint8_t *event, uint32_t data_len,

+ 46 - 18
components/wmi/src/wmi_unified_roam_tlv.c

@@ -1745,6 +1745,7 @@ wmi_get_converted_tx_status(
 	return QDF_TX_RX_STATUS_INVALID;
 }
 
+#define WLAN_FC0_SUBTYPE_SHIFT         4
 /**
  * extract_roam_frame_info_tlv() - Extract the frame exchanges during roaming
  * info from the WMI_ROAM_STATS_EVENTID
@@ -1756,18 +1757,19 @@ wmi_get_converted_tx_status(
  */
 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,
+			    struct roam_frame_stats *dst, uint8_t frame_idx,
 			    uint8_t num_frames)
 {
 	WMI_ROAM_STATS_EVENTID_param_tlvs *param_buf;
 	wmi_roam_frame_info *src_data = NULL;
+	struct roam_frame_info *dst_buf;
 	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) {
+	    (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;
@@ -1778,31 +1780,35 @@ extract_roam_frame_info_tlv(wmi_unified_t wmi_handle, void *evt_buf,
 	if (num_frames > WLAN_ROAM_MAX_FRAME_INFO)
 		num_frames = WLAN_ROAM_MAX_FRAME_INFO;
 
+	dst->num_frame = num_frames;
+	dst_buf = dst->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);
+		dst_buf->timestamp = src_data->timestamp;
+		dst_buf->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 =
+		if (dst_buf->type == WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT) {
+			dst_buf->type = ROAM_FRAME_INFO_FRAME_TYPE_EXT;
+			dst_buf->subtype =
 				wmi_get_converted_roam_eapol_subtype(subtype);
 		} else {
-			dst->subtype = subtype;
+			dst_buf->subtype = subtype << WLAN_FC0_SUBTYPE_SHIFT;
 		}
 
-		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(
+		dst_buf->is_rsp = WMI_GET_BITS(src_data->frame_info, 6, 1);
+		dst_buf->is_rsp &=
+			(dst_buf->type != WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT &&
+			 dst_buf->subtype == MGMT_SUBTYPE_AUTH);
+		dst_buf->seq_num = WMI_GET_BITS(src_data->frame_info, 7, 16);
+		dst_buf->status_code = src_data->status_code;
+		if (!dst_buf->is_rsp)
+			dst_buf->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_buf->retry_count = src_data->retry_count;
+		dst_buf->rssi = (-1) * src_data->rssi_dbm_abs;
 
-		dst++;
+		dst_buf++;
 		src_data++;
 	}
 
@@ -2922,7 +2928,7 @@ extract_roam_stats_event_tlv(wmi_unified_t wmi_handle, uint8_t *evt_buf,
 	wmi_roam_stats_event_fixed_param *fixed_param;
 	struct roam_stats_event *stats_info;
 	struct roam_msg_info *roam_msg_info = NULL;
-	uint8_t vdev_id, i, num_btm = 0;
+	uint8_t vdev_id, i, num_btm = 0, num_frames = 0;
 	uint8_t num_tlv = 0, num_chan = 0, num_ap = 0, num_rpt = 0;
 	uint32_t rem_len;
 	QDF_STATUS status;
@@ -3025,6 +3031,14 @@ extract_roam_stats_event_tlv(wmi_unified_t wmi_handle, uint8_t *evt_buf,
 		wmi_err_rl("Invalid roam msg info");
 		return QDF_STATUS_E_INVAL;
 	}
+
+	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)) {
+		wmi_err_rl("Invalid roam frame info");
+		return QDF_STATUS_E_INVAL;
+	}
+
 	stats_info = qdf_mem_malloc(sizeof(struct roam_stats_event));
 	if (!stats_info) {
 		status = QDF_STATUS_E_NOMEM;
@@ -3073,6 +3087,7 @@ extract_roam_stats_event_tlv(wmi_unified_t wmi_handle, uint8_t *evt_buf,
 		}
 		num_chan += stats_info->scan[i].num_chan;
 		num_ap += stats_info->scan[i].num_ap;
+		num_frames = stats_info->scan[i].frame_info_count;
 
 		/* Roam result - Success/Failure status, failure reason */
 		status = wmi_unified_extract_roam_result_stats(wmi_handle,
@@ -3085,6 +3100,19 @@ extract_roam_stats_event_tlv(wmi_unified_t wmi_handle, uint8_t *evt_buf,
 			goto err;
 		}
 
+		if (num_frames) {
+			status = wmi_unified_extract_roam_extract_frame_info(
+					wmi_handle, evt_buf,
+					&stats_info->frame_stats[i], i,
+					num_frames);
+			if (QDF_IS_STATUS_ERROR(status)) {
+				wmi_debug_rl("Roam frame stats extract failed vdev %d at %d iteration",
+					     vdev_id, i);
+				status = QDF_STATUS_E_INVAL;
+				goto err;
+			}
+		}
+
 		/* BTM req/resp or Neighbor report/response info */
 		status = wmi_unified_extract_roam_11kv_stats(
 				      wmi_handle,