|
@@ -24,7 +24,194 @@
|
|
|
#include <wlan_pkt_capture_data_txrx.h>
|
|
|
#include <wlan_pkt_capture_main.h>
|
|
|
#include <enet.h>
|
|
|
-#include <htt_internal.h>
|
|
|
+#include <wlan_reg_services_api.h>
|
|
|
+#include <cds_ieee80211_common.h>
|
|
|
+
|
|
|
+#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);
|
|
|
+}
|