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:
Tallapragada Kalyan
2017-12-08 21:07:43 +05:30
committed by snandini
parent 9dee72a40c
commit 2a5fc625d2
8 changed files with 286 additions and 8 deletions

View File

@@ -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);
};

View File

@@ -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

View File

@@ -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
};
/*

View File

@@ -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,

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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