From 274eb9e76b441013aab010518ab7ae22d29c32d5 Mon Sep 17 00:00:00 2001 From: Tallapragada Kalyan Date: Tue, 16 May 2017 18:59:10 +0530 Subject: [PATCH] qcacmn: Temporary WAR for Multicast echo check in host This is a temporary WAR in host for multicast loopback check until we finalize on exact design, and host or firmware will take care of this Change-Id: I4d2d1b0f5d2a78d4c8716740b74c4fee22c28e96 CRs-Fixed: 2039038 --- dp/wifi3.0/dp_rx.c | 9 ++++++-- dp/wifi3.0/dp_rx_err.c | 30 ++++++++++++++++++++++----- dp/wifi3.0/dp_tx.c | 42 ++++++++++++++++++++++++++++++++++++++ dp/wifi3.0/dp_types.h | 11 ++++++++++ qdf/linux/src/i_qdf_nbuf.h | 18 +++------------- 5 files changed, 88 insertions(+), 22 deletions(-) diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c index 64bfb92cdbd0..b49cb6aecb9c 100644 --- a/dp/wifi3.0/dp_rx.c +++ b/dp/wifi3.0/dp_rx.c @@ -337,6 +337,8 @@ dp_rx_intrabss_fwd(struct dp_soc *soc, if (da_peer->vdev == sa_peer->vdev && !da_peer->bss_peer) { memset(nbuf->cb, 0x0, sizeof(nbuf->cb)); len = qdf_nbuf_len(nbuf); + qdf_nbuf_set_fctx_type(nbuf, (void *)NULL, + CB_FTYPE_INTRABSS_FWD); if (!dp_tx_send(sa_peer->vdev, nbuf)) { DP_STATS_INC_PKT(sa_peer, rx.intra_bss.pkts, 1, len); @@ -363,9 +365,12 @@ dp_rx_intrabss_fwd(struct dp_soc *soc, return false; memset(nbuf_copy->cb, 0x0, sizeof(nbuf_copy->cb)); len = qdf_nbuf_len(nbuf_copy); - if (dp_tx_send(sa_peer->vdev, nbuf_copy)) + qdf_nbuf_set_fctx_type(nbuf_copy, (void *)NULL, + CB_FTYPE_INTRABSS_FWD); + if (dp_tx_send(sa_peer->vdev, nbuf_copy)) { + DP_STATS_INC_PKT(sa_peer, rx.intra_bss.fail, 1, len); qdf_nbuf_free(nbuf_copy); - else + } else DP_STATS_INC_PKT(sa_peer, rx.intra_bss.pkts, 1, len); } /* return false as we have to still send the original pkt diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 6a65be9369fc..eedda2ff81fe 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -224,6 +224,9 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, struct dp_rx_desc *rx_desc, uint16_t peer_id = 0xFFFF; struct dp_peer *peer = NULL; uint32_t sgi, rate_mcs, tid; + uint8_t count; + struct mect_entry *mect_entry; + uint8_t *nbuf_data = NULL; rx_bufs_used++; @@ -293,11 +296,6 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, struct dp_rx_desc *rx_desc, "%s: %d, SGI: %d, rate_mcs: %d, tid: %d", __func__, __LINE__, sgi, rate_mcs, tid); - /* WDS Source Port Learning */ - if (qdf_likely(vdev->rx_decap_type == htt_cmn_pkt_type_ethernet) && - (vdev->wds_enabled)) - dp_rx_wds_srcport_learn(soc, rx_desc->rx_buf_start, peer, nbuf); - /* * Advance the packet start pointer by total size of * pre-header TLV's @@ -307,6 +305,28 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, struct dp_rx_desc *rx_desc, if (l2_hdr_offset) qdf_nbuf_pull_head(nbuf, l2_hdr_offset); + nbuf_data = qdf_nbuf_data(nbuf); + for (count = 0; count < soc->mect_cnt; count++) { + mect_entry = &soc->mect_table[count]; + mect_entry->ts = jiffies_64; + if (!(memcmp(mect_entry->mac_addr, &nbuf_data[DP_MAC_ADDR_LEN], + DP_MAC_ADDR_LEN))) { + QDF_TRACE(QDF_MODULE_ID_DP, + QDF_TRACE_LEVEL_INFO, + FL("received pkt with same src MAC")); + + /* Drop & free packet */ + qdf_nbuf_free(nbuf); + /* Statistics */ + goto fail; + } + } + + /* WDS Source Port Learning */ + if (qdf_likely(vdev->rx_decap_type == htt_cmn_pkt_type_ethernet) && + (vdev->wds_enabled)) + dp_rx_wds_srcport_learn(soc, rx_desc->rx_buf_start, peer, nbuf); + if (hal_rx_mpdu_start_mpdu_qos_control_valid_get( rx_desc->rx_buf_start)) { /* TODO: Assuming that qos_control_valid also indicates diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index 09f2a33857f1..85e31dd22606 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -1397,11 +1397,53 @@ qdf_nbuf_t dp_tx_send(void *vap_dev, qdf_nbuf_t nbuf) struct dp_tx_msdu_info_s msdu_info; struct dp_tx_seg_info_s seg_info; struct dp_vdev *vdev = (struct dp_vdev *) vap_dev; + struct dp_soc *soc = vdev->pdev->soc; uint16_t peer_id = HTT_INVALID_PEER; + uint8_t count; + uint8_t found = 0; + uint8_t oldest_mec_entry_idx = 0; + uint64_t oldest_mec_ts = 0; + struct mect_entry *mect_entry; qdf_mem_set(&msdu_info, sizeof(msdu_info), 0x0); qdf_mem_set(&seg_info, sizeof(seg_info), 0x0); + if (qdf_nbuf_get_ftype(nbuf) == CB_FTYPE_INTRABSS_FWD) + goto out; + + eh = (struct ether_header *)qdf_nbuf_data(nbuf); + if (DP_FRAME_IS_MULTICAST((eh)->ether_dhost)) { + for (count = 0; count < soc->mect_cnt; count++) { + mect_entry = &soc->mect_table[count]; + if (!memcmp(mect_entry->mac_addr, eh->ether_shost, + DP_MAC_ADDR_LEN)) { + found = 1; + break; + } + + if (!oldest_mec_ts) { + oldest_mec_entry_idx = count; + oldest_mec_ts = mect_entry->ts; + } else if (mect_entry->ts < oldest_mec_ts) { + oldest_mec_entry_idx = count; + oldest_mec_ts = mect_entry->ts; + } + } + + if (!found) { + if (count >= DP_MAX_MECT_ENTRIES) + count = oldest_mec_entry_idx; + else + soc->mect_cnt++; + + mect_entry = &soc->mect_table[count]; + mect_entry->ts = jiffies_64; + memcpy(mect_entry->mac_addr, eh->ether_shost, + DP_MAC_ADDR_LEN); + } + } + +out: QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG, "%s , skb %0x:%0x:%0x:%0x:%0x:%0x\n", __func__, nbuf->data[0], nbuf->data[1], nbuf->data[2], diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 0d60efcd3711..7a472afd2393 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -87,6 +87,7 @@ #define MAX_TX_HW_QUEUES 3 #define DP_MAX_INTERRUPT_CONTEXTS 8 +#define DP_MAX_MECT_ENTRIES 64 struct dp_soc_cmn; struct dp_pdev; @@ -378,6 +379,13 @@ struct dp_ast_entry { TAILQ_ENTRY(dp_ast_entry) ast_entry_elem; }; +struct mect_entry { + uint8_t idx; + uint8_t valid; + uint8_t mac_addr[6]; + uint64_t ts; +}; + /* SOC level structure for data path */ struct dp_soc { /* Common base structure - Should be the first member */ @@ -612,6 +620,9 @@ struct dp_soc { #endif qdf_list_t reo_desc_freelist; qdf_spinlock_t reo_desc_freelist_lock; + struct mect_entry mect_table[DP_MAX_MECT_ENTRIES]; + uint8_t mect_cnt; + /* Obj Mgr SoC */ struct wlan_objmgr_psoc *psoc; qdf_nbuf_t invalid_peer_head_msdu; diff --git a/qdf/linux/src/i_qdf_nbuf.h b/qdf/linux/src/i_qdf_nbuf.h index 1812b8a2bd8e..df162f3c1b19 100644 --- a/qdf/linux/src/i_qdf_nbuf.h +++ b/qdf/linux/src/i_qdf_nbuf.h @@ -569,28 +569,16 @@ void __qdf_nbuf_num_frags_init(struct sk_buff *skb) QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb) = 0; } -#ifdef CONFIG_MCL typedef enum { CB_FTYPE_INVALID = 0, CB_FTYPE_MCAST2UCAST = 1, CB_FTYPE_TSO = 2, CB_FTYPE_TSO_SG = 3, CB_FTYPE_SG = 4, + CB_FTYPE_INTRABSS_FWD = 5, + CB_FTYPE_RX_INFO = 6, + CB_FTYPE_MESH_RX_INFO = 7, } CB_FTYPE; -#else -typedef enum { - CB_FTYPE_INVALID = 0, - CB_FTYPE_MCAST2UCAST = 1, - CB_FTYPE_TSO = 2, - CB_FTYPE_TSO_SG = 3, - CB_FTYPE_SG = 4, -#if ATH_DATA_RX_INFO_EN - CB_FTYPE_RX_INFO = 5, -#else - CB_FTYPE_MESH_RX_INFO = 5, -#endif -} CB_FTYPE; -#endif /* * prototypes. Implemented in qdf_nbuf.c