From 88ab94ce0aff8475d6fa6c4dd6deb449ca389859 Mon Sep 17 00:00:00 2001 From: Vulupala Shashank Reddy Date: Wed, 29 Jan 2020 14:20:52 +0530 Subject: [PATCH] qcacld-3.0: Process Tx data packet for pkt capture mode Process Tx data packets and post into mon thread for packet capture mode Change-Id: I71e48b024c3e9b9e92d5dc3ec22e55a384ff572f CRs-Fixed: 2619330 --- .../core/inc/wlan_pkt_capture_data_txrx.h | 51 +- .../core/src/wlan_pkt_capture_data_txrx.c | 472 +++++++++++++++++- .../inc/wlan_pkt_capture_ucfg_api.h | 76 ++- .../src/wlan_pkt_capture_ucfg_api.c | 30 ++ core/dp/htt/htt_t2h.c | 68 +++ core/dp/txrx/ol_tx_send.c | 172 ++++++- 6 files changed, 861 insertions(+), 8 deletions(-) diff --git a/components/pkt_capture/core/inc/wlan_pkt_capture_data_txrx.h b/components/pkt_capture/core/inc/wlan_pkt_capture_data_txrx.h index ba6076151599..90ef8c2e1284 100644 --- a/components/pkt_capture/core/inc/wlan_pkt_capture_data_txrx.h +++ b/components/pkt_capture/core/inc/wlan_pkt_capture_data_txrx.h @@ -28,8 +28,8 @@ #define _WLAN_PKT_CAPTURE_DATA_TXRX_H_ #include "cdp_txrx_cmn_struct.h" -#include #include +#include /** * pkt_capture_data_process_type - data pkt types to process @@ -47,6 +47,9 @@ enum pkt_capture_data_process_type { #define TXRX_PKTCAPTURE_PKT_FORMAT_8023 0 #define TXRX_PKTCAPTURE_PKT_FORMAT_80211 1 +#define SHORT_PREAMBLE 1 +#define LONG_PREAMBLE 0 + /** * pkt_capture_datapkt_process() - process data tx and rx packets * for pkt capture mode. (normal tx/rx + offloaded tx/rx) @@ -98,4 +101,50 @@ void pkt_capture_rx_in_order_drop_offload_pkt(qdf_nbuf_t head_msdu); * true, if it is offload pkt */ bool pkt_capture_rx_in_order_offloaded_pkt(qdf_nbuf_t rx_ind_msg); + +/** + * pkt_capture_offload_deliver_indication_handler() - Handle offload data pkts + * @msg: offload netbuf msg + * @vdev_id: vdev id + * @bssid: bssid + * @pdev: pdev handle + * + * Return: none + */ +void pkt_capture_offload_deliver_indication_handler( + void *msg, uint8_t vdev_id, + uint8_t *bssid, htt_pdev_handle pdev); + +/** + * pkt_capture_tx_hdr_elem_t - tx packets header struture to + * be used to update radiotap header for packet capture mode + */ +struct pkt_capture_tx_hdr_elem_t { + uint32_t timestamp; + uint8_t preamble; + uint8_t mcs; + uint8_t rate; + uint8_t rssi_comb; + uint8_t nss; + uint8_t bw; + bool stbc; + bool sgi; + bool ldpc; + bool beamformed; + bool dir; /* rx:0 , tx:1 */ + uint8_t status; /* tx status */ +}; + +/** + * pkt_capture_tx_get_txcomplete_data_hdr() - extract Tx data hdr from Tx + * completion for pkt capture mode + * @msg_word: Tx completion htt msg + * @num_msdus: number of msdus + * + * Return: tx data hdr information + */ +struct htt_tx_data_hdr_information *pkt_capture_tx_get_txcomplete_data_hdr( + uint32_t *msg_word, + int num_msdus); + #endif /* End of _WLAN_PKT_CAPTURE_DATA_TXRX_H_ */ diff --git a/components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c b/components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c index e153e2c33582..f6871a977faf 100644 --- a/components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c +++ b/components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c @@ -24,7 +24,194 @@ #include #include #include -#include +#include +#include + +#define RESERVE_BYTES (100) + +/** + * pkt_capture_get_tx_rate() - get tx rate for tx packet + * @preamble_type: preamble type + * @rate: rate code + * @preamble: preamble + * + * Return: rate + */ +static unsigned char pkt_capture_get_tx_rate( + uint8_t preamble_type, + uint8_t rate, + uint8_t *preamble) +{ + char ret = 0x0; + *preamble = LONG_PREAMBLE; + + if (preamble_type == 0) { + switch (rate) { + case 0x0: + ret = 0x60; + break; + case 0x1: + ret = 0x30; + break; + case 0x2: + ret = 0x18; + break; + case 0x3: + ret = 0x0c; + break; + case 0x4: + ret = 0x6c; + break; + case 0x5: + ret = 0x48; + break; + case 0x6: + ret = 0x24; + break; + case 0x7: + ret = 0x12; + break; + default: + break; + } + } else if (preamble_type == 1) { + switch (rate) { + case 0x0: + ret = 0x16; + *preamble = LONG_PREAMBLE; + case 0x1: + ret = 0xB; + *preamble = LONG_PREAMBLE; + break; + case 0x2: + ret = 0x4; + *preamble = LONG_PREAMBLE; + break; + case 0x3: + ret = 0x2; + *preamble = LONG_PREAMBLE; + break; + case 0x4: + ret = 0x16; + *preamble = SHORT_PREAMBLE; + break; + case 0x5: + ret = 0xB; + *preamble = SHORT_PREAMBLE; + break; + case 0x6: + ret = 0x4; + *preamble = SHORT_PREAMBLE; + break; + default: + break; + } + } else { + qdf_print("Invalid rate info\n"); + } + return ret; +} + +/** + * pkt_capture_tx_get_phy_info() - get phy info for tx packets for pkt + * capture mode(normal tx + offloaded tx) to prepare radiotap header + * @pktcapture_hdr: tx data header + * @tx_status: tx status to be updated with phy info + * + * Return: none + */ +static void pkt_capture_tx_get_phy_info( + struct pkt_capture_tx_hdr_elem_t *pktcapture_hdr, + struct mon_rx_status *tx_status) +{ + uint8_t preamble = 0; + uint8_t preamble_type = pktcapture_hdr->preamble; + uint8_t mcs = 0, bw = 0; + uint16_t vht_flags = 0, ht_flags = 0; + + switch (preamble_type) { + case 0x0: + case 0x1: + /* legacy */ + tx_status->rate = pkt_capture_get_tx_rate( + preamble_type, + pktcapture_hdr->rate, + &preamble); + break; + case 0x2: + ht_flags = 1; + bw = pktcapture_hdr->bw; + if (pktcapture_hdr->nss == 2) + mcs = 8 + pktcapture_hdr->mcs; + else + mcs = pktcapture_hdr->mcs; + break; + case 0x3: + vht_flags = 1; + bw = pktcapture_hdr->bw; + mcs = pktcapture_hdr->mcs; + + /* fallthrough */ + default: + break; + } + + tx_status->mcs = mcs; + tx_status->bw = bw; + tx_status->nr_ant = pktcapture_hdr->nss; + tx_status->is_stbc = pktcapture_hdr->stbc; + tx_status->sgi = pktcapture_hdr->sgi; + tx_status->ldpc = pktcapture_hdr->ldpc; + tx_status->beamformed = pktcapture_hdr->beamformed; + tx_status->vht_flag_values3[0] = mcs << 0x4 | (pktcapture_hdr->nss + 1); + tx_status->ht_flags = ht_flags; + tx_status->vht_flags = vht_flags; + tx_status->rtap_flags |= ((preamble == 1) ? BIT(1) : 0); + if (bw == 0) + tx_status->vht_flag_values2 = 0; + else if (bw == 1) + tx_status->vht_flag_values2 = 1; + else if (bw == 2) + tx_status->vht_flag_values2 = 4; +} + +/** + * pkt_capture_update_tx_status() - tx status for tx packets, for + * pkt capture mode(normal tx + offloaded tx) to prepare radiotap header + * @pdev: device handler + * @tx_status: tx status to be updated + * @mon_hdr: tx data header + * + * Return: none + */ +static void +pkt_capture_update_tx_status( + htt_pdev_handle pdev, + struct mon_rx_status *tx_status, + struct pkt_capture_tx_hdr_elem_t *pktcapture_hdr) +{ + struct mon_channel *ch_info = &pdev->mon_ch_info; + uint16_t channel_flags = 0; + + tx_status->tsft = (u_int64_t)(pktcapture_hdr->timestamp); + tx_status->chan_freq = ch_info->ch_freq; + tx_status->chan_num = ch_info->ch_num; + + pkt_capture_tx_get_phy_info(pktcapture_hdr, tx_status); + + if (pktcapture_hdr->preamble == 0) + channel_flags |= IEEE80211_CHAN_OFDM; + else if (pktcapture_hdr->preamble == 1) + channel_flags |= IEEE80211_CHAN_CCK; + + channel_flags |= + (wlan_reg_chan_to_band(ch_info->ch_num) == BAND_2G ? + IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ); + + tx_status->chan_flags = channel_flags; + tx_status->ant_signal_db = pktcapture_hdr->rssi_comb; + tx_status->rssi_comb = pktcapture_hdr->rssi_comb; +} /** * pkt_capture_rx_convert8023to80211() - convert 802.3 packet to 802.11 @@ -321,6 +508,181 @@ free_buf: drop_count = pkt_capture_drop_nbuf_list(buf_list); } +/** + * pkt_capture_tx_data_cb() - process data tx and rx packets + * for pkt capture mode. (normal tx/rx + offloaded tx/rx) + * @vdev_id: vdev id for which packet is captured + * @mon_buf_list: netbuf list + * @type: data process type + * @tid: tid number + * @status: Tx status + * @pktformat: Frame format + * @bssid: bssid + * @pdev: pdev handle + * + * Return: none + */ +static void +pkt_capture_tx_data_cb( + void *context, void *ppdev, void *nbuf_list, uint8_t vdev_id, + uint8_t tid, uint8_t status, bool pkt_format, + uint8_t *bssid) +{ + qdf_nbuf_t msdu, next_buf; + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_vdev *vdev = context; + htt_pdev_handle pdev = ppdev; + struct pkt_capture_cb_context *cb_ctx; + uint8_t drop_count; + struct htt_tx_data_hdr_information *cmpl_desc = NULL; + struct pkt_capture_tx_hdr_elem_t pktcapture_hdr = {0}; + struct ethernet_hdr_t *eth_hdr; + struct llc_snap_hdr_t *llc_hdr; + struct ieee80211_frame *wh; + uint8_t hdsize, new_hdsize; + struct ieee80211_qoscntl *qos_cntl; + uint16_t ether_type; + uint32_t headroom; + uint16_t seq_no, fc_ctrl; + struct mon_rx_status tx_status = {0}; + uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4) + + sizeof(struct llc_snap_hdr_t)]; + const uint8_t ethernet_II_llc_snap_header_prefix[] = { + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (qdf_unlikely(!vdev)) + goto free_buf; + + cb_ctx = vdev_priv->cb_ctx; + if (!cb_ctx || !cb_ctx->mon_cb || !cb_ctx->mon_ctx) + goto free_buf; + + msdu = nbuf_list; + while (msdu) { + next_buf = qdf_nbuf_queue_next(msdu); + qdf_nbuf_set_next(msdu, NULL); /* Add NULL terminator */ + + cmpl_desc = (struct htt_tx_data_hdr_information *) + (qdf_nbuf_data(msdu)); + + pktcapture_hdr.timestamp = cmpl_desc->phy_timestamp_l32; + pktcapture_hdr.preamble = cmpl_desc->preamble; + pktcapture_hdr.mcs = cmpl_desc->mcs; + pktcapture_hdr.bw = cmpl_desc->bw; + pktcapture_hdr.nss = cmpl_desc->nss; + pktcapture_hdr.rssi_comb = cmpl_desc->rssi; + pktcapture_hdr.rate = cmpl_desc->rate; + pktcapture_hdr.stbc = cmpl_desc->stbc; + pktcapture_hdr.sgi = cmpl_desc->sgi; + pktcapture_hdr.ldpc = cmpl_desc->ldpc; + pktcapture_hdr.beamformed = cmpl_desc->beamformed; + + qdf_nbuf_pull_head( + msdu, + sizeof(struct htt_tx_data_hdr_information)); + + if (pkt_format == TXRX_PKTCAPTURE_PKT_FORMAT_8023) { + eth_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu); + hdsize = sizeof(struct ethernet_hdr_t); + wh = (struct ieee80211_frame *)localbuf; + + *(uint16_t *)wh->i_dur = 0; + + new_hdsize = 0; + + if (vdev_id == HTT_INVALID_VDEV) + qdf_mem_copy(bssid, eth_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + + /* BSSID , SA , DA */ + qdf_mem_copy(wh->i_addr1, bssid, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr2, eth_hdr->src_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr3, eth_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + + seq_no = cmpl_desc->seqno; + seq_no = (seq_no << IEEE80211_SEQ_SEQ_SHIFT) & + IEEE80211_SEQ_SEQ_MASK; + fc_ctrl = cmpl_desc->framectrl; + qdf_mem_copy(wh->i_fc, &fc_ctrl, sizeof(fc_ctrl)); + qdf_mem_copy(wh->i_seq, &seq_no, sizeof(seq_no)); + + wh->i_fc[1] &= ~IEEE80211_FC1_WEP; + + new_hdsize = sizeof(struct ieee80211_frame); + + if (wh->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_QOS) { + qos_cntl = (struct ieee80211_qoscntl *) + (localbuf + new_hdsize); + qos_cntl->i_qos[0] = + (tid & IEEE80211_QOS_TID); + qos_cntl->i_qos[1] = 0; + new_hdsize += sizeof(struct ieee80211_qoscntl); + } + /* + * Prepare llc Header + */ + llc_hdr = (struct llc_snap_hdr_t *) + (localbuf + new_hdsize); + ether_type = (eth_hdr->ethertype[0] << 8) | + (eth_hdr->ethertype[1]); + if (ether_type >= ETH_P_802_3_MIN) { + qdf_mem_copy( + llc_hdr, + ethernet_II_llc_snap_header_prefix, + sizeof + (ethernet_II_llc_snap_header_prefix)); + if (ether_type == ETHERTYPE_AARP || + ether_type == ETHERTYPE_IPX) { + llc_hdr->org_code[2] = + BTEP_SNAP_ORGCODE_2; + /* 0xf8; bridge tunnel header */ + } + llc_hdr->ethertype[0] = eth_hdr->ethertype[0]; + llc_hdr->ethertype[1] = eth_hdr->ethertype[1]; + new_hdsize += sizeof(struct llc_snap_hdr_t); + } + + /* + * Remove 802.3 Header by adjusting the head + */ + qdf_nbuf_pull_head(msdu, hdsize); + + /* + * Adjust the head and prepare 802.11 Header + */ + qdf_nbuf_push_head(msdu, new_hdsize); + qdf_mem_copy(qdf_nbuf_data(msdu), localbuf, new_hdsize); + } + + pkt_capture_update_tx_status( + pdev, + &tx_status, + &pktcapture_hdr); + /* + * Calculate the headroom and adjust head + * to prepare radiotap header. + */ + headroom = qdf_nbuf_headroom(msdu); + qdf_nbuf_update_radiotap(&tx_status, msdu, headroom); + + if (QDF_STATUS_SUCCESS != + cb_ctx->mon_cb(cb_ctx->mon_ctx, msdu)) { + pkt_capture_err("Frame Tx to HDD failed"); + qdf_nbuf_free(msdu); + } + + msdu = next_buf; + } + return; + +free_buf: + drop_count = pkt_capture_drop_nbuf_list(nbuf_list); +} + void pkt_capture_datapkt_process( uint8_t vdev_id, qdf_nbuf_t mon_buf_list, @@ -346,8 +708,8 @@ void pkt_capture_datapkt_process( callback = pkt_capture_rx_data_cb; break; case TXRX_PROCESS_TYPE_DATA_TX: - break; case TXRX_PROCESS_TYPE_DATA_TX_COMPL: + callback = pkt_capture_tx_data_cb; break; default: return; @@ -368,3 +730,109 @@ void pkt_capture_datapkt_process( drop_rx_buf: drop_count = pkt_capture_drop_nbuf_list(mon_buf_list); } + +struct htt_tx_data_hdr_information *pkt_capture_tx_get_txcomplete_data_hdr( + uint32_t *msg_word, + int num_msdus) +{ + int offset_dwords; + u_int32_t has_tx_tsf; + u_int32_t has_retry; + u_int32_t has_ack_rssi; + u_int32_t has_tx_tsf64; + u_int32_t has_tx_compl_payload; + struct htt_tx_compl_ind_append_retries *retry_list = NULL; + struct htt_tx_data_hdr_information *txcomplete_data_hrd_list = NULL; + + has_tx_compl_payload = HTT_TX_COMPL_IND_APPEND4_GET(*msg_word); + if (num_msdus <= 0 || !has_tx_compl_payload) + return NULL; + + offset_dwords = 1 + ((num_msdus + 1) >> 1); + + has_retry = HTT_TX_COMPL_IND_APPEND_GET(*msg_word); + if (has_retry) { + int retry_index = 0; + int width_for_each_retry = + (sizeof(struct htt_tx_compl_ind_append_retries) + + 3) >> 2; + + retry_list = (struct htt_tx_compl_ind_append_retries *) + (msg_word + offset_dwords); + while (retry_list) { + if (retry_list[retry_index++].flag == 0) + break; + } + offset_dwords += retry_index * width_for_each_retry; + } + has_tx_tsf = HTT_TX_COMPL_IND_APPEND1_GET(*msg_word); + if (has_tx_tsf) { + int width_for_each_tsf = + (sizeof(struct htt_tx_compl_ind_append_tx_tstamp)) >> 2; + offset_dwords += width_for_each_tsf * num_msdus; + } + + has_ack_rssi = HTT_TX_COMPL_IND_APPEND2_GET(*msg_word); + if (has_ack_rssi) + offset_dwords += ((num_msdus + 1) >> 1); + + has_tx_tsf64 = HTT_TX_COMPL_IND_APPEND3_GET(*msg_word); + if (has_tx_tsf64) + offset_dwords += (num_msdus << 1); + + txcomplete_data_hrd_list = (struct htt_tx_data_hdr_information *) + (msg_word + offset_dwords); + + return txcomplete_data_hrd_list; +} + +void pkt_capture_offload_deliver_indication_handler( + void *msg, uint8_t vdev_id, + uint8_t *bssid, htt_pdev_handle pdev) +{ + int nbuf_len; + qdf_nbuf_t netbuf; + uint8_t status; + uint8_t tid = 0; + bool pkt_format; + u_int32_t *msg_word = (u_int32_t *)msg; + u_int8_t *buf = (u_int8_t *)msg; + struct htt_tx_data_hdr_information *txhdr; + struct htt_tx_offload_deliver_ind_hdr_t *offload_deliver_msg; + + offload_deliver_msg = (struct htt_tx_offload_deliver_ind_hdr_t *)msg; + + txhdr = (struct htt_tx_data_hdr_information *) + (msg_word + 1); + + nbuf_len = offload_deliver_msg->tx_mpdu_bytes; + + netbuf = qdf_nbuf_alloc(NULL, + roundup(nbuf_len + RESERVE_BYTES, 4), + RESERVE_BYTES, 4, false); + + if (!netbuf) + return; + + qdf_nbuf_put_tail(netbuf, nbuf_len); + + qdf_mem_copy(qdf_nbuf_data(netbuf), + buf + sizeof(struct htt_tx_offload_deliver_ind_hdr_t), + nbuf_len); + + qdf_nbuf_push_head( + netbuf, + sizeof(struct htt_tx_data_hdr_information)); + + qdf_mem_copy(qdf_nbuf_data(netbuf), txhdr, + sizeof(struct htt_tx_data_hdr_information)); + + status = offload_deliver_msg->status; + pkt_format = offload_deliver_msg->format; + tid = offload_deliver_msg->tid_num; + + pkt_capture_datapkt_process( + vdev_id, + netbuf, TXRX_PROCESS_TYPE_DATA_TX, + tid, status, pkt_format, bssid, pdev); +} diff --git a/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_ucfg_api.h b/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_ucfg_api.h index 9a5f141279cb..21da9c5d4d37 100644 --- a/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_ucfg_api.h +++ b/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_ucfg_api.h @@ -30,6 +30,8 @@ #include "wlan_pkt_capture_public_structs.h" #include "wlan_pkt_capture_mon_thread.h" #include +#include "wlan_pkt_capture_data_txrx.h" +#include #ifdef WLAN_FEATURE_PKT_CAPTURE /** @@ -52,7 +54,7 @@ void ucfg_pkt_capture_deinit(void); /** * ucfg_pkt_capture_get_mode() - get packet capture mode - * @psoc: pointer to psoc object + * @psoc: objmgr psoc handle * * Return: enum pkt_capture_mode */ @@ -189,6 +191,52 @@ bool ucfg_pkt_capture_rx_offloaded_pkt(qdf_nbuf_t rx_ind_msg); */ void ucfg_pkt_capture_rx_drop_offload_pkt(qdf_nbuf_t head_msdu); +/** + * ucfg_pkt_capture_offload_deliver_indication_handler() - Handle offload + * data pkts + * @msg: offload netbuf msg + * @vdev_id: vdev id + * @bssid: bssid + * @pdev: pdev handle + * + * Return: none + */ +void ucfg_pkt_capture_offload_deliver_indication_handler( + void *msg, uint8_t vdev_id, + uint8_t *bssid, htt_pdev_handle pdev); + +/** + * ucfg_pkt_capture_tx_get_txcomplete_data_hdr() - extract Tx data hdr from Tx + * completion for pkt capture mode + * @msg_word: Tx completion htt msg + * @num_msdus: number of msdus + * + * Return: tx data hdr information + */ +struct htt_tx_data_hdr_information *ucfg_pkt_capture_tx_get_txcomplete_data_hdr( + uint32_t *msg_word, + int num_msdus); + +/** + * ucfg_pkt_capture_tx_completion_process() - process data tx packets + * @vdev_id: vdev id for which packet is captured + * @mon_buf_list: netbuf list + * @type: data process type + * @tid: tid number + * @status: Tx status + * @pktformat: Frame format + * @bssid: bssid + * @pdev: pdev handle + * + * Return: none + */ +void ucfg_pkt_capture_tx_completion_process( + uint8_t vdev_id, + qdf_nbuf_t mon_buf_list, + enum pkt_capture_data_process_type type, + uint8_t tid, uint8_t status, bool pkt_format, + uint8_t *bssid, htt_pdev_handle pdev); + #else static inline QDF_STATUS ucfg_pkt_capture_init(void) @@ -261,6 +309,21 @@ ucfg_pkt_capture_mgmt_tx_completion(struct wlan_objmgr_pdev *pdev, { } +static inline void +ucfg_pkt_capture_offload_deliver_indication_handler( + void *msg, uint8_t vdev_id, + uint8_t *bssid, htt_pdev_handle pdev) +{ +} + +static inline +struct htt_tx_data_hdr_information *ucfg_pkt_capture_tx_get_txcomplete_data_hdr( + uint32_t *msg_word, + int num_msdus) +{ + return NULL; +} + static inline void ucfg_pkt_capture_rx_msdu_process( uint8_t *bssid, @@ -279,5 +342,16 @@ static inline void ucfg_pkt_capture_rx_drop_offload_pkt(qdf_nbuf_t head_msdu) { } + +static inline void +ucfg_pkt_capture_tx_completion_process( + uint8_t vdev_id, + qdf_nbuf_t mon_buf_list, + enum pkt_capture_data_process_type type, + uint8_t tid, uint8_t status, bool pkt_format, + uint8_t *bssid, htt_pdev_handle pdev) + +{ +} #endif /* WLAN_FEATURE_PKT_CAPTURE */ #endif /* _WLAN_PKT_CAPTURE_UCFG_API_H_ */ diff --git a/components/pkt_capture/dispatcher/src/wlan_pkt_capture_ucfg_api.c b/components/pkt_capture/dispatcher/src/wlan_pkt_capture_ucfg_api.c index e891125620c1..ab83031a77ec 100644 --- a/components/pkt_capture/dispatcher/src/wlan_pkt_capture_ucfg_api.c +++ b/components/pkt_capture/dispatcher/src/wlan_pkt_capture_ucfg_api.c @@ -291,3 +291,33 @@ void ucfg_pkt_capture_rx_drop_offload_pkt(qdf_nbuf_t head_msdu) { pkt_capture_rx_in_order_drop_offload_pkt(head_msdu); } + +void +ucfg_pkt_capture_offload_deliver_indication_handler( + void *msg, uint8_t vdev_id, + uint8_t *bssid, htt_pdev_handle pdev) +{ + pkt_capture_offload_deliver_indication_handler(msg, vdev_id, + bssid, pdev); +} + +struct htt_tx_data_hdr_information *ucfg_pkt_capture_tx_get_txcomplete_data_hdr( + uint32_t *msg_word, + int num_msdus) +{ + return pkt_capture_tx_get_txcomplete_data_hdr(msg_word, num_msdus); +} + +void +ucfg_pkt_capture_tx_completion_process( + uint8_t vdev_id, + qdf_nbuf_t mon_buf_list, + enum pkt_capture_data_process_type type, + uint8_t tid, uint8_t status, bool pkt_format, + uint8_t *bssid, htt_pdev_handle pdev) +{ + pkt_capture_datapkt_process( + vdev_id, + mon_buf_list, TXRX_PROCESS_TYPE_DATA_TX_COMPL, + tid, status, pkt_format, bssid, pdev); +} diff --git a/core/dp/htt/htt_t2h.c b/core/dp/htt/htt_t2h.c index b792a85eb595..826c89da01bd 100644 --- a/core/dp/htt/htt_t2h.c +++ b/core/dp/htt/htt_t2h.c @@ -44,6 +44,8 @@ #include #include "pktlog_ac.h" #include +#include +#include /*--- target->host HTT message dispatch function ----------------------------*/ #ifndef DEBUG_CREDIT @@ -1091,6 +1093,7 @@ void htt_t2h_msg_handler_fast(void *context, qdf_nbuf_t *cmpl_msdus, uint32_t i; enum htt_t2h_msg_type msg_type; uint32_t msg_len; + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); for (i = 0; i < num_cmpls; i++) { htt_t2h_msg = cmpl_msdus[i]; @@ -1240,6 +1243,71 @@ void htt_t2h_msg_handler_fast(void *context, qdf_nbuf_t *cmpl_msdus, break; } + case HTT_T2H_MSG_TYPE_TX_OFFLOAD_DELIVER_IND: + { + struct htt_tx_offload_deliver_ind_hdr_t + *offload_deliver_msg; + uint8_t vdev_id; + struct ol_txrx_vdev_t *vdev; + bool is_pkt_during_roam = false; + struct ol_txrx_pdev_t *txrx_pdev = pdev->txrx_pdev; + struct ol_txrx_peer_t *peer; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + uint32_t freq = 0; + + if (!(ucfg_pkt_capture_get_pktcap_mode((void *)soc->psoc) & + PKT_CAPTURE_MODE_DATA_ONLY)) + break; + + offload_deliver_msg = + (struct htt_tx_offload_deliver_ind_hdr_t *)msg_word; + is_pkt_during_roam = + (offload_deliver_msg->reserved_2 ? true : false); + + if (qdf_unlikely( + !pdev->cfg.is_full_reorder_offload)) { + break; + } + + /* Is FW sends offload data during roaming */ + if (is_pkt_during_roam) { + vdev_id = HTT_INVALID_VDEV; + freq = + (uint32_t)offload_deliver_msg->reserved_3; + htt_rx_mon_note_capture_channel( + pdev, cds_freq_to_chan(freq)); + } else { + vdev_id = offload_deliver_msg->vdev_id; + vdev = (struct ol_txrx_vdev_t *) + ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (vdev) { + qdf_spin_lock_bh( + &txrx_pdev->peer_ref_mutex); + peer = TAILQ_FIRST(&vdev->peer_list); + qdf_spin_unlock_bh( + &txrx_pdev->peer_ref_mutex); + if (peer) { + qdf_spin_lock_bh( + &peer->peer_info_lock); + qdf_mem_copy( + bssid, + &peer->mac_addr.raw, + QDF_MAC_ADDR_SIZE); + qdf_spin_unlock_bh( + &peer->peer_info_lock); + } else { + break; + } + } else { + break; + } + } + ucfg_pkt_capture_offload_deliver_indication_handler( + msg_word, + vdev_id, bssid, pdev); + break; + } case HTT_T2H_MSG_TYPE_RX_PN_IND: { u_int16_t peer_id; diff --git a/core/dp/txrx/ol_tx_send.c b/core/dp/txrx/ol_tx_send.c index 3ae328107c3e..0553054f7056 100644 --- a/core/dp/txrx/ol_tx_send.c +++ b/core/dp/txrx/ol_tx_send.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -53,7 +53,7 @@ #include #include #include - +#include #ifdef TX_CREDIT_RECLAIM_SUPPORT #define OL_TX_CREDIT_RECLAIM(pdev) \ @@ -604,6 +604,151 @@ void ol_tx_flow_pool_unlock(struct ol_tx_desc_t *tx_desc) } #endif +#ifdef WLAN_FEATURE_PKT_CAPTURE +#define RESERVE_BYTES 100 +/** + * ol_tx_pkt_capture_tx_completion_process(): process tx packets + * for pkt capture mode + * @pdev: device handler + * @tx_desc: tx desc + * @payload: tx data header + * @tid: tid number + * @status: Tx status + * + * Return: none + */ +static void +ol_tx_pkt_capture_tx_completion_process( + ol_txrx_pdev_handle pdev, + struct ol_tx_desc_t *tx_desc, + struct htt_tx_data_hdr_information *payload_hdr, + uint8_t tid, uint8_t status) +{ + qdf_nbuf_t netbuf; + int nbuf_len; + struct qdf_tso_seg_elem_t *tso_seg = NULL; + struct ol_txrx_peer_t *peer; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + uint8_t pkt_type = 0; + + qdf_assert(tx_desc); + + ol_tx_flow_pool_lock(tx_desc); + /* + * In cases when vdev has gone down and tx completion + * are received, leads to NULL vdev access. + * So, check for NULL before dereferencing it. + */ + if (!tx_desc->vdev) { + ol_tx_flow_pool_unlock(tx_desc); + return; + } + + ol_tx_flow_pool_unlock(tx_desc); + + if (tx_desc->pkt_type == OL_TX_FRM_TSO) { + if (!tx_desc->tso_desc) + return; + + tso_seg = tx_desc->tso_desc; + nbuf_len = tso_seg->seg.total_len; + } else { + int i, extra_frag_len = 0; + + i = QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(tx_desc->netbuf); + if (i > 0) + extra_frag_len = + QDF_NBUF_CB_TX_EXTRA_FRAG_LEN(tx_desc->netbuf); + nbuf_len = qdf_nbuf_len(tx_desc->netbuf) - extra_frag_len; + } + + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + peer = TAILQ_FIRST(&tx_desc->vdev->peer_list); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + if (!peer) + return; + + qdf_spin_lock_bh(&peer->peer_info_lock); + qdf_mem_copy(bssid, &peer->mac_addr.raw, QDF_MAC_ADDR_SIZE); + qdf_spin_unlock_bh(&peer->peer_info_lock); + + netbuf = qdf_nbuf_alloc(NULL, + roundup(nbuf_len + RESERVE_BYTES, 4), + RESERVE_BYTES, 4, false); + if (!netbuf) + return; + + qdf_nbuf_put_tail(netbuf, nbuf_len); + + if (tx_desc->pkt_type == OL_TX_FRM_TSO) { + uint8_t frag_cnt, num_frags = 0; + int frag_len = 0; + uint32_t tcp_seq_num; + uint16_t ip_len; + + qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + + if (tso_seg->seg.num_frags > 0) + num_frags = tso_seg->seg.num_frags - 1; + + /*Num of frags in a tso seg cannot be less than 2 */ + if (num_frags < 1) { + qdf_print("ERROR: num of frags in tso segment is %d\n", + (num_frags + 1)); + qdf_nbuf_free(netbuf); + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + return; + } + + tcp_seq_num = tso_seg->seg.tso_flags.tcp_seq_num; + tcp_seq_num = qdf_cpu_to_be32(tcp_seq_num); + + ip_len = tso_seg->seg.tso_flags.ip_len; + ip_len = qdf_cpu_to_be16(ip_len); + + for (frag_cnt = 0; frag_cnt < num_frags; frag_cnt++) { + qdf_mem_copy(qdf_nbuf_data(netbuf) + frag_len, + tso_seg->seg.tso_frags[frag_cnt].vaddr, + tso_seg->seg.tso_frags[frag_cnt].length); + frag_len += tso_seg->seg.tso_frags[frag_cnt].length; + } + + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + + qdf_mem_copy((qdf_nbuf_data(netbuf) + IPV4_PKT_LEN_OFFSET), + &ip_len, sizeof(ip_len)); + qdf_mem_copy((qdf_nbuf_data(netbuf) + IPV4_TCP_SEQ_NUM_OFFSET), + &tcp_seq_num, sizeof(tcp_seq_num)); + } else { + qdf_mem_copy(qdf_nbuf_data(netbuf), + qdf_nbuf_data(tx_desc->netbuf), + nbuf_len); + } + + qdf_nbuf_push_head( + netbuf, + sizeof(struct htt_tx_data_hdr_information)); + qdf_mem_copy(qdf_nbuf_data(netbuf), payload_hdr, + sizeof(struct htt_tx_data_hdr_information)); + + ucfg_pkt_capture_tx_completion_process( + tx_desc->vdev_id, + netbuf, pkt_type, + tid, status, + TXRX_PKTCAPTURE_PKT_FORMAT_8023, bssid, + pdev->htt_pdev); +} +#else +static void +ol_tx_pkt_capture_tx_completion_process( + ol_txrx_pdev_handle pdev, + struct ol_tx_desc_t *tx_desc, + struct htt_tx_data_hdr_information *payload_hdr, + uint8_t tid, uint8_t status) +{ +} +#endif /* WLAN_FEATURE_PKT_CAPTURE */ + #ifdef WLAN_FEATURE_TSF_PLUS static inline struct htt_tx_compl_ind_append_tx_tstamp *ol_tx_get_txtstamps( u_int32_t *msg_word_header, u_int32_t **msg_word_payload, @@ -854,11 +999,12 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev, qdf_nbuf_t netbuf; #if !defined(REMOVE_PKT_LOG) ol_txrx_pktdump_cb packetdump_cb; - void *soc = cds_get_context(QDF_MODULE_ID_SOC); #endif + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); uint32_t is_tx_desc_freed = 0; struct htt_tx_compl_ind_append_tx_tstamp *txtstamp_list = NULL; struct htt_tx_compl_ind_append_tx_tsf64 *txtstamp64_list = NULL; + struct htt_tx_data_hdr_information *pkt_capture_txcomp_hdr_list = NULL; u_int32_t *msg_word_header = (u_int32_t *)msg; /*msg_word skip header*/ u_int32_t *msg_word_payload = msg_word_header + 1; @@ -868,9 +1014,12 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev, union ol_tx_desc_list_elem_t *tx_desc_last = NULL; ol_tx_desc_list tx_descs; uint64_t tx_tsf64; + uint8_t tid; TAILQ_INIT(&tx_descs); + tid = HTT_TX_COMPL_IND_TID_GET(*msg_word); + ol_tx_delay_compute(pdev, status, desc_ids, num_msdus); if (status == htt_tx_status_ok) { txtstamp_list = ol_tx_get_txtstamps( @@ -880,6 +1029,13 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev, msg_word_header, &msg_word_payload, num_msdus); } + if ((ucfg_pkt_capture_get_mode((void *)soc->psoc) & + PKT_CAPTURE_MODE_DATA_ONLY)) + pkt_capture_txcomp_hdr_list = + ucfg_pkt_capture_tx_get_txcomplete_data_hdr( + msg_word, + num_msdus); + for (i = 0; i < num_msdus; i++) { tx_desc_id = desc_ids[i]; if (tx_desc_id >= pdev->tx_desc.pool_size) { @@ -905,6 +1061,14 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev, (u_int64_t)txtstamp_list->timestamp[i] ); + if (pkt_capture_txcomp_hdr_list) { + ol_tx_pkt_capture_tx_completion_process( + pdev, + tx_desc, + &pkt_capture_txcomp_hdr_list[i], + tid, status); + } + QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_FREE); if (QDF_NBUF_CB_GET_PACKET_TYPE(netbuf) == @@ -927,7 +1091,7 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev, if (tx_desc->pkt_type != OL_TX_FRM_TSO) { packetdump_cb = pdev->ol_tx_packetdump_cb; if (packetdump_cb) - packetdump_cb(soc, pdev->id, + packetdump_cb((void *)soc, pdev->id, tx_desc->vdev_id, netbuf, status, TX_DATA_PKT); }