Browse Source

qcacld-3.0: Use field-by-field assignment for FW stats

In wma_unified_link_iface_stats_event_handler, FW stats is cast into
some host data structure via memory copy. It could be dangerous since
there could be some mismatch between host and FW data structures.
Update it with field-by-field assignment.

Change-Id: If90c6062551c8769d948b3267dfa323fba310a78
CRs-Fixed: 2274034
Min Liu 6 years ago
parent
commit
ffb250d8af
4 changed files with 96 additions and 225 deletions
  1. 41 37
      core/hdd/src/wlan_hdd_debugfs_llstat.c
  2. 29 28
      core/hdd/src/wlan_hdd_stats.c
  3. 5 116
      core/mac/inc/sir_api.h
  4. 21 44
      core/wma/src/wma_utils.c

+ 41 - 37
core/hdd/src/wlan_hdd_debugfs_llstat.c

@@ -42,8 +42,9 @@ void hdd_debugfs_process_iface_stats(struct hdd_adapter *adapter,
 {
 	tpSirWifiIfaceStat iface_stat;
 	tpSirWifiInterfaceInfo iface_info;
-	tpSirWifiWmmAcStat ac_stat;
-	struct wifi_iface_offload_stat *offload_stat;
+	wmi_iface_link_stats *link_stats;
+	wmi_wmm_ac_stats *ac_stats;
+	wmi_iface_offload_stats *offload_stats;
 	uint64_t average_tsf_offset;
 	int i;
 	ssize_t len = 0;
@@ -81,47 +82,50 @@ void hdd_debugfs_process_iface_stats(struct hdd_adapter *adapter,
 			&iface_info->bssid.bytes[0], iface_info->apCountryStr,
 			iface_info->countryStr);
 
-	average_tsf_offset =  iface_stat->avg_bcn_spread_offset_high;
+	link_stats = &iface_stat->link_stats;
+	average_tsf_offset =  link_stats->avg_bcn_spread_offset_high;
 	average_tsf_offset =  (average_tsf_offset << 32) |
-				iface_stat->avg_bcn_spread_offset_low;
+				link_stats->avg_bcn_spread_offset_low;
 
 	buffer += len;
 	ll_stats.len += len;
 	len = scnprintf(buffer, DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len,
 			"\nbeacon_rx: %u, mgmt_rx: %u, mgmt_action_rx: %u, mgmt_action_tx: %u, rssi_mgmt: %u, rssi_data: %u, rssi_ack: %u, is_leaky_ap: %u, avg_rx_frms_leaked: %u, rx_leak_window: %u, average_tsf_offset: %llu, Tx RTS success count: %u, Tx RTS fail count: %u, Tx ppdu success count: %u, Tx ppdu fail count: %u, Connected duration: %u, Disconnected duration: %u, RTT ranging duration: %u, RTT responder duration: %u, Num tx probes: %u, Num beacon miss: %u,\n\nNumber of AC: %d",
-			iface_stat->beaconRx, iface_stat->mgmtRx,
-			iface_stat->mgmtActionRx, iface_stat->mgmtActionTx,
-			iface_stat->rssiMgmt, iface_stat->rssiData,
-			iface_stat->rssiAck, iface_stat->is_leaky_ap,
-			iface_stat->avg_rx_frms_leaked,
-			iface_stat->rx_leak_window, average_tsf_offset,
-			iface_stat->tx_rts_succ_cnt,
-			iface_stat->tx_rts_fail_cnt,
-			iface_stat->tx_ppdu_succ_cnt,
-			iface_stat->tx_ppdu_fail_cnt,
-			iface_stat->connected_duration,
-			iface_stat->disconnected_duration,
-			iface_stat->rtt_ranging_duration,
-			iface_stat->rtt_responder_duration,
-			iface_stat->num_probes_tx, iface_stat->num_beacon_miss,
-			iface_stat->num_ac);
-
-	for (i = 0; i < iface_stat->num_ac; i++) {
-		ac_stat = &iface_stat->AccessclassStats[i];
+			link_stats->beacon_rx, link_stats->mgmt_rx,
+			link_stats->mgmt_action_rx, link_stats->mgmt_action_tx,
+			link_stats->rssi_mgmt, link_stats->rssi_data,
+			link_stats->rssi_ack, link_stats->is_leaky_ap,
+			link_stats->avg_rx_frms_leaked,
+			link_stats->rx_leak_window, average_tsf_offset,
+			link_stats->tx_rts_succ_cnt,
+			link_stats->tx_rts_fail_cnt,
+			link_stats->tx_ppdu_succ_cnt,
+			link_stats->tx_ppdu_fail_cnt,
+			link_stats->connected_duration,
+			link_stats->disconnected_duration,
+			link_stats->rtt_ranging_duration,
+			link_stats->rtt_responder_duration,
+			link_stats->num_probes_tx, link_stats->num_beacon_miss,
+			link_stats->num_ac);
+
+	for (i = 0; i < link_stats->num_ac; i++) {
+		ac_stats = &iface_stat->ac_stats[i];
 		buffer += len;
 		ll_stats.len += len;
 		len = scnprintf(buffer,
 				DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len,
-				"\nAC: %d, tx_mpdu: %u, rx_mpdu: %u, tx_mcast: %u, rx_mcast: %u, rx_ampdu: %u tx_ampdu: %u, mpdu_lost: %u, retries: %u, retries_short: %u, retries_long: %u, contention_time: min-%u max-%u avg-%u, contention num samples: %u",
-				ac_stat->ac, ac_stat->txMpdu, ac_stat->rxMpdu,
-				ac_stat->txMcast, ac_stat->rxMcast,
-				ac_stat->rxAmpdu, ac_stat->txAmpdu,
-				ac_stat->mpduLost, ac_stat->retries,
-				ac_stat->retriesShort, ac_stat->retriesLong,
-				ac_stat->contentionTimeMin,
-				ac_stat->contentionTimeMax,
-				ac_stat->contentionTimeAvg,
-				ac_stat->contentionNumSamples);
+				"\nac_type: %d, tx_mpdu: %u, rx_mpdu: %u, tx_mcast: %u, rx_mcast: %u, rx_ampdu: %u tx_ampdu: %u, mpdu_lost: %u, retries: %u, retries_short: %u, retries_long: %u, contention_time: min-%u max-%u avg-%u, contention num samples: %u, tx_pending_msdu: %u",
+				ac_stats->ac_type,
+				ac_stats->tx_mpdu, ac_stats->rx_mpdu,
+				ac_stats->tx_mcast, ac_stats->rx_mcast,
+				ac_stats->rx_ampdu, ac_stats->rx_ampdu,
+				ac_stats->mpdu_lost, ac_stats->retries,
+				ac_stats->retries_short, ac_stats->retries_long,
+				ac_stats->contention_time_min,
+				ac_stats->contention_time_max,
+				ac_stats->contention_time_avg,
+				ac_stats->contention_num_samples,
+				ac_stats->tx_pending_msdu);
 	}
 
 	buffer += len;
@@ -131,15 +135,15 @@ void hdd_debugfs_process_iface_stats(struct hdd_adapter *adapter,
 			iface_stat->num_offload_stats);
 
 	for (i = 0; i < iface_stat->num_offload_stats; i++) {
-		offload_stat = &iface_stat->offload_stat[i];
+		offload_stats = &iface_stat->offload_stats[i];
 		buffer += len;
 		ll_stats.len += len;
 		len = scnprintf(buffer,
 				DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len,
 				"\ntype: %d, rx_count: %u, drp_count: %u, fwd_count: %u",
-				offload_stat->type, offload_stat->rx_count,
-				offload_stat->drp_count,
-				offload_stat->fwd_count);
+				offload_stats->type, offload_stats->rx_count,
+				offload_stats->drp_count,
+				offload_stats->fwd_count);
 	}
 
 	ll_stats.len += len;

+ 29 - 28
core/hdd/src/wlan_hdd_stats.c

@@ -283,53 +283,53 @@ error:
  *
  * Return: bool
  */
-static bool put_wifi_wmm_ac_stat(tpSirWifiWmmAcStat stats,
+static bool put_wifi_wmm_ac_stat(wmi_wmm_ac_stats *stats,
 				 struct sk_buff *vendor_event)
 {
 	if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC,
-			stats->ac) ||
+			stats->ac_type) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU,
-			stats->txMpdu) ||
+			stats->tx_mpdu) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU,
-			stats->rxMpdu) ||
+			stats->rx_mpdu) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST,
-			stats->txMcast) ||
+			stats->tx_mcast) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST,
-			stats->rxMcast) ||
+			stats->rx_mcast) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU,
-			stats->rxAmpdu) ||
+			stats->rx_ampdu) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU,
-			stats->txAmpdu) ||
+			stats->tx_ampdu) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST,
-			stats->mpduLost) ||
+			stats->mpdu_lost) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES,
 			stats->retries) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT,
-			stats->retriesShort) ||
+			stats->retries_short) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG,
-			stats->retriesLong) ||
+			stats->retries_long) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN,
-			stats->contentionTimeMin) ||
+			stats->contention_time_min) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX,
-			stats->contentionTimeMax) ||
+			stats->contention_time_max) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG,
-			stats->contentionTimeAvg) ||
+			stats->contention_time_avg) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES,
-			stats->contentionNumSamples)) {
+			stats->contention_num_samples)) {
 		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
 		return false;
 	}
@@ -396,6 +396,7 @@ static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat,
 	struct nlattr *wmmInfo;
 	struct nlattr *wmmStats;
 	u64 average_tsf_offset;
+	wmi_iface_link_stats *link_stats = &pWifiIfaceStat->link_stats;
 
 	if (false == put_wifi_interface_info(&pWifiIfaceStat->info,
 					     vendor_event)) {
@@ -404,9 +405,9 @@ static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat,
 
 	}
 
-	average_tsf_offset =  pWifiIfaceStat->avg_bcn_spread_offset_high;
+	average_tsf_offset =  link_stats->avg_bcn_spread_offset_high;
 	average_tsf_offset =  (average_tsf_offset << 32) |
-		pWifiIfaceStat->avg_bcn_spread_offset_low;
+		link_stats->avg_bcn_spread_offset_low;
 
 	if (nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE,
@@ -416,34 +417,34 @@ static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat,
 			num_peers) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
-			pWifiIfaceStat->beaconRx) ||
+			link_stats->beacon_rx) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX,
-			pWifiIfaceStat->mgmtRx) ||
+			link_stats->mgmt_rx) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX,
-			pWifiIfaceStat->mgmtActionRx) ||
+			link_stats->mgmt_action_rx) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
-			pWifiIfaceStat->mgmtActionTx) ||
+			link_stats->mgmt_action_tx) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
-			pWifiIfaceStat->rssiMgmt) ||
+			link_stats->rssi_mgmt) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
-			pWifiIfaceStat->rssiData) ||
+			link_stats->rssi_data) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
-			pWifiIfaceStat->rssiAck) ||
+			link_stats->rssi_ack) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED,
-			pWifiIfaceStat->is_leaky_ap) ||
+			link_stats->is_leaky_ap) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED,
-			pWifiIfaceStat->avg_rx_frms_leaked) ||
+			link_stats->avg_rx_frms_leaked) ||
 	    nla_put_u32(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME,
-			pWifiIfaceStat->rx_leak_window) ||
+			link_stats->rx_leak_window) ||
 	    hdd_wlan_nla_put_u64(vendor_event,
 			QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET,
 			average_tsf_offset) ||
@@ -474,7 +475,7 @@ static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat,
 			return false;
 
 		if (false ==
-		    put_wifi_wmm_ac_stat(&pWifiIfaceStat->AccessclassStats[i],
+		    put_wifi_wmm_ac_stat(&pWifiIfaceStat->ac_stats[i],
 					 vendor_event)) {
 			hdd_err("put_wifi_wmm_ac_stat Fail");
 			return false;

+ 5 - 116
core/mac/inc/sir_api.h

@@ -4842,137 +4842,26 @@ typedef struct {
 	tSirWifiRateStat rateStats[0];
 } tSirWifiPeerInfo, *tpSirWifiPeerInfo;
 
-/**
- * struct wifi_iface_offload_stat - Wifi Iface offload statistics
- * @type: type of offload stats (enum wmi_offload_stats_type)
- * @rx_count: Number of (MSDUs) frames Received
- * @drp_count: Number of frames Dropped
- * @fwd_count:
- *  Number of frames for which FW Responded (Valid for ARP and NS only).(or)
- *  Number of frames forwarded to Host (Valid for stats type except ARP and NS).
- */
-struct wifi_iface_offload_stat {
-	wmi_offload_stats_type type;
-	uint32_t rx_count;
-	uint32_t drp_count;
-	uint32_t fwd_count;
-};
-
-/* per access category statistics */
-typedef struct {
-	/* tSirWifiTrafficAc */
-	/* access category (VI, VO, BE, BK) */
-	uint32_t ac;
-	/* number of successfully transmitted unicast data pkts (ACK rcvd) */
-	uint32_t txMpdu;
-	/* number of received unicast mpdus */
-	uint32_t rxMpdu;
-	/* number of successfully transmitted multicast data packets */
-	/* STA case: implies ACK received from AP for the unicast */
-	/* packet in which mcast pkt was sent */
-	uint32_t txMcast;
-	/* number of received multicast data packets */
-	uint32_t rxMcast;
-	/* number of received unicast a-mpdus */
-	uint32_t rxAmpdu;
-	/* number of transmitted unicast a-mpdus */
-	uint32_t txAmpdu;
-	/* number of data pkt losses (no ACK) */
-	uint32_t mpduLost;
-	/* total number of data pkt retries */
-	uint32_t retries;
-	/* number of short data pkt retries */
-	uint32_t retriesShort;
-	/* number of long data pkt retries */
-	uint32_t retriesLong;
-	/* data pkt min contention time (usecs) */
-	uint32_t contentionTimeMin;
-	/* data pkt max contention time (usecs) */
-	uint32_t contentionTimeMax;
-	/* data pkt avg contention time (usecs) */
-	uint32_t contentionTimeAvg;
-	/* num of data pkts used for contention statistics */
-	uint32_t contentionNumSamples;
-} tSirWifiWmmAcStat, *tpSirWifiWmmAcStat;
-
 /* Interface statistics - corresponding to 2nd most
  * LSB in wifi statistics bitmap  for getting statistics
  */
 typedef struct {
 	/* current state of the interface */
 	tSirWifiInterfaceInfo info;
-	/* access point beacon received count from connected AP */
-	uint32_t beaconRx;
-	/* access point mgmt frames received count from */
-	/* connected AP (including Beacon) */
-	uint32_t mgmtRx;
-	/* action frames received count */
-	uint32_t mgmtActionRx;
-	/* action frames transmit count */
-	uint32_t mgmtActionTx;
-	/* access Point Beacon and Management frames RSSI (averaged) */
-	uint32_t rssiMgmt;
-	/* access Point Data Frames RSSI (averaged) from connected AP */
-	uint32_t rssiData;
-	/* access Point ACK RSSI (averaged) from connected AP */
-	uint32_t rssiAck;
-	/* number of peers */
-	uint32_t num_peers;
-	/*
-	 * Indicates how many peer_stats events will be sent depending on the
-	 * num_peers.
-	 */
-	uint32_t num_peer_events;
-	/* number of ac */
-	uint32_t num_ac;
-	/* Roaming Stat */
-	uint32_t roam_state;
-	/*
-	 * Average Beacon spread offset is the averaged time delay between TBTT
-	 * and beacon TSF. Upper 32 bits of averaged 64 bit beacon spread offset
-	 */
-	uint32_t avg_bcn_spread_offset_high;
-	/* Lower 32 bits of averaged 64 bit beacon spread offset */
-	uint32_t avg_bcn_spread_offset_low;
-	/*
-	 * Takes value of 1 if AP leaks packets after sending an ACK for PM=1
-	 * otherwise 0
-	 */
-	uint32_t is_leaky_ap;
-	/*
-	 * Average number of frames received from AP after receiving the ACK
-	 * for a frame with PM = 1
-	 */
-	uint32_t avg_rx_frms_leaked;
-	/*
-	 *  Rx leak watch window currently in force to minimize data loss
-	 *  because of leaky AP. Rx leak window is the
-	 *  time driver waits before shutting down the radio or switching
-	 *  the channel and after receiving an ACK for
-	 *  a data frame with PM bit set.
-	 */
-	uint32_t rx_leak_window;
+
 	uint32_t rts_succ_cnt;
 	uint32_t rts_fail_cnt;
 	uint32_t ppdu_succ_cnt;
 	uint32_t ppdu_fail_cnt;
 
-	uint32_t tx_rts_succ_cnt;
-	uint32_t tx_rts_fail_cnt;
-	uint32_t tx_ppdu_succ_cnt;
-	uint32_t tx_ppdu_fail_cnt;
-	uint32_t connected_duration;
-	uint32_t disconnected_duration;
-	uint32_t rtt_ranging_duration;
-	uint32_t rtt_responder_duration;
-	uint32_t num_probes_tx;
-	uint32_t num_beacon_miss;
+	/* link statistics */
+	wmi_iface_link_stats link_stats;
 
 	/* per ac data packet statistics */
-	tSirWifiWmmAcStat AccessclassStats[WIFI_AC_MAX];
+	wmi_wmm_ac_stats ac_stats[WIFI_AC_MAX];
 
 	uint32_t num_offload_stats;
-	struct wifi_iface_offload_stat offload_stat[WMI_OFFLOAD_STATS_TYPE_MAX];
+	wmi_iface_offload_stats offload_stats[WMI_OFFLOAD_STATS_TYPE_MAX];
 } tSirWifiIfaceStat, *tpSirWifiIfaceStat;
 
 /* Peer statistics - corresponding to 3rd most LSB in

+ 21 - 44
core/wma/src/wma_utils.c

@@ -2055,13 +2055,12 @@ int wma_unified_link_iface_stats_event_handler(void *handle,
 {
 	WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *param_tlvs;
 	wmi_iface_link_stats_event_fixed_param *fixed_param;
-	wmi_iface_link_stats *link_stats;
-	wmi_wmm_ac_stats *ac_stats;
-	wmi_iface_offload_stats *offload_stats;
+	wmi_iface_link_stats *link_stats, *iface_link_stats;
+	wmi_wmm_ac_stats *ac_stats, *iface_ac_stats;
+	wmi_iface_offload_stats *offload_stats, *iface_offload_stats;
 	tSirLLStatsResults *link_stats_results;
-	uint8_t *results, *t_link_stats, *t_ac_stats, *t_offload_stats;
-	uint32_t next_res_offset, next_ac_offset, next_offload_offset, count;
-	uint32_t roaming_offset, size;
+	tSirWifiIfaceStat *iface_stat;
+	uint32_t count;
 	size_t link_stats_size, ac_stats_size, iface_info_size;
 	size_t link_stats_results_size, offload_stats_size;
 	size_t total_ac_size, total_offload_size;
@@ -2119,8 +2118,8 @@ int wma_unified_link_iface_stats_event_handler(void *handle,
 	link_stats_size = sizeof(tSirWifiIfaceStat);
 	iface_info_size = sizeof(tSirWifiInterfaceInfo);
 
-	ac_stats_size = sizeof(tSirWifiWmmAcStat);
-	offload_stats_size = sizeof(struct wifi_iface_offload_stat);
+	ac_stats_size = sizeof(wmi_wmm_ac_stats);
+	offload_stats_size = sizeof(wmi_iface_offload_stats);
 
 	total_ac_size = ac_stats_size * WIFI_AC_MAX;
 	total_offload_size = offload_stats_size * WMI_OFFLOAD_STATS_TYPE_MAX +
@@ -2154,50 +2153,28 @@ int wma_unified_link_iface_stats_event_handler(void *handle,
 	 *    - offload stats (from wmi_iface_offload_stats)
 	 */
 
-	results = (uint8_t *) link_stats_results->results;
-	t_link_stats = (uint8_t *) link_stats;
-	t_ac_stats = (uint8_t *) ac_stats;
-	t_offload_stats = (uint8_t *) offload_stats;
-
-	/* Copy roaming state */
-	roaming_offset = offsetof(tSirWifiInterfaceInfo, roaming);
-	size = member_size(tSirWifiInterfaceInfo, roaming);
+	iface_stat = (tSirWifiIfaceStat *)link_stats_results->results;
 
-	qdf_mem_copy(results + roaming_offset, &link_stats->roam_state, size);
+	iface_link_stats = &iface_stat->link_stats;
+	*iface_link_stats = *link_stats;
 
-	next_res_offset = iface_info_size;
-	qdf_mem_copy(results + next_res_offset,
-		     t_link_stats + WMI_TLV_HDR_SIZE,
-		     link_stats_size - iface_info_size -
-		     total_ac_size - total_offload_size);
-
-	next_res_offset = link_stats_size - total_ac_size - total_offload_size;
-	next_ac_offset = WMI_TLV_HDR_SIZE;
+	/* Copy roaming state */
+	iface_stat->info.roaming = link_stats->roam_state;
 
+	iface_ac_stats = &iface_stat->ac_stats[0];
 	for (count = 0; count < link_stats->num_ac; count++) {
+		*iface_ac_stats = *ac_stats;
 		ac_stats++;
-
-		qdf_mem_copy(results + next_res_offset,
-			     t_ac_stats + next_ac_offset, ac_stats_size);
-		next_res_offset += ac_stats_size;
-		next_ac_offset += sizeof(*ac_stats);
+		iface_ac_stats++;
 	}
 
-	next_res_offset = link_stats_size - total_offload_size;
-	/* copy num_offload_stats into result */
-	size =  member_size(tSirWifiIfaceStat, num_offload_stats);
-	qdf_mem_copy(results + next_res_offset, &fixed_param->num_offload_stats,
-		     size);
-
-	next_res_offset += size;
-	next_offload_offset = WMI_TLV_HDR_SIZE;
-
+	/* Copy wmi_iface_offload_stats to wifi_iface_offload_stat */
+	iface_stat->num_offload_stats = fixed_param->num_offload_stats;
+	iface_offload_stats = &iface_stat->offload_stats[0];
 	for (count = 0; count < fixed_param->num_offload_stats; count++) {
-		qdf_mem_copy(results + next_res_offset,
-			     t_offload_stats + next_offload_offset,
-			     offload_stats_size);
-		next_res_offset += offload_stats_size;
-		next_offload_offset += sizeof(*offload_stats);
+		*iface_offload_stats = *offload_stats;
+		offload_stats++;
+		iface_offload_stats++;
 	}
 
 	/* call hdd callback with Link Layer Statistics