From b43e679a586c8031dbcf4e31234e688b0580a5cb Mon Sep 17 00:00:00 2001 From: Sai Rupesh Chevuru Date: Tue, 23 Nov 2021 19:39:15 +0530 Subject: [PATCH] qcacmn: Multicast support for MLO Multicast support for MLO 1. Following functions are newly added. dp_rx_igmp_handler() dp_tx_mlo_mcast_handler_be() dp_rx_mlo_mcast_handler_be() dp_mlo_get_mcast_primary_vdev() Change-Id: If215f843369e6e2621ef302b924e524c86f0d30b --- dp/inc/cdp_txrx_cmn_struct.h | 6 +- dp/wifi3.0/be/dp_be.c | 23 ++++++ dp/wifi3.0/be/dp_be.h | 41 +++++++++++ dp/wifi3.0/be/dp_be_rx.c | 66 +++++++++++++++++ dp/wifi3.0/be/dp_be_rx.h | 19 +++++ dp/wifi3.0/be/dp_be_tx.c | 97 ++++++++++++++++++++++++- dp/wifi3.0/be/dp_be_tx.h | 30 ++++++++ dp/wifi3.0/be/mlo/dp_mlo.c | 74 +++++++++++++++++++ dp/wifi3.0/dp_htt.c | 134 +++++++++++++++++++++++++++-------- dp/wifi3.0/dp_main.c | 12 +++- dp/wifi3.0/dp_rx_err.c | 26 +++++++ dp/wifi3.0/dp_tx.c | 133 +++++++++++++++++++++++++++++----- dp/wifi3.0/dp_tx.h | 8 +++ dp/wifi3.0/dp_types.h | 6 ++ qdf/inc/qdf_nbuf.h | 30 ++++++++ qdf/linux/src/i_qdf_nbuf.h | 2 + qdf/linux/src/qdf_nbuf.c | 56 +++++++++++++++ 17 files changed, 709 insertions(+), 54 deletions(-) diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index 9bf4c8e328..b67dcbff31 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -1243,6 +1243,7 @@ enum cdp_pdev_param_type { * @cdp_vdev_param_peer_tid_latency_enable: set peer tid latency enable flag * @cdp_vdev_param_mesh_tid: config tatency tid on vdev * @cdp_vdev_param_dscp_tid_map_id: set dscp to tid map id + * @cdp_vdev_param_mcast_vdev: set mcast vdev params * * @cdp_pdev_param_dbg_snf: Enable debug sniffer feature * @cdp_pdev_param_bpr_enable: Enable bcast probe feature @@ -1314,6 +1315,7 @@ typedef union cdp_config_param_t { uint8_t cdp_vdev_param_peer_tid_latency_enable; uint8_t cdp_vdev_param_mesh_tid; uint8_t cdp_vdev_param_dscp_tid_map_id; + bool cdp_vdev_param_mcast_vdev; /* pdev params */ bool cdp_pdev_param_cptr_latcy; @@ -1433,6 +1435,7 @@ enum cdp_pdev_bpr_param { * @CDP_ENABLE_PEER_TID_LATENCY: set peer tid latency enable flag * @CDP_SET_VAP_MESH_TID : Set latency tid in vap * @CDP_UPDATE_DSCP_TO_TID_MAP: Set DSCP to TID map id + * @CDP_SET_MCAST_VDEV : Set primary mcast vdev */ enum cdp_vdev_param_type { CDP_ENABLE_NAWDS, @@ -1470,7 +1473,8 @@ enum cdp_vdev_param_type { #ifdef WLAN_VENDOR_SPECIFIC_BAR_UPDATE CDP_SKIP_BAR_UPDATE_AP, #endif - CDP_UPDATE_DSCP_TO_TID_MAP + CDP_UPDATE_DSCP_TO_TID_MAP, + CDP_SET_MCAST_VDEV, }; /* diff --git a/dp/wifi3.0/be/dp_be.c b/dp/wifi3.0/be/dp_be.c index ea7c03502f..25c7686ada 100644 --- a/dp/wifi3.0/be/dp_be.c +++ b/dp/wifi3.0/be/dp_be.c @@ -1238,6 +1238,22 @@ dp_mlo_peer_find_hash_add_be(struct dp_soc *soc, struct dp_peer *peer) } #endif +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP) && \ + defined(WLAN_MCAST_MLO) +static void dp_txrx_set_mlo_mcast_primary_vdev_param_be( + struct dp_vdev_be *be_vdev, + cdp_config_param_type val) +{ + be_vdev->mcast_primary = val.cdp_vdev_param_mcast_vdev; +} +#else +static void dp_txrx_set_mlo_mcast_primary_vdev_param_be( + struct dp_vdev_be *be_vdev, + cdp_config_param_type val) +{ +} +#endif + #ifdef DP_TX_IMPLICIT_RBM_MAPPING static void dp_tx_implicit_rbm_set_be(struct dp_soc *soc, uint8_t tx_ring_id, @@ -1348,6 +1364,9 @@ QDF_STATUS dp_txrx_set_vdev_param_be(struct dp_soc *soc, if (vdev->tx_encap_type == htt_cmn_pkt_type_raw) dp_tx_update_bank_profile(be_soc, be_vdev); break; + case CDP_SET_MCAST_VDEV: + dp_txrx_set_mlo_mcast_primary_vdev_param_be(be_vdev, val); + break; default: dp_warn("invalid param %d", param); break; @@ -1438,6 +1457,10 @@ void dp_initialize_arch_ops_be(struct dp_arch_ops *arch_ops) arch_ops->txrx_set_vdev_param = dp_txrx_set_vdev_param_be; #ifdef WLAN_FEATURE_11BE_MLO +#ifdef WLAN_MCAST_MLO + arch_ops->dp_tx_mcast_handler = dp_tx_mlo_mcast_handler_be; + arch_ops->dp_rx_mcast_handler = dp_rx_mlo_igmp_handler; +#endif arch_ops->mlo_peer_find_hash_detach = dp_mlo_peer_find_hash_detach_wrapper; arch_ops->mlo_peer_find_hash_attach = diff --git a/dp/wifi3.0/be/dp_be.h b/dp/wifi3.0/be/dp_be.h index 453d2bf770..f530901e14 100644 --- a/dp/wifi3.0/be/dp_be.h +++ b/dp/wifi3.0/be/dp_be.h @@ -256,6 +256,14 @@ struct dp_vdev_be { #ifdef WLAN_MLO_MULTI_CHIP /* partner list used for Intra-BSS */ uint8_t partner_vdev_list[WLAN_MAX_MLO_CHIPS][WLAN_MAX_MLO_LINKS_PER_SOC]; +#ifdef WLAN_FEATURE_11BE_MLO +#ifdef WLAN_MCAST_MLO + /* DP MLO seq number */ + uint16_t seq_num; + /* MLO Mcast primary vdev */ + bool mcast_primary; +#endif +#endif #endif }; @@ -320,6 +328,39 @@ dp_mlo_get_peer_hash_obj(struct dp_soc *soc) } void dp_clr_mlo_ptnr_list(struct dp_soc *soc, struct dp_vdev *vdev); + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MCAST_MLO) +typedef void dp_ptnr_vdev_iter_func(struct dp_vdev_be *be_vdev, + struct dp_vdev *ptnr_vdev, + void *arg); +/* + * dp_mcast_mlo_iter_ptnr_vdev - API to iterate through ptnr vdev list + * @be_soc: dp_soc_be pointer + * @be_vdev: dp_vdev_be pointer + * @func : function to be called for each peer + * @arg : argument need to be passed to func + * @mod_id: module id + * + * Return: None + */ +void dp_mcast_mlo_iter_ptnr_vdev(struct dp_soc_be *be_soc, + struct dp_vdev_be *be_vdev, + dp_ptnr_vdev_iter_func func, + void *arg, + enum dp_mod_id mod_id); +/* + * dp_mlo_get_mcast_primary_vdev- get ref to mcast primary vdev + * @be_soc: dp_soc_be pointer + * @be_vdev: dp_vdev_be pointer + * @mod_id: module id + * + * Return: mcast primary DP VDEV handle on success, NULL on failure + */ +struct dp_vdev *dp_mlo_get_mcast_primary_vdev(struct dp_soc_be *be_soc, + struct dp_vdev_be *be_vdev, + enum dp_mod_id mod_id); +#endif + #else typedef struct dp_soc_be *dp_mld_peer_hash_obj_t; diff --git a/dp/wifi3.0/be/dp_be_rx.c b/dp/wifi3.0/be/dp_be_rx.c index 8695b1853e..77d6adc969 100644 --- a/dp/wifi3.0/be/dp_be_rx.c +++ b/dp/wifi3.0/be/dp_be_rx.c @@ -1072,6 +1072,72 @@ struct dp_rx_desc *dp_rx_desc_cookie_2_va_be(struct dp_soc *soc, return (struct dp_rx_desc *)dp_cc_desc_find(soc, cookie); } +#if defined(WLAN_FEATURE_11BE_MLO) +#if defined(WLAN_MLO_MULTI_CHIP) && defined(WLAN_MCAST_MLO) +static inline void dp_rx_dummy_src_mac(qdf_nbuf_t nbuf) +{ + qdf_ether_header_t *eh = + (qdf_ether_header_t *)qdf_nbuf_data(nbuf); + + eh->ether_shost[0] = 0x4d; /* M */ + eh->ether_shost[1] = 0x4c; /* L */ + eh->ether_shost[2] = 0x4d; /* M */ + eh->ether_shost[3] = 0x43; /* C */ + eh->ether_shost[4] = 0x41; /* A */ + eh->ether_shost[5] = 0x53; /* S */ +} + +bool dp_rx_mlo_igmp_handler(struct dp_soc *soc, + struct dp_vdev *vdev, + struct dp_peer *peer, + qdf_nbuf_t nbuf) +{ + struct dp_vdev *mcast_primary_vdev = NULL; + struct dp_vdev_be *be_vdev = dp_get_be_vdev_from_dp_vdev(vdev); + struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); + + if (!(qdf_nbuf_is_ipv4_igmp_pkt(buf) || + qdf_nbuf_is_ipv6_igmp_pkt(buf))) + return false; + + if (vdev->mcast_enhancement_en || be_vdev->mcast_primary) + goto send_pkt; + + mcast_primary_vdev = dp_mlo_get_mcast_primary_vdev(be_soc, be_vdev, + DP_MOD_ID_RX); + if (!mcast_primary_vdev) { + dp_rx_debug("Non mlo vdev"); + goto send_pkt; + } + dp_rx_dummy_src_mac(nbuf); + dp_rx_deliver_to_stack(mcast_primary_vdev->pdev->soc, + mcast_primary_vdev, + peer, + nbuf, + NULL); + dp_vdev_unref_delete(mcast_primary_vdev->pdev->soc, + mcast_primary_vdev, + DP_MOD_ID_RX); + return true; +send_pkt: + dp_rx_deliver_to_stack(be_vdev->vdev.pdev->soc, + &be_vdev->vdev, + peer, + nbuf, + NULL); + return true; +} +#else +bool dp_rx_mlo_igmp_handler(struct dp_soc *soc, + struct dp_vdev *vdev, + struct dp_peer *peer, + qdf_nbuf_t nbuf) +{ + return false; +} +#endif +#endif + #ifdef WLAN_FEATURE_NEAR_FULL_IRQ uint32_t dp_rx_nf_process(struct dp_intr *int_ctx, hal_ring_handle_t hal_ring_hdl, diff --git a/dp/wifi3.0/be/dp_be_rx.h b/dp/wifi3.0/be/dp_be_rx.h index ac32ccefe7..fe11a1dbbe 100644 --- a/dp/wifi3.0/be/dp_be_rx.h +++ b/dp/wifi3.0/be/dp_be_rx.h @@ -209,4 +209,23 @@ dp_rx_replensih_soc_get(struct dp_soc *soc, uint8_t reo_ring_num) return soc; } #endif + +#ifdef WLAN_FEATURE_11BE_MLO +#ifdef WLAN_MCAST_MLO +/** + * dp_rx_mlo_igmp_handler() - Rx handler for Mcast packets + * @soc: Handle to DP Soc structure + * @vdev: DP vdev handle + * @peer: DP peer handle + * @nbuf: nbuf to be enqueued + * + * Return: true when packet sent to stack, false failure + */ +bool dp_rx_mlo_igmp_handler(struct dp_soc *soc, + struct dp_vdev *vdev, + struct dp_peer *peer, + qdf_nbuf_t nbuf); +#endif +#endif + #endif diff --git a/dp/wifi3.0/be/dp_be_tx.c b/dp/wifi3.0/be/dp_be_tx.c index 4b2d26a9bf..99ada432af 100644 --- a/dp/wifi3.0/be/dp_be_tx.c +++ b/dp/wifi3.0/be/dp_be_tx.c @@ -38,6 +38,14 @@ #define DP_TX_BANK_LOCK_RELEASE(lock) qdf_spin_unlock_bh(lock) #endif +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP) +#ifdef WLAN_MCAST_MLO +/* MLO peer id for reinject*/ +#define DP_MLO_MCAST_REINJECT_PEER_ID 0XFFFD +#define MAX_GSN_NUM 0x0FFF +#endif +#endif + extern uint8_t sec_type_map[MAX_CDP_SEC_TYPE]; #ifdef DP_USE_REDUCED_PEER_ID_FIELD_WIDTH @@ -156,6 +164,93 @@ static inline uint8_t dp_tx_get_rbm_id_be(struct dp_soc *soc, } #endif +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP) && \ + defined(WLAN_MCAST_MLO) +void +dp_tx_mlo_mcast_pkt_send(struct dp_vdev_be *be_vdev, + struct dp_vdev *ptnr_vdev, + void *arg) +{ + qdf_nbuf_t nbuf = (qdf_nbuf_t)arg; + qdf_nbuf_t nbuf_clone; + struct dp_vdev_be *be_ptnr_vdev = NULL; + struct dp_tx_msdu_info_s msdu_info; + + be_ptnr_vdev = dp_get_be_vdev_from_dp_vdev(ptnr_vdev); + if (be_vdev != be_ptnr_vdev) { + nbuf_clone = qdf_nbuf_clone(nbuf); + if (qdf_unlikely(!nbuf_clone)) { + dp_tx_debug("nbuf clone failed"); + return; + } + } else { + nbuf_clone = nbuf; + } + + qdf_mem_zero(&msdu_info, sizeof(msdu_info)); + dp_tx_get_queue(ptnr_vdev, nbuf_clone, &msdu_info.tx_queue); + msdu_info.gsn = be_vdev->seq_num; + be_ptnr_vdev->seq_num = be_vdev->seq_num; + + nbuf_clone = dp_tx_send_msdu_single( + ptnr_vdev, + nbuf_clone, + &msdu_info, + DP_MLO_MCAST_REINJECT_PEER_ID, + NULL); + if (qdf_unlikely(nbuf_clone)) { + dp_info("pkt send failed"); + qdf_nbuf_free(nbuf_clone); + return; + } +} + +static inline void +dp_tx_vdev_id_set_hal_tx_desc(uint32_t *hal_tx_desc_cached, + struct dp_vdev *vdev, + struct dp_tx_msdu_info_s *msdu_info) +{ + hal_tx_desc_set_vdev_id(hal_tx_desc_cached, msdu_info->vdev_id); +} + +void dp_tx_mlo_mcast_handler_be(struct dp_soc *soc, + struct dp_vdev *vdev, + qdf_nbuf_t nbuf) +{ + struct dp_vdev_be *be_vdev = dp_get_be_vdev_from_dp_vdev(vdev); + struct dp_soc_be *be_soc = dp_get_be_soc_from_dp_soc(soc); + + /* send frame on partner vdevs */ + dp_mcast_mlo_iter_ptnr_vdev(be_soc, be_vdev, + dp_tx_mlo_mcast_pkt_send, + nbuf, DP_MOD_ID_TX); + + /* send frame on mcast primary vdev */ + dp_tx_mlo_mcast_pkt_send(be_vdev, vdev, nbuf); + + if (qdf_unlikely(be_vdev->seq_num > MAX_GSN_NUM)) + be_vdev->seq_num = 0; + else + be_vdev->seq_num++; +} +#else +static inline void +dp_tx_vdev_id_set_hal_tx_desc(uint32_t *hal_tx_desc_cached, + struct dp_vdev *vdev, + struct dp_tx_msdu_info_s *msdu_info) +{ + hal_tx_desc_set_vdev_id(hal_tx_desc_cached, vdev->vdev_id); +} +#endif +#if defined(WLAN_FEATURE_11BE_MLO) && !defined(WLAN_MLO_MULTI_CHIP) && \ + !defined(WLAN_MCAST_MLO) +void dp_tx_mlo_mcast_handler_be(struct dp_soc *soc, + struct dp_vdev *vdev, + qdf_nbuf_t nbuf) +{ +} +#endif + QDF_STATUS dp_tx_hw_enqueue_be(struct dp_soc *soc, struct dp_vdev *vdev, struct dp_tx_desc_s *tx_desc, uint16_t fw_metadata, @@ -229,7 +324,7 @@ dp_tx_hw_enqueue_be(struct dp_soc *soc, struct dp_vdev *vdev, hal_tx_desc_set_bank_id(hal_tx_desc_cached, be_vdev->bank_id); - hal_tx_desc_set_vdev_id(hal_tx_desc_cached, vdev->vdev_id); + dp_tx_vdev_id_set_hal_tx_desc(hal_tx_desc_cached, vdev, msdu_info); if (tid != HTT_TX_EXT_TID_INVALID) hal_tx_desc_set_hlos_tid(hal_tx_desc_cached, tid); diff --git a/dp/wifi3.0/be/dp_be_tx.h b/dp/wifi3.0/be/dp_be_tx.h index afd48b663a..922fa4802f 100644 --- a/dp/wifi3.0/be/dp_be_tx.h +++ b/dp/wifi3.0/be/dp_be_tx.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. 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 @@ -139,6 +140,35 @@ void dp_tx_desc_pool_deinit_be(struct dp_soc *soc, struct dp_tx_desc_pool_s *tx_desc_pool, uint8_t pool_id); +#ifdef WLAN_FEATURE_11BE_MLO +#ifdef WLAN_MCAST_MLO +/** + * dp_tx_mlo_mcast_handler_be() - Tx handler for Mcast packets + * @soc: Handle to DP Soc structure + * @vdev: DP vdev handle + * @nbuf: nbuf to be enqueued + * + * Return: None + */ +void dp_tx_mlo_mcast_handler_be(struct dp_soc *soc, + struct dp_vdev *vdev, + qdf_nbuf_t nbuf); +#ifdef WLAN_MLO_MULTI_CHIP +/** + * dp_tx_mlo_mcast_pkt_send() - handler to send MLO Mcast packets + * @be_vdev: Handle to DP be_vdev structure + * @ptnr_vdev: DP ptnr_vdev handle + * @nbuf: nbuf to be enqueued + * + * Return: None + */ +void dp_tx_mlo_mcast_pkt_send(struct dp_vdev_be *be_vdev, + struct dp_vdev *ptnr_vdev, + void *arg); +#endif +#endif +#endif + #ifdef WLAN_FEATURE_NEAR_FULL_IRQ /** * dp_tx_comp_nf_handler() - Tx completion ring Near full scenario handler diff --git a/dp/wifi3.0/be/mlo/dp_mlo.c b/dp/wifi3.0/be/mlo/dp_mlo.c index da50a6926b..65104c2ddb 100644 --- a/dp/wifi3.0/be/mlo/dp_mlo.c +++ b/dp/wifi3.0/be/mlo/dp_mlo.c @@ -472,3 +472,77 @@ dp_rx_replensih_soc_get(struct dp_soc *soc, uint8_t reo_ring_num) return soc; } + +#ifdef WLAN_MCAST_MLO +void dp_mcast_mlo_iter_ptnr_vdev(struct dp_soc_be *be_soc, + struct dp_vdev_be *be_vdev, + dp_ptnr_vdev_iter_func func, + void *arg, + enum dp_mod_id mod_id) +{ + int i = 0; + int j = 0; + struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt; + + for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) { + struct dp_soc *ptnr_soc = + dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i); + + if (!ptnr_soc) + continue; + for (j = 0 ; j < WLAN_MAX_MLO_LINKS_PER_SOC ; j++) { + struct dp_vdev *ptnr_vdev; + + ptnr_vdev = dp_vdev_get_ref_by_id( + ptnr_soc, + be_vdev->partner_vdev_list[i][j], + mod_id); + if (!ptnr_vdev) + continue; + (*func)(be_vdev, ptnr_vdev, arg); + dp_vdev_unref_delete(ptnr_vdev->pdev->soc, + ptnr_vdev, + mod_id); + } + } +} + +qdf_export_symbol(dp_mcast_mlo_iter_ptnr_vdev); + +struct dp_vdev *dp_mlo_get_mcast_primary_vdev(struct dp_soc_be *be_soc, + struct dp_vdev_be *be_vdev, + enum dp_mod_id mod_id) +{ + int i = 0; + int j = 0; + struct dp_mlo_ctxt *dp_mlo = be_soc->ml_ctxt; + + for (i = 0; i < WLAN_MAX_MLO_CHIPS ; i++) { + struct dp_soc *ptnr_soc = + dp_mlo_get_soc_ref_by_chip_id(dp_mlo, i); + + if (!ptnr_soc) + continue; + for (j = 0 ; j < WLAN_MAX_MLO_LINKS_PER_SOC ; j++) { + struct dp_vdev *ptnr_vdev = NULL; + struct dp_vdev_be *be_ptnr_vdev = NULL; + + ptnr_vdev = dp_vdev_get_ref_by_id( + ptnr_soc, + be_vdev->partner_vdev_list[i][j], + mod_id); + if (!ptnr_vdev) + continue; + be_ptnr_vdev = dp_get_be_vdev_from_dp_vdev(ptnr_vdev); + if (be_ptnr_vdev->mcast_primary) + return ptnr_vdev; + dp_vdev_unref_delete(be_ptnr_vdev->vdev.pdev->soc, + &be_ptnr_vdev->vdev, + mod_id); + } + } + return NULL; +} + +qdf_export_symbol(dp_mlo_get_mcast_primary_vdev); +#endif diff --git a/dp/wifi3.0/dp_htt.c b/dp/wifi3.0/dp_htt.c index e7dce83e1b..606b31c100 100644 --- a/dp/wifi3.0/dp_htt.c +++ b/dp/wifi3.0/dp_htt.c @@ -327,6 +327,105 @@ dp_htt_h2t_send_complete(void *context, HTC_PACKET *htc_pkt) #endif /* ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST */ +#ifdef WLAN_MCAST_MLO +/* + * dp_htt_h2t_add_tcl_metadata_verg() - Add tcl_metadata verion + * @htt_soc: HTT SOC handle + * @msg: Pointer to nbuf + * + * Return: 0 on success; error code on failure + */ +static int dp_htt_h2t_add_tcl_metadata_ver(struct htt_soc *soc, qdf_nbuf_t *msg) +{ + uint32_t *msg_word; + + *msg = qdf_nbuf_alloc( + soc->osdev, + HTT_MSG_BUF_SIZE(HTT_VER_REQ_BYTES + HTT_TCL_METADATA_VER_SZ), + /* reserve room for the HTC header */ + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, TRUE); + if (!*msg) + return QDF_STATUS_E_NOMEM; + + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to qdf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + if (!qdf_nbuf_put_tail(*msg, + HTT_VER_REQ_BYTES + HTT_TCL_METADATA_VER_SZ)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to expand head for HTT_H2T_MSG_TYPE_VERSION_REQ msg", + __func__); + return QDF_STATUS_E_FAILURE; + } + + /* fill in the message contents */ + msg_word = (u_int32_t *)qdf_nbuf_data(*msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(*msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_VERSION_REQ); + + /* word 1 */ + msg_word++; + *msg_word = 0; + HTT_OPTION_TLV_TAG_SET(*msg_word, HTT_OPTION_TLV_TAG_TCL_METADATA_VER); + HTT_OPTION_TLV_LENGTH_SET(*msg_word, HTT_TCL_METADATA_VER_SZ); + HTT_OPTION_TLV_TCL_METADATA_VER_SET(*msg_word, + HTT_OPTION_TLV_TCL_METADATA_V2); + + return QDF_STATUS_SUCCESS; +} +#else +/* + * dp_htt_h2t_add_tcl_metadata_verg() - Add tcl_metadata verion + * @htt_soc: HTT SOC handle + * @msg: Pointer to nbuf + * + * Return: 0 on success; error code on failure + */ +static int dp_htt_h2t_add_tcl_metadata_ver(struct htt_soc *soc, qdf_nbuf_t *msg) +{ + uint32_t *msg_word; + + *msg = qdf_nbuf_alloc( + soc->osdev, + HTT_MSG_BUF_SIZE(HTT_VER_REQ_BYTES), + /* reserve room for the HTC header */ + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, TRUE); + if (!*msg) + return QDF_STATUS_E_NOMEM; + + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to qdf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + if (!qdf_nbuf_put_tail(*msg, HTT_VER_REQ_BYTES)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to expand head for HTT_H2T_MSG_TYPE_VERSION_REQ msg", + __func__); + return QDF_STATUS_E_FAILURE; + } + + /* fill in the message contents */ + msg_word = (u_int32_t *)qdf_nbuf_data(*msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(*msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_VERSION_REQ); + + return QDF_STATUS_SUCCESS; +} +#endif + /* * htt_h2t_ver_req_msg() - Send HTT version request message to target * @htt_soc: HTT SOC handle @@ -336,39 +435,12 @@ dp_htt_h2t_send_complete(void *context, HTC_PACKET *htc_pkt) static int htt_h2t_ver_req_msg(struct htt_soc *soc) { struct dp_htt_htc_pkt *pkt; - qdf_nbuf_t msg; - uint32_t *msg_word; + qdf_nbuf_t msg = NULL; QDF_STATUS status; - msg = qdf_nbuf_alloc( - soc->osdev, - HTT_MSG_BUF_SIZE(HTT_VER_REQ_BYTES), - /* reserve room for the HTC header */ - HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, TRUE); - if (!msg) - return QDF_STATUS_E_NOMEM; - - /* - * Set the length of the message. - * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added - * separately during the below call to qdf_nbuf_push_head. - * The contribution from the HTC header is added separately inside HTC. - */ - if (qdf_nbuf_put_tail(msg, HTT_VER_REQ_BYTES) == NULL) { - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: Failed to expand head for HTT_H2T_MSG_TYPE_VERSION_REQ msg", - __func__); - return QDF_STATUS_E_FAILURE; - } - - /* fill in the message contents */ - msg_word = (u_int32_t *) qdf_nbuf_data(msg); - - /* rewind beyond alignment pad to get to the HTC header reserved area */ - qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); - - *msg_word = 0; - HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_VERSION_REQ); + status = dp_htt_h2t_add_tcl_metadata_ver(soc, &msg); + if (status != QDF_STATUS_SUCCESS) + return status; pkt = htt_htc_pkt_alloc(soc); if (!pkt) { diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 6eab930806..c8e0fd442a 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -111,6 +111,14 @@ cdp_dump_flow_pool_info(struct cdp_soc_t *soc) #define WLAN_SYSFS_STAT_REQ_WAIT_MS 3000 #endif +#ifdef WLAN_MCAST_MLO +#define DP_TX_TCL_METADATA_PDEV_ID_SET(_var, _val) \ + HTT_TX_TCL_METADATA_V2_PDEV_ID_SET(_var, _val) +#else +#define DP_TX_TCL_METADATA_PDEV_ID_SET(_var, _val) \ + HTT_TX_TCL_METADATA_PDEV_ID_SET(_var, _val) +#endif + QDF_COMPILE_TIME_ASSERT(max_rx_rings_check, MAX_REO_DEST_RINGS == CDP_MAX_RX_RINGS); @@ -11136,8 +11144,8 @@ dp_soc_handle_pdev_mode_change qdf_spin_lock_bh(&pdev->vdev_list_lock); TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { - HTT_TX_TCL_METADATA_PDEV_ID_SET(vdev->htt_tcl_metadata, - hw_pdev_id); + DP_TX_TCL_METADATA_PDEV_ID_SET(vdev->htt_tcl_metadata, + hw_pdev_id); vdev->lmac_id = pdev->lmac_id; } qdf_spin_unlock_bh(&pdev->vdev_list_lock); diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index f505a2e480..f8c92d99b5 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -1764,6 +1764,29 @@ dp_rx_deliver_to_osif_stack(struct dp_soc *soc, #endif #ifdef WLAN_SUPPORT_RX_PROTOCOL_TYPE_TAG +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP) && \ + defined(WLAN_MCAST_MLO) +static bool dp_rx_igmp_handler(struct dp_soc *soc, + struct dp_vdev *vdev, + struct dp_peer *peer, + qdf_nbuf_t nbuf) +{ + if (soc->arch_ops.dp_rx_mcast_handler) { + if (soc->arch_ops.dp_rx_mcast_handler(soc, vdev, peer, nbuf)) + return true; + } + return false; +} +#else +static bool dp_rx_igmp_handler(struct dp_soc *soc, + struct dp_vdev *vdev, + struct dp_peer *peer, + qdf_nbuf_t nbuf) +{ + return false; +} +#endif + /** * dp_rx_err_route_hdl() - Function to send EAPOL frames to stack * Free any other packet which comes in @@ -1836,6 +1859,9 @@ dp_rx_err_route_hdl(struct dp_soc *soc, qdf_nbuf_t nbuf, qdf_nbuf_pull_head(nbuf, (msdu_metadata.l3_hdr_pad + soc->rx_pkt_tlv_size)); + if (dp_rx_igmp_handler(soc, vdev, peer, nbuf)) + return; + dp_vdev_peer_stats_update_protocol_cnt(vdev, nbuf, NULL, 0, 1); /* diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index c7a672db20..38dea70e11 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -65,6 +65,42 @@ #define DP_RETRY_COUNT 7 +#ifdef WLAN_MCAST_MLO +#define DP_TX_TCL_METADATA_PDEV_ID_SET(_var, _val)\ + HTT_TX_TCL_METADATA_V2_PDEV_ID_SET(_var, _val) +#define DP_TX_TCL_METADATA_VALID_HTT_SET(_var, _val) \ + HTT_TX_TCL_METADATA_V2_VALID_HTT_SET(_var, _val) +#define DP_TX_TCL_METADATA_TYPE_SET(_var, _val) \ + HTT_TX_TCL_METADATA_TYPE_V2_SET(_var, _val) +#define DP_TX_TCL_METADATA_HOST_INSPECTED_SET(_var, _val) \ + HTT_TX_TCL_METADATA_V2_HOST_INSPECTED_SET(_var, _val) +#define DP_TX_TCL_METADATA_PEER_ID_SET(_var, _val) \ + HTT_TX_TCL_METADATA_V2_PEER_ID_SET(_var, _val) +#define DP_TX_TCL_METADATA_VDEV_ID_SET(_var, _val) \ + HTT_TX_TCL_METADATA_V2_VDEV_ID_SET(_var, _val) +#define DP_TCL_METADATA_TYPE_PEER_BASED \ + HTT_TCL_METADATA_V2_TYPE_PEER_BASED +#define DP_TCL_METADATA_TYPE_VDEV_BASED \ + HTT_TCL_METADATA_V2_TYPE_VDEV_BASED +#else +#define DP_TX_TCL_METADATA_PDEV_ID_SET(_var, _val)\ + HTT_TX_TCL_METADATA_PDEV_ID_SET(_var, _val) +#define DP_TX_TCL_METADATA_VALID_HTT_SET(_var, _val) \ + HTT_TX_TCL_METADATA_VALID_HTT_SET(_var, _val) +#define DP_TX_TCL_METADATA_TYPE_SET(_var, _val) \ + HTT_TX_TCL_METADATA_TYPE_SET(_var, _val) +#define DP_TX_TCL_METADATA_HOST_INSPECTED_SET(_var, _val) \ + HTT_TX_TCL_METADATA_HOST_INSPECTED_SET(_var, _val) +#define DP_TX_TCL_METADATA_PEER_ID_SET(_var, _val) \ + HTT_TX_TCL_METADATA_PEER_ID_SET(_var, _val) +#define DP_TX_TCL_METADATA_VDEV_ID_SET(_var, _val) \ + HTT_TX_TCL_METADATA_VDEV_ID_SET(_var, _val) +#define DP_TCL_METADATA_TYPE_PEER_BASED \ + HTT_TCL_METADATA_TYPE_PEER_BASED +#define DP_TCL_METADATA_TYPE_VDEV_BASED \ + HTT_TCL_METADATA_TYPE_VDEV_BASED +#endif + /*mapping between hal encrypt type and cdp_sec_type*/ uint8_t sec_type_map[MAX_CDP_SEC_TYPE] = {HAL_TX_ENCRYPT_TYPE_NO_CIPHER, HAL_TX_ENCRYPT_TYPE_WEP_128, @@ -1908,6 +1944,41 @@ int dp_tx_frame_is_drop(struct dp_vdev *vdev, uint8_t *srcmac, uint8_t *dstmac) return 0; } +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP) && \ + defined(WLAN_MCAST_MLO) +/* MLO peer id for reinject*/ +#define DP_MLO_MCAST_REINJECT_PEER_ID 0XFFFD +/* MLO vdev id inc offset */ +#define DP_MLO_VDEV_ID_OFFSET 0x80 + +static inline void +dp_tx_update_mcast_param(uint16_t peer_id, + uint16_t *htt_tcl_metadata, + struct dp_vdev *vdev, + struct dp_tx_msdu_info_s *msdu_info) +{ + if (peer_id == DP_MLO_MCAST_REINJECT_PEER_ID) { + *htt_tcl_metadata = 0; + DP_TX_TCL_METADATA_TYPE_SET( + *htt_tcl_metadata, + HTT_TCL_METADATA_V2_TYPE_GLOBAL_SEQ_BASED); + HTT_TX_TCL_METADATA_GLBL_SEQ_NO_SET(*htt_tcl_metadata, + msdu_info->gsn); + + msdu_info->vdev_id = vdev->vdev_id + DP_MLO_VDEV_ID_OFFSET; + } else { + msdu_info->vdev_id = vdev->vdev_id; + } +} +#else +static inline void +dp_tx_update_mcast_param(uint16_t peer_id, + uint16_t *htt_tcl_metadata, + struct dp_vdev *vdev, + struct dp_tx_msdu_info_s *msdu_info) +{ +} +#endif /** * dp_tx_send_msdu_single() - Setup descriptor and enqueue single MSDU to TCL * @vdev: DP vdev handle @@ -1950,17 +2021,17 @@ dp_tx_send_msdu_single(struct dp_vdev *vdev, qdf_nbuf_t nbuf, if (qdf_unlikely(peer_id == DP_INVALID_PEER)) { htt_tcl_metadata = vdev->htt_tcl_metadata; - HTT_TX_TCL_METADATA_HOST_INSPECTED_SET(htt_tcl_metadata, 1); + DP_TX_TCL_METADATA_HOST_INSPECTED_SET(htt_tcl_metadata, 1); } else if (qdf_unlikely(peer_id != HTT_INVALID_PEER)) { - HTT_TX_TCL_METADATA_TYPE_SET(htt_tcl_metadata, - HTT_TCL_METADATA_TYPE_PEER_BASED); - HTT_TX_TCL_METADATA_PEER_ID_SET(htt_tcl_metadata, - peer_id); + DP_TX_TCL_METADATA_TYPE_SET(htt_tcl_metadata, + DP_TCL_METADATA_TYPE_PEER_BASED); + DP_TX_TCL_METADATA_PEER_ID_SET(htt_tcl_metadata, + peer_id); } else htt_tcl_metadata = vdev->htt_tcl_metadata; if (msdu_info->exception_fw) - HTT_TX_TCL_METADATA_VALID_HTT_SET(htt_tcl_metadata, 1); + DP_TX_TCL_METADATA_VALID_HTT_SET(htt_tcl_metadata, 1); dp_tx_desc_update_fast_comp_flag(soc, tx_desc, !pdev->enhanced_stats_en); @@ -1979,6 +2050,7 @@ dp_tx_send_msdu_single(struct dp_vdev *vdev, qdf_nbuf_t nbuf, tx_desc->dma_addr = qdf_nbuf_mapped_paddr_get(tx_desc->nbuf); dp_tx_desc_history_add(soc, tx_desc->dma_addr, nbuf, tx_desc->id, DP_TX_DESC_MAP); + dp_tx_update_mcast_param(peer_id, &htt_tcl_metadata, vdev, msdu_info); /* Enqueue the Tx MSDU descriptor to HW for transmit */ status = soc->arch_ops.tx_hw_enqueue(soc, vdev, tx_desc, htt_tcl_metadata, @@ -2177,7 +2249,7 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf, htt_tcl_metadata = vdev->htt_tcl_metadata; if (msdu_info->exception_fw) { - HTT_TX_TCL_METADATA_VALID_HTT_SET(htt_tcl_metadata, 1); + DP_TX_TCL_METADATA_VALID_HTT_SET(htt_tcl_metadata, 1); } /* @@ -2204,6 +2276,10 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf, } } + dp_tx_update_mcast_param(DP_INVALID_PEER, + &htt_tcl_metadata, + vdev, + msdu_info); /* * Enqueue the Tx MSDU descriptor to HW for transmit */ @@ -3226,6 +3302,7 @@ int dp_tx_proxy_arp(struct dp_vdev *vdev, qdf_nbuf_t nbuf) * @vdev: datapath vdev handle * @tx_desc: software descriptor head pointer * @status : Tx completion status from HTT descriptor + * @reinject_reason : reinject reason from HTT descriptor * * This function reinjects frames back to Target. * Todo - Host queue needs to be added @@ -3236,7 +3313,8 @@ static void dp_tx_reinject_handler(struct dp_soc *soc, struct dp_vdev *vdev, struct dp_tx_desc_s *tx_desc, - uint8_t *status) + uint8_t *status, + uint8_t reinject_reason) { struct dp_peer *peer = NULL; uint32_t peer_id = HTT_INVALID_PEER; @@ -3252,15 +3330,23 @@ void dp_tx_reinject_handler(struct dp_soc *soc, qdf_assert(vdev); - qdf_mem_zero(&msdu_info, sizeof(msdu_info)); - - dp_tx_get_queue(vdev, nbuf, &msdu_info.tx_queue); - dp_tx_debug("Tx reinject path"); DP_STATS_INC_PKT(vdev, tx_i.reinject_pkts, 1, qdf_nbuf_len(tx_desc->nbuf)); +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP) +#ifdef WLAN_MCAST_MLO + if (reinject_reason == HTT_TX_FW2WBM_REINJECT_REASON_MLO_MCAST) { + if (soc->arch_ops.dp_tx_mcast_handler) + soc->arch_ops.dp_tx_mcast_handler(soc, vdev, nbuf); + + dp_tx_desc_release(tx_desc, tx_desc->pool_id); + return; + } +#endif +#endif + #ifdef WDS_VENDOR_EXTENSION if (qdf_unlikely(vdev->tx_encap_type != htt_cmn_pkt_type_raw)) { is_mcast = (IS_MULTICAST(wh->i_addr1)) ? 1 : 0; @@ -3318,6 +3404,9 @@ void dp_tx_reinject_handler(struct dp_soc *soc, dp_tx_debug("nbuf copy failed"); break; } + qdf_mem_zero(&msdu_info, sizeof(msdu_info)); + dp_tx_get_queue(vdev, nbuf, + &msdu_info.tx_queue); nbuf_copy = dp_tx_send_msdu_single(vdev, nbuf_copy, @@ -4498,7 +4587,13 @@ void dp_tx_process_htt_completion(struct dp_soc *soc, } case HTT_TX_FW2WBM_TX_STATUS_REINJECT: { - dp_tx_reinject_handler(soc, vdev, tx_desc, status); + uint8_t reinject_reason; + + reinject_reason = + HTT_TX_WBM_COMPLETION_V2_REINJECT_REASON_GET( + htt_desc[0]); + dp_tx_reinject_handler(soc, vdev, tx_desc, + status, reinject_reason); break; } case HTT_TX_FW2WBM_TX_STATUS_INSPECT: @@ -4843,21 +4938,21 @@ QDF_STATUS dp_tx_vdev_attach(struct dp_vdev *vdev) /* * Fill HTT TCL Metadata with Vdev ID and MAC ID */ - HTT_TX_TCL_METADATA_TYPE_SET(vdev->htt_tcl_metadata, - HTT_TCL_METADATA_TYPE_VDEV_BASED); + DP_TX_TCL_METADATA_TYPE_SET(vdev->htt_tcl_metadata, + DP_TCL_METADATA_TYPE_VDEV_BASED); - HTT_TX_TCL_METADATA_VDEV_ID_SET(vdev->htt_tcl_metadata, - vdev->vdev_id); + DP_TX_TCL_METADATA_VDEV_ID_SET(vdev->htt_tcl_metadata, + vdev->vdev_id); pdev_id = dp_get_target_pdev_id_for_host_pdev_id(vdev->pdev->soc, vdev->pdev->pdev_id); - HTT_TX_TCL_METADATA_PDEV_ID_SET(vdev->htt_tcl_metadata, pdev_id); + DP_TX_TCL_METADATA_PDEV_ID_SET(vdev->htt_tcl_metadata, pdev_id); /* * Set HTT Extension Valid bit to 0 by default */ - HTT_TX_TCL_METADATA_VALID_HTT_SET(vdev->htt_tcl_metadata, 0); + DP_TX_TCL_METADATA_VALID_HTT_SET(vdev->htt_tcl_metadata, 0); dp_tx_vdev_update_search_flags(vdev); diff --git a/dp/wifi3.0/dp_tx.h b/dp/wifi3.0/dp_tx.h index 9a05e47a2c..e3631ce397 100644 --- a/dp/wifi3.0/dp_tx.h +++ b/dp/wifi3.0/dp_tx.h @@ -179,6 +179,8 @@ struct dp_tx_queue { * @exception_fw: Duplicate frame to be sent to firmware * @ppdu_cookie: 16-bit ppdu_cookie that has to be replayed back in completions * @ix_tx_sniffer: Indicates if the packet has to be sniffed + * @gsn: global sequence for reinjected mcast packets + * @vdev_id : vdev_id for reinjected mcast packets * * This structure holds the complete MSDU information needed to program the * Hardware TCL and MSDU extension descriptors for different frame types @@ -197,6 +199,12 @@ struct dp_tx_msdu_info_s { } u; uint32_t meta_data[DP_TX_MSDU_INFO_META_DATA_DWORDS]; uint16_t ppdu_cookie; +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP) +#ifdef WLAN_MCAST_MLO + uint16_t gsn; + uint8_t vdev_id; +#endif +#endif }; #ifndef QCA_HOST_MODE_WIFI_DISABLED diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 2a29e60ebb..da9c35a5e2 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -1713,6 +1713,12 @@ struct dp_arch_ops { /* MLO ops */ #ifdef WLAN_FEATURE_11BE_MLO +#ifdef WLAN_MCAST_MLO + void (*dp_tx_mcast_handler)(struct dp_soc *soc, struct dp_vdev *vdev, + qdf_nbuf_t nbuf); + bool (*dp_rx_mcast_handler)(struct dp_soc *soc, struct dp_vdev *vdev, + struct dp_peer *peer, qdf_nbuf_t nbuf); +#endif void (*mlo_peer_find_hash_detach)(struct dp_soc *soc); QDF_STATUS (*mlo_peer_find_hash_attach)(struct dp_soc *soc); void (*mlo_peer_find_hash_add)(struct dp_soc *soc, diff --git a/qdf/inc/qdf_nbuf.h b/qdf/inc/qdf_nbuf.h index baf12da9c1..5597cd43b1 100644 --- a/qdf/inc/qdf_nbuf.h +++ b/qdf/inc/qdf_nbuf.h @@ -75,6 +75,7 @@ #define QDF_NBUF_TRAC_IPV6_OFFSET 14 #define QDF_NBUF_TRAC_IPV6_HEADER_SIZE 40 #define QDF_NBUF_TRAC_ICMP_TYPE 1 +#define QDF_NBUF_TRAC_IGMP_TYPE 2 #define QDF_NBUF_TRAC_TCP_TYPE 6 #define QDF_NBUF_TRAC_TCP_FLAGS_OFFSET (47 - 34) #define QDF_NBUF_TRAC_TCP_ACK_OFFSET (42 - 34) @@ -84,6 +85,7 @@ #define QDF_NBUF_TRAC_TCP_DPORT_OFFSET (36 - 34) #define QDF_NBUF_TRAC_UDP_TYPE 17 #define QDF_NBUF_TRAC_ICMPV6_TYPE 0x3a +#define QDF_NBUF_TRAC_HOPOPTS_TYPE 0 #define QDF_NBUF_TRAC_DHCP6_SRV_PORT 547 #define QDF_NBUF_TRAC_DHCP6_CLI_PORT 546 #define QDF_NBUF_TRAC_MDNS_SRC_N_DST_PORT 5353 @@ -2886,6 +2888,34 @@ bool qdf_nbuf_is_ipv4_wapi_pkt(qdf_nbuf_t buf) return __qdf_nbuf_is_ipv4_wapi_pkt(buf); } +/** + * qdf_nbuf_is_ipv4_igmp_pkt() - check if packet is a igmp packet or not + * @buf: buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is igmp packet + */ +static inline +bool qdf_nbuf_is_ipv4_igmp_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_ipv4_igmp_pkt(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_is_ipv6_igmp_pkt() - check if packet is a igmp packet or not + * @buf: buffer + * + * This api is for ipv6 packet. + * + * Return: true if packet is igmp packet + */ +static inline +bool qdf_nbuf_is_ipv6_igmp_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_ipv6_igmp_pkt(qdf_nbuf_data(buf)); +} + /** * qdf_nbuf_is_ipv4_tdls_pkt() - check if packet is a tdls packet or not * @buf: buffer diff --git a/qdf/linux/src/i_qdf_nbuf.h b/qdf/linux/src/i_qdf_nbuf.h index ae4a9d7bce..af1556dc80 100644 --- a/qdf/linux/src/i_qdf_nbuf.h +++ b/qdf/linux/src/i_qdf_nbuf.h @@ -861,6 +861,8 @@ bool __qdf_nbuf_data_is_ipv4_dhcp_pkt(uint8_t *data); bool __qdf_nbuf_data_is_ipv6_dhcp_pkt(uint8_t *data); bool __qdf_nbuf_data_is_ipv6_mdns_pkt(uint8_t *data); bool __qdf_nbuf_data_is_ipv4_eapol_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_ipv4_igmp_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_ipv6_igmp_pkt(uint8_t *data); bool __qdf_nbuf_data_is_ipv4_arp_pkt(uint8_t *data); bool __qdf_nbuf_is_bcast_pkt(__qdf_nbuf_t nbuf); bool __qdf_nbuf_data_is_arp_req(uint8_t *data); diff --git a/qdf/linux/src/qdf_nbuf.c b/qdf/linux/src/qdf_nbuf.c index b7804c3e96..7eb44caa1e 100644 --- a/qdf/linux/src/qdf_nbuf.c +++ b/qdf/linux/src/qdf_nbuf.c @@ -1614,6 +1614,62 @@ bool __qdf_nbuf_is_ipv4_wapi_pkt(struct sk_buff *skb) } qdf_export_symbol(__qdf_nbuf_is_ipv4_wapi_pkt); +/** + * __qdf_nbuf_data_is_ipv4_igmp_pkt() - check if skb data is a igmp packet + * @data: Pointer to network data buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is igmp packet + * false otherwise. + */ +bool __qdf_nbuf_data_is_ipv4_igmp_pkt(uint8_t *data) +{ + if (__qdf_nbuf_data_is_ipv4_pkt(data)) { + uint8_t pkt_type; + + pkt_type = (uint8_t)(*(uint8_t *)(data + + QDF_NBUF_TRAC_IPV4_PROTO_TYPE_OFFSET)); + + if (pkt_type == QDF_NBUF_TRAC_IGMP_TYPE) + return true; + } + return false; +} + +qdf_export_symbol(__qdf_nbuf_data_is_ipv4_igmp_pkt); + +/** + * __qdf_nbuf_data_is_ipv6_igmp_pkt() - check if skb data is a igmp packet + * @data: Pointer to network data buffer + * + * This api is for ipv6 packet. + * + * Return: true if packet is igmp packet + * false otherwise. + */ +bool __qdf_nbuf_data_is_ipv6_igmp_pkt(uint8_t *data) +{ + if (__qdf_nbuf_data_is_ipv6_pkt(data)) { + uint8_t pkt_type; + uint8_t next_hdr; + + pkt_type = (uint8_t)(*(uint8_t *)(data + + QDF_NBUF_TRAC_IPV6_PROTO_TYPE_OFFSET)); + next_hdr = (uint8_t)(*(uint8_t *)(data + + QDF_NBUF_TRAC_IPV6_HEADER_SIZE)); + + if (pkt_type == QDF_NBUF_TRAC_ICMPV6_TYPE) + return true; + if ((pkt_type == QDF_NBUF_TRAC_HOPOPTS_TYPE) && + (next_hdr == QDF_NBUF_TRAC_HOPOPTS_TYPE)) + return true; + } + return false; +} + +qdf_export_symbol(__qdf_nbuf_data_is_ipv6_igmp_pkt); + /** * __qdf_nbuf_is_ipv4_tdls_pkt() - check if skb data is a tdls packet * @skb: Pointer to network buffer