qcacmn: Add WDS Vendor Extension ECM Framework
Add WDS tx/rx policy checks in Tx and Rx datapaths. In Rx path, check packets against rx policy configured In Tx Reinject path, checks are to process or drop 4-addr/3-addr packets to peers decisively Change-Id: I0a6c01b7555fa5d369ab2c9baf454d49808857fc
This commit is contained in:

committed by
snandini

parent
9dee72a40c
commit
2a5fc625d2
@@ -571,6 +571,9 @@ struct cdp_wds_ops {
|
||||
void
|
||||
(*txrx_set_wds_rx_policy)(struct cdp_vdev *vdev,
|
||||
u_int32_t val);
|
||||
void
|
||||
(*txrx_wds_peer_tx_policy_update)(struct cdp_peer *peer,
|
||||
int wds_tx_ucast, int wds_tx_mcast);
|
||||
int (*vdev_set_wds)(void *vdev, uint32_t val);
|
||||
};
|
||||
|
||||
|
@@ -58,6 +58,33 @@ cdp_set_wds_rx_policy(ol_txrx_soc_handle soc,
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief set the wds rx filter policy of the device
|
||||
* @details
|
||||
* This flag sets the wds rx policy on the vdev. Rx frames not compliant
|
||||
* with the policy will be dropped.
|
||||
*
|
||||
* @param vdev - the data virtual device object
|
||||
* @param val - the wds rx policy bitmask
|
||||
* @return - void
|
||||
*/
|
||||
static inline void
|
||||
cdp_set_wds_tx_policy_update(ol_txrx_soc_handle soc,
|
||||
struct cdp_peer *peer,
|
||||
int wds_tx_ucast, int wds_tx_mcast)
|
||||
{
|
||||
if (!soc || !soc->ops || !soc->ops->wds_ops) {
|
||||
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_FATAL,
|
||||
"%s invalid instance", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (soc->ops->wds_ops->txrx_wds_peer_tx_policy_update)
|
||||
return soc->ops->wds_ops->txrx_wds_peer_tx_policy_update(
|
||||
peer, wds_tx_ucast, wds_tx_mcast);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* cdp_vdev_set_wds() - Set/unset wds_enable flag in vdev
|
||||
* @soc - data path soc handle
|
||||
|
@@ -5328,8 +5328,81 @@ QDF_STATUS dp_update_config_parameters(struct cdp_soc *psoc,
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* dp_txrx_set_wds_rx_policy() - API to store datapath
|
||||
* config parameters
|
||||
* @vdev_handle - datapath vdev handle
|
||||
* @cfg: ini parameter handle
|
||||
*
|
||||
* Return: status
|
||||
*/
|
||||
#ifdef WDS_VENDOR_EXTENSION
|
||||
void
|
||||
dp_txrx_set_wds_rx_policy(
|
||||
struct cdp_vdev *vdev_handle,
|
||||
u_int32_t val)
|
||||
{
|
||||
struct dp_vdev *vdev = (struct dp_vdev *)vdev_handle;
|
||||
struct dp_peer *peer;
|
||||
if (vdev->opmode == wlan_op_mode_ap) {
|
||||
/* for ap, set it on bss_peer */
|
||||
TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) {
|
||||
if (peer->bss_peer) {
|
||||
peer->wds_ecm.wds_rx_filter = 1;
|
||||
peer->wds_ecm.wds_rx_ucast_4addr = (val & WDS_POLICY_RX_UCAST_4ADDR) ? 1:0;
|
||||
peer->wds_ecm.wds_rx_mcast_4addr = (val & WDS_POLICY_RX_MCAST_4ADDR) ? 1:0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (vdev->opmode == wlan_op_mode_sta) {
|
||||
peer = TAILQ_FIRST(&vdev->peer_list);
|
||||
peer->wds_ecm.wds_rx_filter = 1;
|
||||
peer->wds_ecm.wds_rx_ucast_4addr = (val & WDS_POLICY_RX_UCAST_4ADDR) ? 1:0;
|
||||
peer->wds_ecm.wds_rx_mcast_4addr = (val & WDS_POLICY_RX_MCAST_4ADDR) ? 1:0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* dp_txrx_peer_wds_tx_policy_update() - API to set tx wds policy
|
||||
*
|
||||
* @peer_handle - datapath peer handle
|
||||
* @wds_tx_ucast: policy for unicast transmission
|
||||
* @wds_tx_mcast: policy for multicast transmission
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
void
|
||||
dp_txrx_peer_wds_tx_policy_update(struct cdp_peer *peer_handle,
|
||||
int wds_tx_ucast, int wds_tx_mcast)
|
||||
{
|
||||
struct dp_peer *peer = (struct dp_peer *)peer_handle;
|
||||
if (wds_tx_ucast || wds_tx_mcast) {
|
||||
peer->wds_enabled = 1;
|
||||
peer->wds_ecm.wds_tx_ucast_4addr = wds_tx_ucast;
|
||||
peer->wds_ecm.wds_tx_mcast_4addr = wds_tx_mcast;
|
||||
} else {
|
||||
peer->wds_enabled = 0;
|
||||
peer->wds_ecm.wds_tx_ucast_4addr = 0;
|
||||
peer->wds_ecm.wds_tx_mcast_4addr = 0;
|
||||
}
|
||||
|
||||
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
|
||||
FL("Policy Update set to :\
|
||||
peer->wds_enabled %d\
|
||||
peer->wds_ecm.wds_tx_ucast_4addr %d\
|
||||
peer->wds_ecm.wds_tx_mcast_4addr %d\n"),
|
||||
peer->wds_enabled, peer->wds_ecm.wds_tx_ucast_4addr,
|
||||
peer->wds_ecm.wds_tx_mcast_4addr);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct cdp_wds_ops dp_ops_wds = {
|
||||
.vdev_set_wds = dp_vdev_set_wds,
|
||||
#ifdef WDS_VENDOR_EXTENSION
|
||||
.txrx_set_wds_rx_policy = dp_txrx_set_wds_rx_policy,
|
||||
.txrx_wds_peer_tx_policy_update = dp_txrx_peer_wds_tx_policy_update,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -817,7 +817,7 @@ static inline void dp_rx_adjust_nbuf_len(qdf_nbuf_t nbuf, uint16_t *mpdu_len)
|
||||
*
|
||||
*/
|
||||
void dp_rx_sg_create(qdf_nbuf_t nbuf, uint8_t *rx_tlv_hdr,
|
||||
uint16_t *mpdu_len, bool *is_first_frag,
|
||||
uint16_t *mpdu_len, bool *is_first_frag,
|
||||
uint16_t *frag_list_len, qdf_nbuf_t *head_frag_nbuf,
|
||||
qdf_nbuf_t *frag_list_head, qdf_nbuf_t *frag_list_tail)
|
||||
{
|
||||
@@ -888,6 +888,98 @@ static inline void dp_rx_deliver_to_stack(struct dp_vdev *vdev,
|
||||
|
||||
}
|
||||
|
||||
#ifdef WDS_VENDOR_EXTENSION
|
||||
int dp_wds_rx_policy_check(
|
||||
uint8_t *rx_tlv_hdr,
|
||||
struct dp_vdev *vdev,
|
||||
struct dp_peer *peer,
|
||||
int rx_mcast
|
||||
)
|
||||
{
|
||||
struct dp_peer *bss_peer;
|
||||
int fr_ds, to_ds, rx_3addr, rx_4addr;
|
||||
int rx_policy_ucast, rx_policy_mcast;
|
||||
|
||||
if (vdev->opmode == wlan_op_mode_ap) {
|
||||
TAILQ_FOREACH(bss_peer, &vdev->peer_list, peer_list_elem) {
|
||||
if (bss_peer->bss_peer) {
|
||||
/* if wds policy check is not enabled on this vdev, accept all frames */
|
||||
if (!bss_peer->wds_ecm.wds_rx_filter) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
rx_policy_ucast = bss_peer->wds_ecm.wds_rx_ucast_4addr;
|
||||
rx_policy_mcast = bss_peer->wds_ecm.wds_rx_mcast_4addr;
|
||||
} else { /* sta mode */
|
||||
if (!peer->wds_ecm.wds_rx_filter) {
|
||||
return 1;
|
||||
}
|
||||
rx_policy_ucast = peer->wds_ecm.wds_rx_ucast_4addr;
|
||||
rx_policy_mcast = peer->wds_ecm.wds_rx_mcast_4addr;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------
|
||||
* self
|
||||
* peer- rx rx-
|
||||
* wds ucast mcast dir policy accept note
|
||||
* ------------------------------------------------
|
||||
* 1 1 0 11 x1 1 AP configured to accept ds-to-ds Rx ucast from wds peers, constraint met; so, accept
|
||||
* 1 1 0 01 x1 0 AP configured to accept ds-to-ds Rx ucast from wds peers, constraint not met; so, drop
|
||||
* 1 1 0 10 x1 0 AP configured to accept ds-to-ds Rx ucast from wds peers, constraint not met; so, drop
|
||||
* 1 1 0 00 x1 0 bad frame, won't see it
|
||||
* 1 0 1 11 1x 1 AP configured to accept ds-to-ds Rx mcast from wds peers, constraint met; so, accept
|
||||
* 1 0 1 01 1x 0 AP configured to accept ds-to-ds Rx mcast from wds peers, constraint not met; so, drop
|
||||
* 1 0 1 10 1x 0 AP configured to accept ds-to-ds Rx mcast from wds peers, constraint not met; so, drop
|
||||
* 1 0 1 00 1x 0 bad frame, won't see it
|
||||
* 1 1 0 11 x0 0 AP configured to accept from-ds Rx ucast from wds peers, constraint not met; so, drop
|
||||
* 1 1 0 01 x0 0 AP configured to accept from-ds Rx ucast from wds peers, constraint not met; so, drop
|
||||
* 1 1 0 10 x0 1 AP configured to accept from-ds Rx ucast from wds peers, constraint met; so, accept
|
||||
* 1 1 0 00 x0 0 bad frame, won't see it
|
||||
* 1 0 1 11 0x 0 AP configured to accept from-ds Rx mcast from wds peers, constraint not met; so, drop
|
||||
* 1 0 1 01 0x 0 AP configured to accept from-ds Rx mcast from wds peers, constraint not met; so, drop
|
||||
* 1 0 1 10 0x 1 AP configured to accept from-ds Rx mcast from wds peers, constraint met; so, accept
|
||||
* 1 0 1 00 0x 0 bad frame, won't see it
|
||||
*
|
||||
* 0 x x 11 xx 0 we only accept td-ds Rx frames from non-wds peers in mode.
|
||||
* 0 x x 01 xx 1
|
||||
* 0 x x 10 xx 0
|
||||
* 0 x x 00 xx 0 bad frame, won't see it
|
||||
* ------------------------------------------------
|
||||
*/
|
||||
|
||||
fr_ds = hal_rx_mpdu_get_fr_ds(rx_tlv_hdr);
|
||||
to_ds = hal_rx_mpdu_get_to_ds(rx_tlv_hdr);
|
||||
rx_3addr = fr_ds ^ to_ds;
|
||||
rx_4addr = fr_ds & to_ds;
|
||||
|
||||
if (vdev->opmode == wlan_op_mode_ap) {
|
||||
if ((!peer->wds_enabled && rx_3addr && to_ds) ||
|
||||
(peer->wds_enabled && !rx_mcast && (rx_4addr == rx_policy_ucast)) ||
|
||||
(peer->wds_enabled && rx_mcast && (rx_4addr == rx_policy_mcast))) {
|
||||
return 1;
|
||||
}
|
||||
} else { /* sta mode */
|
||||
if ((!rx_mcast && (rx_4addr == rx_policy_ucast)) ||
|
||||
(rx_mcast && (rx_4addr == rx_policy_mcast))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int dp_wds_rx_policy_check(
|
||||
uint8_t *rx_tlv_hdr,
|
||||
struct dp_vdev *vdev,
|
||||
struct dp_peer *peer,
|
||||
int rx_mcast
|
||||
)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* dp_rx_process() - Brain of the Rx processing functionality
|
||||
* Called from the bottom half (tasklet/NET_RX_SOFTIRQ)
|
||||
@@ -1182,6 +1274,18 @@ done:
|
||||
*/
|
||||
dp_rx_peer_validity_check(peer);
|
||||
|
||||
if (!dp_wds_rx_policy_check(rx_tlv_hdr, vdev, peer,
|
||||
hal_rx_msdu_end_da_is_mcbc_get(rx_tlv_hdr))) {
|
||||
QDF_TRACE(QDF_MODULE_ID_DP,
|
||||
QDF_TRACE_LEVEL_ERROR,
|
||||
FL("Policy Check Drop pkt"));
|
||||
/* Drop & free packet */
|
||||
qdf_nbuf_free(nbuf);
|
||||
/* Statistics */
|
||||
nbuf = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (qdf_unlikely(peer && peer->bss_peer)) {
|
||||
QDF_TRACE(QDF_MODULE_ID_DP,
|
||||
QDF_TRACE_LEVEL_ERROR,
|
||||
|
@@ -659,4 +659,7 @@ void dp_rx_fill_mesh_stats(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
|
||||
QDF_STATUS dp_rx_filter_mesh_packets(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
|
||||
uint8_t *rx_tlv_hdr);
|
||||
|
||||
int dp_wds_rx_policy_check(uint8_t *rx_tlv_hdr, struct dp_vdev *vdev,
|
||||
struct dp_peer *peer, int rx_mcast);
|
||||
|
||||
#endif /* _DP_RX_H */
|
||||
|
@@ -494,6 +494,16 @@ skip_mec_check:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!dp_wds_rx_policy_check(rx_desc->rx_buf_start, vdev, peer,
|
||||
hal_rx_msdu_end_da_is_mcbc_get(rx_desc->rx_buf_start))) {
|
||||
QDF_TRACE(QDF_MODULE_ID_DP,
|
||||
QDF_TRACE_LEVEL_ERROR,
|
||||
FL("mcast Policy Check Drop pkt"));
|
||||
/* Drop & free packet */
|
||||
qdf_nbuf_free(nbuf);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* WDS Source Port Learning */
|
||||
if (qdf_likely(vdev->rx_decap_type == htt_cmn_pkt_type_ethernet))
|
||||
dp_rx_wds_srcport_learn(soc, rx_desc->rx_buf_start, peer, nbuf);
|
||||
|
@@ -1746,6 +1746,12 @@ void dp_tx_reinject_handler(struct dp_tx_desc_s *tx_desc, uint8_t *status)
|
||||
struct dp_ast_entry *ast_entry = NULL;
|
||||
struct dp_soc *soc = NULL;
|
||||
struct ether_header *eh = (struct ether_header *)qdf_nbuf_data(nbuf);
|
||||
#ifdef WDS_VENDOR_EXTENSION
|
||||
int is_mcast = 0, is_ucast = 0;
|
||||
int num_peers_3addr = 0;
|
||||
struct ether_header *eth_hdr = (struct ether_header *)(qdf_nbuf_data(nbuf));
|
||||
struct ieee80211_frame_addr4 *wh = (struct ieee80211_frame_addr4 *)(qdf_nbuf_data(nbuf));
|
||||
#endif
|
||||
|
||||
vdev = tx_desc->vdev;
|
||||
soc = vdev->pdev->soc;
|
||||
@@ -1762,7 +1768,6 @@ void dp_tx_reinject_handler(struct dp_tx_desc_s *tx_desc, uint8_t *status)
|
||||
DP_STATS_INC_PKT(vdev, tx_i.reinject_pkts, 1,
|
||||
qdf_nbuf_len(tx_desc->nbuf));
|
||||
|
||||
|
||||
qdf_spin_lock_bh(&(soc->ast_lock));
|
||||
|
||||
ast_entry = dp_peer_ast_hash_find(soc, (uint8_t *)(eh->ether_shost), 0);
|
||||
@@ -1771,16 +1776,53 @@ void dp_tx_reinject_handler(struct dp_tx_desc_s *tx_desc, uint8_t *status)
|
||||
|
||||
qdf_spin_unlock_bh(&(soc->ast_lock));
|
||||
|
||||
#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;
|
||||
} else {
|
||||
is_mcast = (IS_MULTICAST(eth_hdr->ether_dhost)) ? 1 : 0;
|
||||
}
|
||||
is_ucast = !is_mcast;
|
||||
|
||||
TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) {
|
||||
if (peer->bss_peer)
|
||||
continue;
|
||||
|
||||
/* Detect wds peers that use 3-addr framing for mcast.
|
||||
* if there are any, the bss_peer is used to send the
|
||||
* the mcast frame using 3-addr format. all wds enabled
|
||||
* peers that use 4-addr framing for mcast frames will
|
||||
* be duplicated and sent as 4-addr frames below.
|
||||
*/
|
||||
if (!peer->wds_enabled || !peer->wds_ecm.wds_tx_mcast_4addr) {
|
||||
num_peers_3addr = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (qdf_unlikely(vdev->mesh_vdev)) {
|
||||
DP_TX_FREE_SINGLE_BUF(vdev->pdev->soc, tx_desc->nbuf);
|
||||
} else {
|
||||
TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) {
|
||||
if ((peer->peer_ids[0] != HTT_INVALID_PEER) &&
|
||||
((peer->bss_peer &&
|
||||
!(vdev->osif_proxy_arp(
|
||||
vdev->osif_vdev,
|
||||
nbuf))) ||
|
||||
peer->nawds_enabled)) {
|
||||
#ifdef WDS_VENDOR_EXTENSION
|
||||
/*
|
||||
* . if 3-addr STA, then send on BSS Peer
|
||||
* . if Peer WDS enabled and accept 4-addr mcast,
|
||||
* send mcast on that peer only
|
||||
* . if Peer WDS enabled and accept 4-addr ucast,
|
||||
* send ucast on that peer only
|
||||
*/
|
||||
((peer->bss_peer && num_peers_3addr && is_mcast) ||
|
||||
(peer->wds_enabled &&
|
||||
((is_mcast && peer->wds_ecm.wds_tx_mcast_4addr) ||
|
||||
(is_ucast && peer->wds_ecm.wds_tx_ucast_4addr))))) {
|
||||
#else
|
||||
((peer->bss_peer &&
|
||||
!(vdev->osif_proxy_arp(vdev->osif_vdev, nbuf))) ||
|
||||
peer->nawds_enabled)) {
|
||||
#endif
|
||||
peer_id = DP_INVALID_PEER;
|
||||
|
||||
if (peer->nawds_enabled) {
|
||||
|
@@ -1217,6 +1217,17 @@ enum {
|
||||
dp_sec_ucast
|
||||
};
|
||||
|
||||
#ifdef WDS_VENDOR_EXTENSION
|
||||
typedef struct {
|
||||
uint8_t wds_tx_mcast_4addr:1,
|
||||
wds_tx_ucast_4addr:1,
|
||||
wds_rx_filter:1, /* enforce rx filter */
|
||||
wds_rx_ucast_4addr:1, /* when set, accept 4addr unicast frames */
|
||||
wds_rx_mcast_4addr:1; /* when set, accept 4addr multicast frames */
|
||||
|
||||
} dp_ecm_policy;
|
||||
#endif
|
||||
|
||||
/* Peer structure for data path state */
|
||||
struct dp_peer {
|
||||
/* VDEV to which this peer is associated */
|
||||
@@ -1265,7 +1276,8 @@ struct dp_peer {
|
||||
/* NAWDS Flag and Bss Peer bit */
|
||||
uint8_t nawds_enabled:1,
|
||||
bss_peer:1,
|
||||
wapi:1;
|
||||
wapi:1,
|
||||
wds_enabled:1;
|
||||
|
||||
/* MCL specific peer local id */
|
||||
uint16_t local_id;
|
||||
@@ -1280,6 +1292,10 @@ struct dp_peer {
|
||||
|
||||
TAILQ_HEAD(, dp_ast_entry) ast_entry_list;
|
||||
/* TBD */
|
||||
|
||||
#ifdef WDS_VENDOR_EXTENSION
|
||||
dp_ecm_policy wds_ecm;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_WIN
|
||||
|
Reference in New Issue
Block a user