1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243 |
- /*
- * Copyright (c) 2020 The Linux Foundation. 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 above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include "qca_multi_link.h"
- static bool is_initialized;
- qca_multi_link_parameters_t qca_multi_link_cfg;
- static inline bool is_fast_lane_radio(struct wiphy *fl_wiphy)
- {
- qdf_list_node_t *node = NULL, *next_node = NULL;
- if (!fl_wiphy) {
- return false;
- }
- if (qdf_list_empty(&qca_multi_link_cfg.fast_lane_list)) {
- return false;
- }
- qdf_list_peek_front(&qca_multi_link_cfg.fast_lane_list,
- (qdf_list_node_t **)&next_node);
- while (next_node) {
- struct qca_multi_link_list_node *fast_lane_node
- = (struct qca_multi_link_list_node *)next_node;
- if (fast_lane_node->wiphy == fl_wiphy) {
- return true;
- } else {
- node = next_node;
- next_node = NULL;
- if ((qdf_list_peek_next(&qca_multi_link_cfg.fast_lane_list, node, &next_node))
- != QDF_STATUS_SUCCESS) {
- return false;
- }
- }
- }
- return false;
- }
- static inline bool is_no_backhaul_radio(struct wiphy *no_bl_wiphy)
- {
- qdf_list_node_t *node = NULL, *next_node = NULL;
- if (!no_bl_wiphy) {
- return false;
- }
- if (qdf_list_empty(&qca_multi_link_cfg.no_backhaul_list)) {
- return false;
- }
- qdf_list_peek_front(&qca_multi_link_cfg.no_backhaul_list,
- (qdf_list_node_t **)&next_node);
- while (next_node) {
- struct qca_multi_link_list_node *no_bl_node
- = (struct qca_multi_link_list_node *)next_node;
- if (no_bl_node->wiphy == no_bl_wiphy) {
- return true;
- } else {
- node = next_node;
- next_node = NULL;
- if ((qdf_list_peek_next(&qca_multi_link_cfg.no_backhaul_list, node, &next_node))
- != QDF_STATUS_SUCCESS) {
- return false;
- }
- }
- }
- return false;
- }
- static inline bool is_other_fast_lane_radio_primary(struct wiphy *fl_wiphy)
- {
- qdf_list_node_t *next_node = NULL;
- if (!fl_wiphy) {
- return false;
- }
- if (qdf_list_empty(&qca_multi_link_cfg.fast_lane_list)) {
- return false;
- }
- qdf_list_peek_front(&qca_multi_link_cfg.fast_lane_list,
- (qdf_list_node_t **)&next_node);
- while (next_node) {
- struct qca_multi_link_list_node *fast_lane_node
- = (struct qca_multi_link_list_node *)next_node;
- if ((fast_lane_node->wiphy != fl_wiphy)
- && (fast_lane_node->wiphy == qca_multi_link_cfg.primary_wiphy)) {
- return true;
- }
- }
- return false;
- }
- /**
- * qca_multi_link_is_primary_radio() - Check if this is a primary radio
- *
- * Return: true: if it primary radio
- * false: if it is secondary radio
- */
- static inline bool qca_multi_link_is_primary_radio(struct wiphy *dev_wiphy)
- {
- bool is_primary = false;
- if (!qca_multi_link_cfg.primary_wiphy || !dev_wiphy) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
- FL("\nprimary_wiphy is NULL\n"));
- is_primary = false;
- } else {
- is_primary = (dev_wiphy == qca_multi_link_cfg.primary_wiphy)?true:false;
- }
- if ((is_primary == false) && is_fast_lane_radio(dev_wiphy)) {
- is_primary = is_other_fast_lane_radio_primary(dev_wiphy);
- }
- return is_primary;
- }
- /**
- * qca_multi_link_need_procesing() - Check if repeater processing is required
- *
- * Return: true: processing is required
- * false: processing is not required
- */
- static inline bool qca_multi_link_need_procesing(void)
- {
- if ((!qca_multi_link_cfg.rptr_processing_enable)
- || (qca_multi_link_cfg.total_stavaps_up < 2)) {
- return false;
- }
- return true;
- }
- /**
- * qca_multi_link_pktfrom_ownsrc() - Check if packet is from same device
- *
- * Return: true: packet is from same device
- * false: packet is not from same device
- */
- static inline bool qca_multi_link_pktfrom_ownsrc(struct net_device *net_dev, qdf_nbuf_t nbuf)
- {
- qdf_ether_header_t *eh = (qdf_ether_header_t *) qdf_nbuf_data(nbuf);
- if (qdf_is_macaddr_equal((struct qdf_mac_addr *)net_dev->dev_addr,
- (struct qdf_mac_addr *)eh->ether_shost)) {
- return true;
- }
- return false;
- }
- /**
- * qca_multi_link_drop_secondary_mcast() - Check if mcast to be dropped on secondary
- *
- * Return: true: Drop the packet
- * false: Do not drop
- */
- static inline bool qca_multi_link_drop_secondary_mcast(qdf_nbuf_t nbuf)
- {
- qdf_ether_header_t *eh = (qdf_ether_header_t *) qdf_nbuf_data(nbuf);
- uint8_t is_mcast = IEEE80211_IS_MULTICAST(eh->ether_dhost);
- if (is_mcast && qca_multi_link_cfg.drop_secondary_mcast) {
- return true;
- }
- return false;
- }
- /**
- * qca_multi_link_drop_always_primary() - Check if packet to be dropped for always_primary
- *
- * Return: true: Drop the packet
- * false: Do not drop
- */
- static inline bool qca_multi_link_drop_always_primary(bool is_primary, qdf_nbuf_t nbuf)
- {
- qdf_ether_header_t *eh = (qdf_ether_header_t *) qdf_nbuf_data(nbuf);
- if (qca_multi_link_cfg.always_primary) {
- if (is_primary) {
- return false;
- } else {
- if (eh->ether_type != qdf_htons(ETHERTYPE_PAE)) {
- return true;
- }
- }
- }
- return false;
- }
- /**
- * qca_multi_link_deinit_module() - De-initialize the repeater base structute
- * Return: void
- */
- void qca_multi_link_deinit_module(void)
- {
- if (!is_initialized)
- return;
- qca_multi_link_cfg.total_stavaps_up = 0;
- qca_multi_link_cfg.loop_detected = 0;
- qca_multi_link_cfg.primary_wiphy = NULL;
- qdf_list_destroy(&qca_multi_link_cfg.fast_lane_list);
- qdf_list_destroy(&qca_multi_link_cfg.no_backhaul_list);
- is_initialized = false;
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO,
- FL("\n******QCA RPtr De-Init Done***********\n"));
- }
- qdf_export_symbol(qca_multi_link_deinit_module);
- /**
- * qca_multi_link_init_module() - Initialize the repeater base structute
- *
- * Return: void
- */
- void qca_multi_link_init_module(void)
- {
- if (is_initialized)
- return;
- is_initialized = true;
- qca_multi_link_cfg.total_stavaps_up = 0;
- qca_multi_link_cfg.loop_detected = 0;
- qca_multi_link_cfg.primary_wiphy = NULL;
- qdf_list_create(&qca_multi_link_cfg.fast_lane_list, QCA_MULTI_LINK_FAST_LANE_LIST_SIZE);
- qdf_list_create(&qca_multi_link_cfg.no_backhaul_list, QCA_MULTI_LINK_NO_BACKHAUL_LIST_SIZE);
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO,
- FL("\n******QCA Repeater Initialization Done***********\n"));
- }
- qdf_export_symbol(qca_multi_link_init_module);
- /**
- * qca_multi_link_get_num_sta() - Get the total number of sta vaps up.
- *
- * Return: int
- */
- uint8_t qca_multi_link_get_num_sta(void)
- {
- return qca_multi_link_cfg.total_stavaps_up;
- }
- qdf_export_symbol(qca_multi_link_get_num_sta);
- /**
- * qca_multi_link_append_num_sta() - Append the total number of sta vaps up.
- * @inc_or_dec: true to increment and false to decrement
- *
- * Return: void
- */
- void qca_multi_link_append_num_sta(bool inc_or_dec)
- {
- if (inc_or_dec) {
- qca_multi_link_cfg.total_stavaps_up++;
- if (qca_multi_link_cfg.total_stavaps_up > 1) {
- qca_multi_link_set_drop_sec_mcast(true);
- }
- } else {
- if (qca_multi_link_cfg.total_stavaps_up == 0) {
- return;
- }
- qca_multi_link_cfg.total_stavaps_up--;
- if (qca_multi_link_cfg.total_stavaps_up <= 1) {
- qca_multi_link_cfg.loop_detected = 0;
- }
- }
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_NONE,
- FL("\nStation vap number in Repeater is val=%d***********\n"),
- qca_multi_link_cfg.total_stavaps_up);
- }
- qdf_export_symbol(qca_multi_link_append_num_sta);
- /**
- * qca_multi_link_is_dbdc_processing_reqd() - Check if dbdc processing is required
- * @net_dev: current net device
- *
- * Return: true: loop is detected
- * false: loop not detected
- */
- bool qca_multi_link_is_dbdc_processing_reqd(struct net_device *net_dev)
- {
- if (qca_multi_link_cfg.total_stavaps_up > 2)
- return (qca_multi_link_cfg.loop_detected && qca_multi_link_cfg.rptr_processing_enable);
- else
- return false;
- }
- qdf_export_symbol(qca_multi_link_is_dbdc_processing_reqd);
- /**
- * qca_multi_link_set_drop_sec_mcast() - set the drop secondary mcast flag
- * @val: boolean true or false
- *
- */
- void qca_multi_link_set_drop_sec_mcast(bool val)
- {
- qca_multi_link_cfg.drop_secondary_mcast = val;
- }
- qdf_export_symbol(qca_multi_link_set_drop_sec_mcast);
- /**
- * qca_multi_link_set_force_client_mcast() - set the flag to force client mcast traffic
- * @val: boolean true or false
- *
- */
- void qca_multi_link_set_force_client_mcast(bool val)
- {
- qca_multi_link_cfg.force_client_mcast_traffic = val;
- }
- qdf_export_symbol(qca_multi_link_set_force_client_mcast);
- /**
- * qca_multi_link_set_always_primary() - set the flag for always primary flag
- * @val: boolean true or false
- *
- */
- void qca_multi_link_set_always_primary(bool val)
- {
- qca_multi_link_cfg.always_primary = val;
- }
- qdf_export_symbol(qca_multi_link_set_always_primary);
- /**
- * qca_multi_link_set_dbdc_enable() - set the dbdc enable flag
- * @val: boolean true or false
- */
- void qca_multi_link_set_dbdc_enable(bool val)
- {
- qca_multi_link_cfg.rptr_processing_enable = val;
- if (!val) {
- qca_multi_link_cfg.loop_detected = 0;
- }
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
- FL("\nSetting DBDC enable = val%d\n"), val);
- }
- qdf_export_symbol(qca_multi_link_set_dbdc_enable);
- /**
- * qca_multi_link_get_primary_radio() - set the dbdc enable flag
- * @primary_wiphy: wiphy pointer of primary radio device
- */
- struct wiphy *qca_multi_link_get_primary_radio(void)
- {
- return qca_multi_link_cfg.primary_wiphy;
- }
- qdf_export_symbol(qca_multi_link_get_primary_radio);
- /**
- * qca_multi_link_set_primary_radio() - set the primary radio
- * @primary_wiphy: wiphy pointer of primary radio device
- */
- void qca_multi_link_set_primary_radio(struct wiphy *primary_wiphy)
- {
- if (!primary_wiphy) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
- FL("\nNull wiphy in Setting primary radio\n"));
- return;
- }
- qca_multi_link_cfg.primary_wiphy = primary_wiphy;
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO,
- FL("\nSetting primary radio for wiphy%p\n"), primary_wiphy);
- }
- qdf_export_symbol(qca_multi_link_set_primary_radio);
- /**
- * qca_multi_link_add_fastlane_radio() - add the fast lane radio pointer to list
- * @primary_wiphy: wiphy pointer of fast-lane radio device
- *
- * Return: false: addition not successful
- * true: addition is successful
- */
- bool qca_multi_link_add_fastlane_radio(struct wiphy *fl_wiphy)
- {
- struct qca_multi_link_list_node *fast_lane_node;
- if (!fl_wiphy) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_WARN,
- FL(" Fast lane radio could not be set - wiphy is NULL\n"));
- return false;
- }
- fast_lane_node = qdf_mem_malloc(sizeof(struct qca_multi_link_list_node));
- if (!fast_lane_node) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
- FL("Could not allocate fast-lane node for wiphy%p\n"), fl_wiphy);
- return false;
- }
- fast_lane_node->wiphy = fl_wiphy;
- if (qdf_list_insert_front(&qca_multi_link_cfg.fast_lane_list, &fast_lane_node->node)
- == QDF_STATUS_SUCCESS) {
- return true;
- }
- return false;
- }
- qdf_export_symbol(qca_multi_link_add_fastlane_radio);
- /**
- * qca_multi_link_remove_fastlane_radio() - remove the fast lane radio pointer from list
- * @primary_wiphy: wiphy pointer of fast-lane radio device
- *
- * Return: false: addition not successful
- * true: addition is successful
- */
- bool qca_multi_link_remove_fastlane_radio(struct wiphy *fl_wiphy)
- {
- qdf_list_node_t *node = NULL, *next_node = NULL;
- if (!fl_wiphy) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_WARN,
- FL(" Fast lane radio could not be removed - wiphy is NULL\n"));
- return false;
- }
- qdf_list_peek_front(&qca_multi_link_cfg.fast_lane_list,
- (qdf_list_node_t **)&next_node);
- while (next_node) {
- struct qca_multi_link_list_node *fast_lane_node
- = (struct qca_multi_link_list_node *)next_node;
- if (fast_lane_node->wiphy == fl_wiphy) {
- qdf_list_remove_node(&qca_multi_link_cfg.fast_lane_list, next_node);
- qdf_mem_free(fast_lane_node);
- return true;
- } else {
- node = next_node;
- next_node = NULL;
- if ((qdf_list_peek_next(&qca_multi_link_cfg.fast_lane_list, node,
- (qdf_list_node_t **)&next_node)) != QDF_STATUS_SUCCESS) {
- return false;
- }
- }
- }
- return false;
- }
- qdf_export_symbol(qca_multi_link_remove_fastlane_radio);
- /**
- * qca_multi_link_add_no_backhaul_radio() - add the no backhaul radio pointer to list
- * @primary_wiphy: wiphy pointer of fast-lane radio device
- *
- * Return: false: addition not successful
- * true: addition is successful
- */
- bool qca_multi_link_add_no_backhaul_radio(struct wiphy *no_bl_wiphy)
- {
- struct qca_multi_link_list_node *no_bl_node;
- if (!no_bl_wiphy) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_WARN,
- FL(" No backhaul radio could not be set - wiphy is NULL\n"));
- return false;
- }
- no_bl_node = qdf_mem_malloc(sizeof(struct qca_multi_link_list_node));
- if (!no_bl_node) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
- FL("Could not allocate back-haul node for wiphy%p\n"), no_bl_node);
- return false;
- }
- no_bl_node->wiphy = no_bl_wiphy;
- if (qdf_list_insert_front(&qca_multi_link_cfg.no_backhaul_list, &no_bl_node->node)
- == QDF_STATUS_SUCCESS) {
- return true;
- }
- return false;
- }
- qdf_export_symbol(qca_multi_link_add_no_backhaul_radio);
- /**
- * qca_multi_link_remove_no_backhaul_radio() - remove no-backhaul radio pointer from list
- * @primary_wiphy: wiphy pointer of no-backhaul radio device
- *
- * Return: false: addition not successful
- * true: addition is successful
- */
- bool qca_multi_link_remove_no_backhaul_radio(struct wiphy *no_bl_wiphy)
- {
- qdf_list_node_t *node = NULL, *next_node = NULL;
- if (!no_bl_wiphy) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_WARN,
- FL(" No backhaul radio could not be removed - wiphy is NULL\n"));
- return false;
- }
- qdf_list_peek_front(&qca_multi_link_cfg.no_backhaul_list,
- (qdf_list_node_t **)&next_node);
- while (next_node) {
- struct qca_multi_link_list_node *no_bl_node
- = (struct qca_multi_link_list_node *)next_node;
- if (no_bl_node->wiphy == no_bl_wiphy) {
- qdf_list_remove_node(&qca_multi_link_cfg.no_backhaul_list, next_node);
- qdf_mem_free(no_bl_node);
- return true;
- } else {
- node = next_node;
- next_node = NULL;
- if ((qdf_list_peek_next(&qca_multi_link_cfg.no_backhaul_list, node, &next_node))
- != QDF_STATUS_SUCCESS) {
- return false;
- }
- }
- }
- return false;
- }
- qdf_export_symbol(qca_multi_link_remove_no_backhaul_radio);
- /**
- * qca_multi_link_secondary_ap_rx() - Processing for frames recieved on Secondary AP VAP
- * @net_device: net device handle
- * @nbuf: frame
- *
- * Return: qca_multi_link_status_t
- * QCA_MULTI_LINK_PKT_ALLOW: frame should be processed further by caller.
- * QCA_MULTI_LINK_PKT_DROP: frame to be dropped.
- * QCA_MULTI_LINK_PKT_CONSUMED: frame is consumed.
- */
- static qca_multi_link_status_t qca_multi_link_secondary_ap_rx(struct net_device *ap_dev, qdf_nbuf_t nbuf)
- {
- struct wiphy *ap_wiphy = NULL;
- struct net_device *sta_dev = NULL;
- qca_multi_link_tbl_entry_t qca_ml_entry;
- QDF_STATUS qal_status = QDF_STATUS_E_FAILURE;
- bool enqueue_to_sta_vap = false;
- qdf_ether_header_t *eh = (qdf_ether_header_t *) qdf_nbuf_data(nbuf);
- ap_wiphy = ap_dev->ieee80211_ptr->wiphy;
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, FL("Secondary AP Rx: always_primary=%d, loop_detected=%d,\
- drop_secondary_mcast=%d, shost %pM dhost %pM\n"),
- qca_multi_link_cfg.always_primary, qca_multi_link_cfg.loop_detected,
- qca_multi_link_cfg.drop_secondary_mcast, eh->ether_shost, eh->ether_dhost);
- /*
- *If the AP is on a fast lane radio, always give the packet to bridge.
- */
- if (is_fast_lane_radio(ap_wiphy)) {
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- qca_ml_entry.qal_fdb_ieee80211_ptr = NULL;
- qca_ml_entry.qal_fdb_dev = NULL;
- qca_ml_entry.qal_fdb_is_local = 0;
- qal_status = qca_multi_link_tbl_has_entry(ap_dev, eh->ether_dhost, 0,
- &qca_ml_entry);
- if (qal_status == QDF_STATUS_SUCCESS) {
- /*
- * Check the FDB entry type, if the mac-address is learnt on a port which is
- * of type station, then it is a source on the RootAP side and enqueue the
- * packet to the corresponding station vap. Else give the packet to bridge.
- */
- if (qca_ml_entry.qal_fdb_ieee80211_ptr
- && (qca_ml_entry.qal_fdb_ieee80211_ptr->iftype == NL80211_IFTYPE_STATION)) {
- enqueue_to_sta_vap = true;
- }
- } else {
- /*
- * If there is no fdb entry, then also the destination might be on the RootAP side,
- * enqueue the packet to the corresponding station vap.
- */
- enqueue_to_sta_vap = true;
- }
- if (enqueue_to_sta_vap) {
- /*
- * Find the station vap corresponding to the AP vap.
- */
- sta_dev = qca_multi_link_tbl_find_sta_or_ap(ap_dev, 1);
- if (!sta_dev) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
- FL("Null STA device found %pM - Give to bridge\n"), eh->ether_shost);
- return QCA_MULTI_LINK_PKT_DROP;
- }
- dev_hold(sta_dev);
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
- FL("shost %pM dhost %pM \n"), eh->ether_shost, eh->ether_dhost);
- /*
- * For packets destined to sources on RootAP directly enq to STA vap.
- */
- sta_dev->netdev_ops->ndo_start_xmit(nbuf, sta_dev);
- dev_put(sta_dev);
- return QCA_MULTI_LINK_PKT_CONSUMED;
- }
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- /**
- * qca_multi_link_ap_rx() - Processing for frames recieved on AP VAP
- * @net_device: net device handle
- * @nbuf: frame
- *
- * Return: false: frame not consumed and should be processed further by caller
- * true: frame consumed
- */
- bool qca_multi_link_ap_rx(struct net_device *net_dev, qdf_nbuf_t nbuf)
- {
- uint8_t is_mcast;
- uint8_t is_eapol;
- struct net_device *ap_dev = net_dev;
- qca_multi_link_status_t status = QCA_MULTI_LINK_PKT_NONE;
- struct wiphy *ap_wiphy = NULL;
- bool drop_packet = false;
- bool is_primary = false;
- qdf_ether_header_t *eh = (qdf_ether_header_t *) qdf_nbuf_data(nbuf);
- if (!qca_multi_link_need_procesing()) {
- goto end;
- }
- if (!qca_multi_link_cfg.loop_detected) {
- goto end;
- }
- /*
- * If it is mcast/broadcast frame, AST search cannot be done, so give
- * the frame up the stack
- * If it is EAPOL frame, just give the frame up the stack
- */
- is_mcast = IEEE80211_IS_MULTICAST(eh->ether_dhost);
- is_eapol = (eh->ether_type == htons(ETHERTYPE_PAE));
- if (is_mcast || is_eapol) {
- goto end;
- }
- ap_wiphy = ap_dev->ieee80211_ptr->wiphy;
- is_primary = qca_multi_link_is_primary_radio(ap_wiphy);
- if (is_primary) {
- goto end;
- } else {
- dev_hold(ap_dev);
- status = qca_multi_link_secondary_ap_rx(ap_dev, nbuf);
- dev_put(ap_dev);
- }
- if (status == QCA_MULTI_LINK_PKT_ALLOW) {
- goto end;
- } else if (status == QCA_MULTI_LINK_PKT_CONSUMED) {
- return true;
- } else if (status == QCA_MULTI_LINK_PKT_DROP) {
- drop_packet = true;
- }
- end:
- if (drop_packet) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
- FL("\n STA TX - Drop Packet for Mac=%pM\n"), eh->ether_shost);
- qdf_nbuf_free(nbuf);
- return true;
- }
- return false;
- }
- qdf_export_symbol(qca_multi_link_ap_rx);
- /**
- * qca_multi_link_secondary_sta_rx() - Processing for frames recieved on secondary station vap
- * @net_dev: station net device
- * @nbuf: frame
- *
- * Return: @qca_multi_link_status_t
- * QCA_MULTI_LINK_PKT_ALLOW: frame should be processed further by caller
- * QCA_MULTI_LINK_PKT_DROP: frame to be dropped.
- * QCA_MULTI_LINK_PKT_CONSUMED: frame is consumed.
- */
- static qca_multi_link_status_t qca_multi_link_secondary_sta_rx(struct net_device *net_dev,
- qdf_nbuf_t nbuf)
- {
- uint8_t is_mcast;
- qca_multi_link_tbl_entry_t qca_ml_entry;
- struct wiphy *sta_wiphy = NULL;
- struct net_device *sta_dev = net_dev;
- struct net_device *ap_dev = NULL;
- QDF_STATUS qal_status = QDF_STATUS_E_FAILURE;
- qdf_ether_header_t *eh = (qdf_ether_header_t *) qdf_nbuf_data(nbuf);
- sta_wiphy = sta_dev->ieee80211_ptr->wiphy;
- is_mcast = IEEE80211_IS_MULTICAST(eh->ether_dhost);
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, FL("Secondary STA Rx:always_primary=%d, loop_detected=%d,\
- drop_secondary_mcast=%d, shost %pM dhost %pM is_mcast=%d\n"),
- qca_multi_link_cfg.always_primary, qca_multi_link_cfg.loop_detected,
- qca_multi_link_cfg.drop_secondary_mcast, eh->ether_shost, eh->ether_dhost, is_mcast);
- /*
- * Mcast packets handling.
- */
- if (is_mcast) {
- /*
- * Always drop mcast packets on secondary radio when loop has been detected.
- */
- if (qca_multi_link_cfg.loop_detected) {
- return QCA_MULTI_LINK_PKT_DROP;
- }
- qca_ml_entry.qal_fdb_ieee80211_ptr = NULL;
- qca_ml_entry.qal_fdb_dev = NULL;
- qca_ml_entry.qal_fdb_is_local = 0;
- qal_status = qca_multi_link_tbl_has_entry(sta_dev, eh->ether_shost, 0,
- &qca_ml_entry);
- if (qal_status != QDF_STATUS_SUCCESS) {
- if (!qca_multi_link_cfg.loop_detected
- && !qca_multi_link_cfg.drop_secondary_mcast) {
- /*
- * This condition is to allow packets on Secondary Station
- * when stations are connected to different RootAPs and loop is not
- * detected.
- */
- return QCA_MULTI_LINK_PKT_ALLOW;
- } else {
- return QCA_MULTI_LINK_PKT_DROP;
- }
- }
- /*
- * Case 1:
- * ieee80211_ptr pointer being NULL indicates that the port
- * corresponding to the fdb entry is a non-wireless/ethernet
- * device behind the repeater and the packet is a mcast looped packet.
- * Case 2:
- * ieee80211_ptr pointer being non NULL indicates that the source
- * corresponding to the fdb entry is a wireless device
- * behind the repeater and the packet is a mcast looped packet.
- */
- if (qca_ml_entry.qal_fdb_ieee80211_ptr && (qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy != sta_wiphy)) {
- if (!qca_multi_link_cfg.loop_detected) {
- if (qca_ml_entry.qal_fdb_is_local
- && (qca_ml_entry.qal_fdb_ieee80211_ptr->iftype == NL80211_IFTYPE_STATION)) {
- qca_multi_link_cfg.loop_detected = true;
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO, FL("\n****Wifi Rptr Loop Detected****\n"));
- }
- }
- return QCA_MULTI_LINK_PKT_DROP;
- }
- if (qca_multi_link_drop_secondary_mcast(nbuf)) {
- return QCA_MULTI_LINK_PKT_DROP;
- }
- /*
- * If the mac-address is learnt on the station in the bridge,
- * then the mcast packet is from a source on the RootAP side and we
- * should allow the packet.
- * This check on secondary will take of the case where stations are connected to different RootAPs
- * and loop is not detected.
- */
- if (qca_ml_entry.qal_fdb_dev == sta_dev) {
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- return QCA_MULTI_LINK_PKT_DROP;
- }
- /*
- * Unicast packets handling received on secondary Stations.
- */
- if (qca_multi_link_cfg.loop_detected) {
- qca_ml_entry.qal_fdb_ieee80211_ptr = NULL;
- qca_ml_entry.qal_fdb_dev = NULL;
- qca_ml_entry.qal_fdb_is_local = 0;
- qal_status = qca_multi_link_tbl_has_entry(sta_dev, eh->ether_dhost, 0,
- &qca_ml_entry);
- if (qal_status == QDF_STATUS_SUCCESS) {
- /*
- * Unicast packets destined to ethernets or bridge should never come
- * on secondary stations.
- */
- if (!qca_ml_entry.qal_fdb_ieee80211_ptr) {
- return QCA_MULTI_LINK_PKT_DROP;
- }
- /*
- * Compare the physical device and check if the destination is a client
- * on the same radio, then enqueue directly to AP vap.
- */
- if ((qca_ml_entry.qal_fdb_ieee80211_ptr->iftype == NL80211_IFTYPE_AP)
- && (qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy == sta_wiphy)) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, FL("Unicast Sec STA to AP direct enq for\
- shost %pM dhost %pM \n"), eh->ether_shost, eh->ether_dhost);
- /*
- * Holding the AP dev so that it cannot be brought down
- * while we are enqueueing.
- */
- dev_hold(qca_ml_entry.qal_fdb_dev);
- qca_ml_entry.qal_fdb_dev->netdev_ops->ndo_start_xmit(nbuf, qca_ml_entry.qal_fdb_dev);
- dev_put(qca_ml_entry.qal_fdb_dev);
- return QCA_MULTI_LINK_PKT_CONSUMED;
- }
- return QCA_MULTI_LINK_PKT_DROP;
- } else {
- /*
- * If there is no bridge fdb entry for unicast packets received on secondary
- * station, give the packet to the first found AP vap entry in the bridge table.
- */
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, FL("No Fdb entry on sec radio\
- for ucast pkt with dhost %pM \n"), eh->ether_dhost);
- /*
- * Find the AP vap corresponding to the station vap.
- */
- ap_dev = qca_multi_link_tbl_find_sta_or_ap(sta_dev, 0);
- if (!ap_dev) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
- FL("Null AP device found %pM - Give to bridge\n"), eh->ether_shost);
- return QCA_MULTI_LINK_PKT_DROP;
- }
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
- FL("shost %pM dhost %pM \n"), eh->ether_shost, eh->ether_dhost);
- /*
- * For packets destined to sources on RootAP directly enq to STA vap.
- */
- dev_hold(ap_dev);
- ap_dev->netdev_ops->ndo_start_xmit(nbuf, ap_dev);
- dev_put(ap_dev);
- return QCA_MULTI_LINK_PKT_CONSUMED;
- }
- }
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- /**
- * qca_multi_link_primary_sta_rx() - Processing for frames recieved on primary station vap
- * @net_dev: station net device
- * @nbuf: frame
- *
- * Return: @qca_multi_link_status_t
- * QCA_MULTI_LINK_PKT_ALLOW: frame should be processed further by caller
- * QCA_MULTI_LINK_PKT_DROP: frame to be dropped
- * QCA_MULTI_LINK_PKT_CONSUMED: frame is consumed.
- */
- static qca_multi_link_status_t qca_multi_link_primary_sta_rx(struct net_device *net_dev, qdf_nbuf_t nbuf)
- {
- uint8_t is_mcast;
- qca_multi_link_tbl_entry_t qca_ml_entry;
- struct wiphy *sta_wiphy = NULL;
- struct net_device *sta_dev = net_dev;
- QDF_STATUS qal_status = QDF_STATUS_E_FAILURE;
- qdf_ether_header_t *eh = (qdf_ether_header_t *) qdf_nbuf_data(nbuf);
- sta_wiphy = sta_dev->ieee80211_ptr->wiphy;
- is_mcast = IEEE80211_IS_MULTICAST(eh->ether_dhost);
- /*
- * Unicast Packets are allowed without any processing on Primary Station Vap.
- */
- if (!is_mcast) {
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, FL("Primary STA Rx: always_primary=%d, loop_detected=%d,\
- drop_secondary_mcast=%d, shost %pM dhost %pM is_mcast=%d\n"),
- qca_multi_link_cfg.always_primary, qca_multi_link_cfg.loop_detected,
- qca_multi_link_cfg.drop_secondary_mcast, eh->ether_shost, eh->ether_dhost, is_mcast);
- /*
- * Mcast packet handling on Primary Station Vap Interface.
- */
- qca_ml_entry.qal_fdb_ieee80211_ptr = NULL;
- qca_ml_entry.qal_fdb_dev = NULL;
- qca_ml_entry.qal_fdb_is_local = 0;
- qal_status = qca_multi_link_tbl_has_entry(sta_dev, eh->ether_shost, 0,
- &qca_ml_entry);
- if (qal_status != QDF_STATUS_SUCCESS) {
- if (qca_multi_link_cfg.loop_detected) {
- /*
- * If there is no fdb entry, the we allow the packet to go to
- * bridge as this might be the first packet from any device
- * on the RootAP side.
- */
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- return QCA_MULTI_LINK_PKT_DROP;
- }
- /*
- * Case 1:
- * ieee80211_ptr pointer being NULL indicates that the port
- * corresponding to the fdb entry is a non-wireless/ethernet
- * device behind the repeater and the packet is a mcast looped packet.
- * Case 2:
- * ieee80211_ptr pointer being non NULL indicates that the source
- * corresponding to the fdb entry is a wireless device
- * behind the repeater and the packet is a mcast looped packet.
- */
- /*
- * Drop the loopback mcast packets from ethernet devices behind the repeater.
- */
- if (!qca_ml_entry.qal_fdb_ieee80211_ptr) {
- return QCA_MULTI_LINK_PKT_DROP;
- }
- if (qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy != sta_wiphy) {
- if (!qca_multi_link_cfg.loop_detected) {
- if (qca_ml_entry.qal_fdb_is_local
- && (qca_ml_entry.qal_fdb_ieee80211_ptr->iftype == NL80211_IFTYPE_STATION)) {
- qca_multi_link_cfg.loop_detected = true;
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_INFO,
- FL("\n****Wifi Rptr Loop Detected****\n"));
- }
- }
- return QCA_MULTI_LINK_PKT_DROP;
- }
- /*
- * If the mac-address is learnt on the Primary station in the bridge,
- * then the mcast packet is from a source on the RootAP side and we
- * should allow the packet.
- */
- if (qca_ml_entry.qal_fdb_dev == sta_dev) {
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- return QCA_MULTI_LINK_PKT_DROP;
- }
- /**
- * qca_multi_link_sta_rx() - Processing for frames recieved on STA VAP
- * @net_dev: station net device
- * @nbuf: frame
- *
- * Return: false: frame not consumed and should be processed further by caller
- * true: frame dropped/enqueued.
- */
- bool qca_multi_link_sta_rx(struct net_device *net_dev, qdf_nbuf_t nbuf)
- {
- uint8_t is_eapol;
- bool is_primary = false;
- struct wiphy *sta_wiphy = NULL;
- struct net_device *sta_dev = net_dev;
- qdf_ether_header_t *eh = (qdf_ether_header_t *) qdf_nbuf_data(nbuf);
- bool drop_packet = false;
- qca_multi_link_status_t status = QCA_MULTI_LINK_PKT_NONE;
- if (!qca_multi_link_need_procesing()) {
- goto end;
- }
- is_eapol = (eh->ether_type == htons(ETHERTYPE_PAE));
- if (is_eapol) {
- goto end;
- }
- sta_wiphy = sta_dev->ieee80211_ptr->wiphy;
- is_primary = qca_multi_link_is_primary_radio(sta_wiphy);
- if (qca_multi_link_drop_always_primary(is_primary, nbuf)) {
- drop_packet = true;
- goto end;
- }
- dev_hold(sta_dev);
- if (is_primary) {
- status = qca_multi_link_primary_sta_rx(sta_dev, nbuf);
- } else {
- status = qca_multi_link_secondary_sta_rx(sta_dev, nbuf);
- }
- dev_put(sta_dev);
- if (status == QCA_MULTI_LINK_PKT_ALLOW) {
- goto end;
- } else if (status == QCA_MULTI_LINK_PKT_CONSUMED) {
- return true;
- } else if (status == QCA_MULTI_LINK_PKT_DROP) {
- drop_packet = true;
- }
- end:
- if (drop_packet) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
- FL("\n STA TX - Drop Packet for Mac=%pM\n"), eh->ether_shost);
- qdf_nbuf_free(nbuf);
- return true;
- }
- return false;
- }
- qdf_export_symbol(qca_multi_link_sta_rx);
- /**
- * qca_multi_link_secondary_sta_tx() - Repeater TX processing for Secondary
- * @net_device: station net device handle
- * @nbuf: frame
- *
- * Return: @qca_multi_link_status_t
- * QCA_MULTI_LINK_PKT_ALLOW: frame should be processed further by caller
- * QCA_MULTI_LINK_PKT_DROP: frame to be dropped
- * QCA_MULTI_LINK_PKT_CONSUMED: frame is consumed.
- */
- static qca_multi_link_status_t qca_multi_link_secondary_sta_tx(struct net_device *net_dev, qdf_nbuf_t nbuf)
- {
- uint8_t is_mcast;
- struct wiphy *sta_wiphy = NULL;
- struct net_device *sta_dev = net_dev;
- qca_multi_link_tbl_entry_t qca_ml_entry;
- QDF_STATUS qal_status = QDF_STATUS_E_FAILURE;
- qdf_ether_header_t *eh = (qdf_ether_header_t *) qdf_nbuf_data(nbuf);
- if (qca_multi_link_drop_always_primary(false, nbuf)) {
- return QCA_MULTI_LINK_PKT_DROP;
- }
- sta_wiphy = sta_dev->ieee80211_ptr->wiphy;
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, FL("STA Secondary Tx: always_primary=%d, loop_detected=%d,\
- drop_secondary_mcast=%d, shost %pM dhost %pM \n"),
- qca_multi_link_cfg.always_primary, qca_multi_link_cfg.loop_detected, qca_multi_link_cfg.drop_secondary_mcast,
- eh->ether_shost, eh->ether_dhost);
- /*
- * For a Secondary station, only Packets from clients on the same band are allowed for transmit.
- */
- is_mcast = IEEE80211_IS_MULTICAST(eh->ether_dhost);
- qca_ml_entry.qal_fdb_ieee80211_ptr = NULL;
- qca_ml_entry.qal_fdb_dev = NULL;
- qca_ml_entry.qal_fdb_is_local = 0;
- qal_status = qca_multi_link_tbl_has_entry(sta_dev, eh->ether_shost, 0,
- &qca_ml_entry);
- if (qal_status != QDF_STATUS_SUCCESS) {
- if (!is_mcast) {
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- return QCA_MULTI_LINK_PKT_DROP;
- }
- if (!qca_ml_entry.qal_fdb_ieee80211_ptr) {
- /*
- * ieee80211_ptr pointer will be NULL for ethernet devices.
- * Packets from ethernet devices or bridge are allowed only on Primary radio.
- */
- return QCA_MULTI_LINK_PKT_DROP;
- }
- /*
- * Do the DBDC Fast Lane processing at the beginning and then fall back to normal DBDC STA TX
- * if either fast-lane is disabled or the TX is for non-fast lane radio.
- */
- if (is_fast_lane_radio(sta_wiphy) && is_fast_lane_radio(qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy)) {
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- if (qca_multi_link_drop_secondary_mcast(nbuf)) {
- return QCA_MULTI_LINK_PKT_DROP;
- }
- /*
- * Compare the physical device and check if the source is a client
- * on the same radio.
- */
- if (qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy != sta_dev->ieee80211_ptr->wiphy) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, FL("STA TX: Diff Band Primary drop\
- shost %pM dhost %pM \n"), eh->ether_shost, eh->ether_dhost);
- return QCA_MULTI_LINK_PKT_DROP;
- }
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- /**
- * qca_multi_link_primary_sta_tx() - Repeater TX processing for Primary
- * @net_device: station net device handle
- * @nbuf: frame
- *
- * Return: @qca_multi_link_status_t
- * QCA_MULTI_LINK_PKT_ALLOW: frame should be processed further by caller
- * QCA_MULTI_LINK_PKT_DROP: frame to be dropped
- * QCA_MULTI_LINK_PKT_CONSUMED: frame is consumed.
- */
- static qca_multi_link_status_t qca_multi_link_primary_sta_tx(struct net_device *net_dev, qdf_nbuf_t nbuf)
- {
- struct wiphy *sta_wiphy = NULL;
- struct net_device *sta_dev = net_dev;
- qca_multi_link_tbl_entry_t qca_ml_entry;
- QDF_STATUS qal_status = QDF_STATUS_E_FAILURE;
- qdf_ether_header_t *eh = (qdf_ether_header_t *) qdf_nbuf_data(nbuf);
- sta_wiphy = sta_dev->ieee80211_ptr->wiphy;
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, FL("Primary STA Tx: always_primary=%d, loop_detected=%d,\
- drop_secondary_mcast=%d, shost %pM dhost %pM \n"),
- qca_multi_link_cfg.always_primary, qca_multi_link_cfg.loop_detected,
- qca_multi_link_cfg.drop_secondary_mcast, eh->ether_shost, eh->ether_dhost);
- /*
- * For Primary station, packets allowed for transmission are:
- * 1) Packets from ethernet devices.
- * 2) Packets from radios which are not participating in backhaul.
- * 3) Packets from clients on the same band.
- */
- qca_ml_entry.qal_fdb_ieee80211_ptr = NULL;
- qca_ml_entry.qal_fdb_dev = NULL;
- qca_ml_entry.qal_fdb_is_local = 0;
- qal_status = qca_multi_link_tbl_has_entry(sta_dev, eh->ether_shost, 0,
- &qca_ml_entry);
- /*
- * All packets coming to Primary station has to have a bridge fdb entry
- * as they will be received from bridge only.
- */
- if (qal_status != QDF_STATUS_SUCCESS) {
- return QCA_MULTI_LINK_PKT_DROP;
- }
- if (!qca_ml_entry.qal_fdb_ieee80211_ptr) {
- /*
- * ieee80211_ptr pointer will be NULL for ethernet devices.
- * Packets from ethernet devices or bridge are allowed only on Primary radio.
- */
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- /*
- * Do the DBDC Fast Lane processing at the beginning and then fall back to normal DBDC STA TX
- * if either fast-lane is disabled or the TX is for non-fast lane radio.
- */
- if (is_fast_lane_radio(sta_wiphy)
- && is_fast_lane_radio(qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy)) {
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- /*
- * This flag will be set for radios which does not particpate in backhaul.
- */
- if (is_no_backhaul_radio(qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy)) {
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- /*
- * Compare the physical device and check if the source is a client
- * on the same radio.
- */
- if (qca_ml_entry.qal_fdb_ieee80211_ptr->wiphy != sta_dev->ieee80211_ptr->wiphy) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG, FL("STA TX: Diff Band Primary drop\
- shost %pM dhost %pM \n"), eh->ether_shost, eh->ether_dhost);
- return QCA_MULTI_LINK_PKT_DROP;
- }
- return QCA_MULTI_LINK_PKT_ALLOW;
- }
- /**
- * qca_multi_link_sta_tx() - Repeater TX processing
- * @net_device: station net device handle
- * @nbuf: frame
- *
- * Return: false: frame not consumed and should be processed further by caller
- * true: frame consumed
- */
- bool qca_multi_link_sta_tx(struct net_device *net_dev, qdf_nbuf_t nbuf)
- {
- bool drop_packet = false;
- bool is_primary = false;
- struct wiphy *sta_wiphy = NULL;
- struct net_device *sta_dev = net_dev;
- qdf_ether_header_t *eh = (qdf_ether_header_t *) qdf_nbuf_data(nbuf);
- qca_multi_link_status_t status = QCA_MULTI_LINK_PKT_NONE;
- if (!qca_multi_link_need_procesing()) {
- goto end;
- }
- if (!qca_multi_link_cfg.loop_detected) {
- goto end;
- }
- if (qca_multi_link_pktfrom_ownsrc(sta_dev, nbuf)) {
- goto end;
- }
- sta_wiphy = sta_dev->ieee80211_ptr->wiphy;
- is_primary = qca_multi_link_is_primary_radio(sta_wiphy);
- dev_hold(net_dev);
- if (is_primary) {
- status = qca_multi_link_primary_sta_tx(sta_dev, nbuf);
- } else {
- status = qca_multi_link_secondary_sta_tx(sta_dev, nbuf);
- }
- dev_put(net_dev);
- if (status == QCA_MULTI_LINK_PKT_ALLOW) {
- goto end;
- } else if (status == QCA_MULTI_LINK_PKT_CONSUMED) {
- return true;
- } else if (status == QCA_MULTI_LINK_PKT_DROP) {
- drop_packet = true;
- }
- end:
- if (drop_packet) {
- QDF_TRACE(QDF_MODULE_ID_RPTR, QDF_TRACE_LEVEL_DEBUG,
- FL("\n STA TX - Drop Packet for Mac=%pM\n"), eh->ether_shost);
- qdf_nbuf_free(nbuf);
- return true;
- }
- return false;
- }
- qdf_export_symbol(qca_multi_link_sta_tx);
|