From eb8a92cedc9c2ed59828114a3b770e8b545ac3b8 Mon Sep 17 00:00:00 2001 From: "Pamidipati, Vijay" Date: Mon, 1 May 2017 00:55:56 +0530 Subject: [PATCH] qcacmn: Add support for delivering unencrypted errors In mesh mode, it is possible to receive unencrypted frames while security is enabled. Deliver such frames to OS stack. Change-Id: Id148b6ecc1432b419ae97c92f2340155f3d851bf CRs-Fixed: 2004658 --- dp/wifi3.0/dp_rx.c | 7 +- dp/wifi3.0/dp_rx.h | 2 +- dp/wifi3.0/dp_rx_err.c | 145 ++++++++++++++++++++++++++++++++++++----- dp/wifi3.0/hal_rx.h | 2 +- 4 files changed, 134 insertions(+), 22 deletions(-) diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c index 80e44e43a0a1..672982dd9692 100644 --- a/dp/wifi3.0/dp_rx.c +++ b/dp/wifi3.0/dp_rx.c @@ -220,7 +220,7 @@ QDF_STATUS dp_rx_buffers_replenish(struct dp_soc *dp_soc, uint32_t mac_id, */ void dp_rx_deliver_raw(struct dp_vdev *vdev, qdf_nbuf_t nbuf_list, - struct cdp_peer *peer) + struct dp_peer *peer) { qdf_nbuf_t deliver_list_head = NULL; qdf_nbuf_t deliver_list_tail = NULL; @@ -248,7 +248,7 @@ dp_rx_deliver_raw(struct dp_vdev *vdev, qdf_nbuf_t nbuf_list, } vdev->osif_rsim_rx_decap(vdev->osif_vdev, &deliver_list_head, - &deliver_list_tail, peer); + &deliver_list_tail, (struct cdp_peer*) peer); vdev->osif_rx(vdev->osif_vdev, deliver_list_head); } @@ -1308,8 +1308,7 @@ done: if (qdf_unlikely(vdev->rx_decap_type == htt_cmn_pkt_type_raw) || (vdev->rx_decap_type == htt_cmn_pkt_type_native_wifi)) - dp_rx_deliver_raw(vdev, deliver_list_head, - (struct cdp_peer *) peer); + dp_rx_deliver_raw(vdev, deliver_list_head, peer); else if (qdf_likely(vdev->osif_rx) && deliver_list_head) vdev->osif_rx(vdev->osif_vdev, deliver_list_head); } diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index 82ec30a719a5..18fdc8722c7b 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -305,7 +305,7 @@ void dp_rx_desc_pool_free(struct dp_soc *soc, struct rx_desc_pool *rx_desc_pool); void dp_rx_deliver_raw(struct dp_vdev *vdev, qdf_nbuf_t nbuf_list, - struct cdp_peer *peer); + struct dp_peer *peer); /** * dp_rx_add_to_free_desc_list() - Adds to a local free descriptor list diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 79c0cafce464..24805b5ecd86 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -342,10 +342,7 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, struct dp_rx_desc *rx_desc, * Advance the packet start pointer by total size of * pre-header TLV's */ - qdf_nbuf_pull_head(nbuf, RX_PKT_TLVS_LEN); - - if (l2_hdr_offset) - qdf_nbuf_pull_head(nbuf, l2_hdr_offset); + qdf_nbuf_pull_head(nbuf, (l2_hdr_offset + RX_PKT_TLVS_LEN)); nbuf_data = qdf_nbuf_data(nbuf); for (count = 0; count < soc->mect_cnt; count++) { @@ -393,7 +390,7 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, struct dp_rx_desc *rx_desc, if (qdf_unlikely(vdev->rx_decap_type == htt_cmn_pkt_type_raw)) { qdf_nbuf_set_next(nbuf, NULL); - dp_rx_deliver_raw(vdev, nbuf, (struct cdp_peer *) peer); + dp_rx_deliver_raw(vdev, nbuf, peer); } else { if (qdf_unlikely(peer->bss_peer)) { QDF_TRACE(QDF_MODULE_ID_DP, @@ -423,6 +420,115 @@ fail: return rx_bufs_used; } +/** +* dp_rx_err_deliver() - Function to deliver error frames to OS +* +* @soc: core DP main context +* @rx_desc : pointer to the sw rx descriptor +* @head: pointer to head of rx descriptors to be added to free list +* @tail: pointer to tail of rx descriptors to be added to free list +* quota: upper limit of descriptors that can be reaped +* +* Return: uint32_t: No. of Rx buffers reaped +*/ +static uint32_t +dp_rx_err_deliver(struct dp_soc *soc, struct dp_rx_desc *rx_desc, + union dp_rx_desc_list_elem_t **head, + union dp_rx_desc_list_elem_t **tail, + uint32_t quota) +{ + uint32_t rx_bufs_used = 0; + uint32_t pkt_len, l2_hdr_offset; + uint16_t msdu_len; + qdf_nbuf_t nbuf; + struct dp_vdev *vdev; + uint16_t peer_id = 0xFFFF; + struct dp_peer *peer = NULL; + + rx_bufs_used++; + + nbuf = rx_desc->nbuf; + + qdf_nbuf_unmap_single(soc->osdev, nbuf, + QDF_DMA_BIDIRECTIONAL); + + rx_desc->rx_buf_start = qdf_nbuf_data(nbuf); + + /* + * Check if DMA completed -- msdu_done is the last bit + * to be written + */ + if (!hal_rx_attn_msdu_done_get(rx_desc->rx_buf_start)) { + + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + FL("MSDU DONE failure")); + + hal_rx_dump_pkt_tlvs(rx_desc->rx_buf_start, + QDF_TRACE_LEVEL_INFO); + qdf_assert(0); + } + + peer_id = hal_rx_mpdu_start_sw_peer_id_get(rx_desc->rx_buf_start); + peer = dp_peer_find_by_id(soc, peer_id); + + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + FL("peer is NULL")); + DP_STATS_INC_PKT(soc, rx.err.rx_invalid_peer, 1, + qdf_nbuf_len(nbuf)); + /* Drop & free packet */ + qdf_nbuf_free(nbuf); + goto fail; + } + + vdev = peer->vdev; + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + FL("INVALID vdev %p OR osif_rx"), vdev); + /* Drop & free packet */ + qdf_nbuf_free(nbuf); + DP_STATS_INC(soc, rx.err.invalid_vdev, 1); + goto fail; + } + + /* Drop & free packet if mesh mode not enabled */ + if (!vdev->mesh_vdev) { + qdf_nbuf_free(nbuf); + DP_STATS_INC(soc, rx.err.invalid_vdev, 1); + goto fail; + } + + l2_hdr_offset = + hal_rx_msdu_end_l3_hdr_padding_get(rx_desc->rx_buf_start); + + msdu_len = + hal_rx_msdu_start_msdu_len_get(rx_desc->rx_buf_start); + + pkt_len = msdu_len + l2_hdr_offset + RX_PKT_TLVS_LEN; + + /* Set length in nbuf */ + qdf_nbuf_set_pktlen(nbuf, pkt_len); + + qdf_nbuf_set_next(nbuf, NULL); + + /* + * Advance the packet start pointer by total size of + * pre-header TLV's + */ + qdf_nbuf_pull_head(nbuf, (l2_hdr_offset + RX_PKT_TLVS_LEN)); + + if (qdf_unlikely(vdev->rx_decap_type == htt_cmn_pkt_type_raw)) { + dp_rx_deliver_raw(vdev, nbuf, peer); + } else { + DP_STATS_INC(vdev->pdev, rx.to_stack.num, 1); + vdev->osif_rx(vdev->osif_vdev, nbuf); + } +fail: + dp_rx_add_to_free_desc_list(head, tail, rx_desc); + + return rx_bufs_used; +} + /** * dp_rx_link_desc_return() - Return a MPDU link descriptor to HW * (WBM), following error handling @@ -432,7 +538,7 @@ fail: * * Return: QDF_STATUS */ -static QDF_STATUS + static QDF_STATUS dp_rx_link_desc_return(struct dp_soc *soc, void *ring_desc) { void *buf_addr_info = HAL_RX_REO_BUF_ADDR_INFO_GET(ring_desc); @@ -646,6 +752,7 @@ dp_rx_wbm_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota) struct dp_pdev *dp_pdev; struct dp_srng *dp_rxdma_srng; struct rx_desc_pool *rx_desc_pool; + uint8_t pool_id; /* Debug -- Remove later */ qdf_assert(soc && hal_ring); @@ -702,6 +809,8 @@ dp_rx_wbm_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota) continue; } + pool_id = rx_desc->pool_id; + /* XXX */ buf_type = HAL_RX_WBM_BUF_TYPE_GET(ring_desc); @@ -716,7 +825,6 @@ dp_rx_wbm_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota) HAL_RX_WBM_REO_PUSH_REASON_GET(ring_desc); if (push_reason == HAL_RX_WBM_REO_PSH_RSN_ERROR) { - uint8_t reo_error_code = HAL_RX_WBM_REO_ERROR_CODE_GET(ring_desc); @@ -734,11 +842,11 @@ dp_rx_wbm_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota) "Got pkt with REO ERROR: %d", reo_error_code); - rx_bufs_used[rx_desc->pool_id] += + rx_bufs_used[pool_id] += dp_rx_null_q_desc_handle(soc, rx_desc, - &head[rx_desc->pool_id], - &tail[rx_desc->pool_id], quota); + &head[pool_id], + &tail[pool_id], quota); continue; /* TODO */ /* Add per error code accounting */ @@ -763,15 +871,20 @@ dp_rx_wbm_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota) rxdma_error_code], 1); switch (rxdma_error_code) { - - /* TODO */ - /* Add per error code accounting */ + case HAL_RXDMA_ERR_UNENCRYPTED: + rx_bufs_used[pool_id] += + dp_rx_err_deliver(soc, + rx_desc, + &head[pool_id], + &tail[pool_id], + quota); + continue; default: QDF_TRACE(QDF_MODULE_ID_DP, - QDF_TRACE_LEVEL_ERROR, - "RXDMA error %d detected", - rxdma_error_code); + QDF_TRACE_LEVEL_ERROR, + "RXDMA error %d", + rxdma_error_code); } } } else { diff --git a/dp/wifi3.0/hal_rx.h b/dp/wifi3.0/hal_rx.h index 3f8e4e6bda22..a1098cc6f34b 100644 --- a/dp/wifi3.0/hal_rx.h +++ b/dp/wifi3.0/hal_rx.h @@ -1827,7 +1827,7 @@ enum hal_rxdma_error_code { HAL_RXDMA_ERR_FCS, HAL_RXDMA_ERR_DECRYPT, HAL_RXDMA_ERR_TKIP_MIC, - HAL_RXDMA_ERR_UNECRYPTED, + HAL_RXDMA_ERR_UNENCRYPTED, HAL_RXDMA_ERR_MSDU_LEN, HAL_RXDMA_ERR_MSDU_LIMIT, HAL_RXDMA_ERR_WIFI_PARSE,