qca-wifi: Add AMSDU support in Tx capture

Add AMSDU subframe header and set the AMSDU bit in
QOS control field.

Change-Id: Id91a032231bf35cd5f87eaed475699035528c12e
This commit is contained in:
Manoj Ekbote
2020-12-22 12:41:05 -08:00
والد c4ae2b3bcd
کامیت a9061165c0

مشاهده پرونده

@@ -2276,7 +2276,8 @@ static uint32_t dp_tx_update_80211_wds_hdr(struct dp_pdev *pdev,
qdf_nbuf_t nbuf,
uint16_t ether_type,
uint8_t *dst_addr,
uint8_t usr_idx)
uint8_t usr_idx,
bool is_amsdu)
{
struct cdp_tx_completion_ppdu *ppdu_desc;
struct cdp_tx_completion_ppdu_user *user;
@@ -2305,17 +2306,29 @@ static uint32_t dp_tx_update_80211_wds_hdr(struct dp_pdev *pdev,
ptr_wh->i_qos[1] = (user->qos_ctrl & 0xFF00) >> 8;
ptr_wh->i_qos[0] = (user->qos_ctrl & 0xFF);
peer->tx_capture.tx_wifi_ppdu_id = ppdu_desc->ppdu_id;
}
if (is_amsdu) {
ptr_wh->i_qos[0] |= IEEE80211_QOS_AMSDU;
/* update addr3 and addr4 with BSSID in an AMSDU frame */
qdf_mem_copy(ptr_wh->i_addr3, ptr_wh->i_addr2,
QDF_MAC_ADDR_SIZE);
qdf_mem_copy(ptr_wh->i_addr4, ptr_wh->i_addr2,
QDF_MAC_ADDR_SIZE);
} else {
/* Update Addr 3 (DA) with DA derived from ether packet */
qdf_mem_copy(ptr_wh->i_addr3, dst_addr, QDF_MAC_ADDR_SIZE);
peer->tx_capture.tx_wifi_ppdu_id = ppdu_desc->ppdu_id;
}
frame_size = (user->tid != DP_NON_QOS_TID) ?
sizeof(struct ieee80211_qosframe_addr4) :
sizeof(struct ieee80211_frame_addr4);
mpdu_buf_len = frame_size + LLC_SNAP_HDR_LEN;
if (is_amsdu)
mpdu_buf_len = frame_size;
else
mpdu_buf_len = frame_size + LLC_SNAP_HDR_LEN;
nbuf->protocol = qdf_htons(ETH_P_802_2);
@@ -2331,15 +2344,16 @@ static uint32_t dp_tx_update_80211_wds_hdr(struct dp_pdev *pdev,
ptr_hdr = ptr_hdr + frame_size;
/* update LLC */
*ptr_hdr = LLC_SNAP_LSAP;
*(ptr_hdr + 1) = LLC_SNAP_LSAP;
*(ptr_hdr + 2) = LLC_UI;
*(ptr_hdr + 3) = 0x00;
*(ptr_hdr + 4) = 0x00;
*(ptr_hdr + 5) = 0x00;
*(ptr_hdr + 6) = (eth_type & 0xFF00) >> 8;
*(ptr_hdr + 7) = (eth_type & 0xFF);
if (!is_amsdu) {
*ptr_hdr = LLC_SNAP_LSAP;
*(ptr_hdr + 1) = LLC_SNAP_LSAP;
*(ptr_hdr + 2) = LLC_UI;
*(ptr_hdr + 3) = 0x00;
*(ptr_hdr + 4) = 0x00;
*(ptr_hdr + 5) = 0x00;
*(ptr_hdr + 6) = (eth_type & 0xFF00) >> 8;
*(ptr_hdr + 7) = (eth_type & 0xFF);
}
qdf_nbuf_trim_tail(nbuf, qdf_nbuf_len(nbuf) - mpdu_buf_len);
return 0;
}
@@ -2361,7 +2375,8 @@ static uint32_t dp_tx_update_80211_hdr(struct dp_pdev *pdev,
qdf_nbuf_t nbuf,
uint16_t ether_type,
uint8_t *src_addr,
uint8_t usr_idx)
uint8_t usr_idx,
bool is_amsdu)
{
struct cdp_tx_completion_ppdu *ppdu_desc;
struct cdp_tx_completion_ppdu_user *user;
@@ -2390,17 +2405,28 @@ static uint32_t dp_tx_update_80211_hdr(struct dp_pdev *pdev,
ptr_wh->i_qos[1] = (user->qos_ctrl & 0xFF00) >> 8;
ptr_wh->i_qos[0] = (user->qos_ctrl & 0xFF);
/* Update Addr 3 (SA) with SA derived from ether packet */
qdf_mem_copy(ptr_wh->i_addr3, src_addr, QDF_MAC_ADDR_SIZE);
peer->tx_capture.tx_wifi_ppdu_id = ppdu_desc->ppdu_id;
}
if (is_amsdu) {
ptr_wh->i_qos[0] |= IEEE80211_QOS_AMSDU;
/* update addr3 with BSSID in an AMSDU frame */
qdf_mem_copy(ptr_wh->i_addr3, ptr_wh->i_addr2,
QDF_MAC_ADDR_SIZE);
} else {
/* Update Addr 3 (SA) with SA derived from ether packet */
qdf_mem_copy(ptr_wh->i_addr3, src_addr, QDF_MAC_ADDR_SIZE);
}
frame_size = (user->tid != DP_NON_QOS_TID) ?
sizeof(struct ieee80211_qosframe) :
sizeof(struct ieee80211_frame);
mpdu_buf_len = frame_size + LLC_SNAP_HDR_LEN;
if (is_amsdu)
mpdu_buf_len = frame_size;
else
mpdu_buf_len = frame_size + LLC_SNAP_HDR_LEN;
nbuf->protocol = qdf_htons(ETH_P_802_2);
@@ -2413,23 +2439,88 @@ static uint32_t dp_tx_update_80211_hdr(struct dp_pdev *pdev,
ptr_hdr = (void *)qdf_nbuf_data(nbuf);
qdf_mem_copy(ptr_hdr, ptr_wh, frame_size);
ptr_hdr = ptr_hdr + frame_size;
/* update LLC */
*ptr_hdr = LLC_SNAP_LSAP;
*(ptr_hdr + 1) = LLC_SNAP_LSAP;
*(ptr_hdr + 2) = LLC_UI;
*(ptr_hdr + 3) = 0x00;
*(ptr_hdr + 4) = 0x00;
*(ptr_hdr + 5) = 0x00;
*(ptr_hdr + 6) = (eth_type & 0xFF00) >> 8;
*(ptr_hdr + 7) = (eth_type & 0xFF);
if (!is_amsdu) {
ptr_hdr = ptr_hdr + frame_size;
/* update LLC */
*ptr_hdr = LLC_SNAP_LSAP;
*(ptr_hdr + 1) = LLC_SNAP_LSAP;
*(ptr_hdr + 2) = LLC_UI;
*(ptr_hdr + 3) = 0x00;
*(ptr_hdr + 4) = 0x00;
*(ptr_hdr + 5) = 0x00;
*(ptr_hdr + 6) = (eth_type & 0xFF00) >> 8;
*(ptr_hdr + 7) = (eth_type & 0xFF);
}
qdf_nbuf_trim_tail(nbuf, qdf_nbuf_len(nbuf) - mpdu_buf_len);
return 0;
}
static QDF_STATUS dp_tx_add_amsdu_llc_hdr(qdf_nbuf_t nbuf, bool is_last_msdu)
{
qdf_ether_header_t *eh = NULL;
struct llc_snap_hdr_t *llchdr = NULL;
uint8_t *p_len = NULL;
uint16_t eth_type;
uint16_t nbuf_len = qdf_nbuf_len(nbuf);
/*
* Steps-
* 1.nbuf->data is pointing to beginning of ethernet header.
* 2.push is done to create space for LLC header
* 3.Move 14 bytes (size of ether_header_t) to nbuf->data
* 4.update AMSDU subframe length
* 5.populate LLC and add padding if needed
*
* AMSDU format: DA | SA | LEN | LLC_SNAP | TYPE | PAYLOAD
*/
eh = (qdf_ether_header_t *)qdf_nbuf_data(nbuf);
eth_type = qdf_htons(eh->ether_type);
/* increase data area to include LLC header */
if (qdf_unlikely(qdf_nbuf_headroom(nbuf) < LLC_SNAP_HDR_LEN)) {
dp_tx_capture_alert("No Head room to push %d bytes, avail:%d\n",
LLC_SNAP_HDR_LEN,
qdf_nbuf_headroom(nbuf));
return QDF_STATUS_E_NOMEM;
}
qdf_nbuf_push_head(nbuf, LLC_SNAP_HDR_LEN);
/* AMSDU subframe header */
qdf_mem_move(qdf_nbuf_data(nbuf), eh, sizeof(qdf_ether_header_t));
p_len = qdf_nbuf_data(nbuf) + (2 * QDF_NET_ETH_LEN);
/*
* update AMSDU length field with size up to LLC not including the
* subframe header
*/
nbuf_len -= sizeof(qdf_ether_header_t);
nbuf_len += LLC_SNAP_HDR_LEN;
p_len[0] = (nbuf_len >> 8);
p_len[1] = (nbuf_len & 0xFF);
/* LLC header */
llchdr = (struct llc_snap_hdr_t *)(qdf_nbuf_data(nbuf) +
sizeof(qdf_ether_header_t));
llchdr->dsap = LLC_SNAP_LSAP;
llchdr->ssap = LLC_SNAP_LSAP;
llchdr->cntl = LLC_UI;
qdf_mem_set(llchdr->org_code, 3, 0);
llchdr->ethertype[0] = (eth_type & 0xFF00) >> 8;
llchdr->ethertype[1] = (eth_type & 0xFF);
/* add padding to end of A-MSDU except the last one (Spec requirement)*/
if (!is_last_msdu) {
nbuf_len = qdf_nbuf_len(nbuf);
if (nbuf_len & 0x3)
qdf_nbuf_put_tail(nbuf, 4 - (nbuf_len & 3));
}
return QDF_STATUS_SUCCESS;
}
/**
* dp_tx_mon_restitch_mpdu(): Function to restitch msdu to mpdu
* @pdev: dp_pdev
@@ -2459,6 +2550,7 @@ dp_tx_mon_restitch_mpdu(struct dp_pdev *pdev, struct dp_peer *peer,
qdf_ether_header_t *eh = NULL;
size_t msdu_comp_info_sz;
size_t ether_hdr_sz;
bool is_amsdu = 0;
if (qdf_nbuf_is_queue_empty(head_msdu))
return 0;
@@ -2471,6 +2563,7 @@ dp_tx_mon_restitch_mpdu(struct dp_pdev *pdev, struct dp_peer *peer,
first_msdu = ptr_msdu_info->first_msdu;
last_msdu = ptr_msdu_info->last_msdu;
is_amsdu = ptr_msdu_info->msdu_part_of_amsdu;
eh = (qdf_ether_header_t *)(curr_nbuf->data +
sizeof(struct msdu_completion_info));
@@ -2495,14 +2588,15 @@ dp_tx_mon_restitch_mpdu(struct dp_pdev *pdev, struct dp_peer *peer,
frag_list_sum_len = 0;
first_msdu_not_seen = 0;
ether_hdr_sz = sizeof(qdf_ether_header_t);
/* pull ethernet header from first MSDU alone */
if (NULL == qdf_nbuf_pull_head(curr_nbuf,
ether_hdr_sz)) {
dp_tx_capture_alert(" No Head space to pull !!\n");
qdf_assert_always(0);
if (!is_amsdu) {
ether_hdr_sz = sizeof(qdf_ether_header_t);
/* pull ethernet header from first MSDU alone */
if (NULL == qdf_nbuf_pull_head(curr_nbuf,
ether_hdr_sz)) {
dp_tx_capture_alert(" No Head space to pull !!\n");
qdf_assert_always(0);
}
}
/* update first buffer to previous buffer */
prev_nbuf = curr_nbuf;
@@ -2537,6 +2631,13 @@ dp_tx_mon_restitch_mpdu(struct dp_pdev *pdev, struct dp_peer *peer,
prev_nbuf = prev_nbuf->next;
}
if (is_amsdu) {
if (dp_tx_add_amsdu_llc_hdr(curr_nbuf,
last_msdu ? 1 : 0) !=
QDF_STATUS_SUCCESS)
goto free_ppdu_desc_mpdu_q;
}
frag_list_sum_len += qdf_nbuf_len(curr_nbuf);
if (last_msdu) {
@@ -2560,13 +2661,15 @@ dp_tx_mon_restitch_mpdu(struct dp_pdev *pdev, struct dp_peer *peer,
ppdu_desc, mpdu_nbuf,
ether_type,
eh->ether_dhost,
usr_idx);
usr_idx,
is_amsdu);
} else {
dp_tx_update_80211_hdr(pdev, peer,
ppdu_desc, mpdu_nbuf,
ether_type,
eh->ether_shost,
usr_idx);
usr_idx,
is_amsdu);
}
/*