qcacmn: Avoid reference of peer object after peer_teardown

In API dp_peer_find_by_id return NULL if delete_in_progress
bit is set, this will avoid referencing peer memory which will
be free in peer_unmap event asynchronously.

Change-Id: Ieab559b9274a886809a9baa9bb348d348e924625
CRs-fixed: 2194265
This commit is contained in:
Chaithanya Garrepalli
2018-02-22 20:32:19 +05:30
committed by nshrivas
parent 3053deedfa
commit 974da2640a
3 changed files with 52 additions and 28 deletions

View File

@@ -914,6 +914,8 @@ static inline struct dp_peer *dp_peer_find_add_id(struct dp_soc *soc,
qdf_atomic_read(&peer->ref_cnt)); qdf_atomic_read(&peer->ref_cnt));
soc->peer_id_to_obj_map[peer_id] = peer; soc->peer_id_to_obj_map[peer_id] = peer;
qdf_assert_always(!peer->delete_in_progress);
if (dp_peer_find_add_id_to_obj(peer, peer_id)) { if (dp_peer_find_add_id_to_obj(peer, peer_id)) {
/* TBDXXX: assert for now */ /* TBDXXX: assert for now */
QDF_ASSERT(0); QDF_ASSERT(0);
@@ -994,7 +996,8 @@ dp_rx_peer_unmap_handler(void *soc_handle, uint16_t peer_id)
struct dp_peer *peer; struct dp_peer *peer;
struct dp_soc *soc = (struct dp_soc *)soc_handle; struct dp_soc *soc = (struct dp_soc *)soc_handle;
uint8_t i; uint8_t i;
peer = dp_peer_find_by_id(soc, peer_id);
peer = __dp_peer_find_by_id(soc, peer_id);
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH,
"peer_unmap_event (soc:%pK) peer_id %d peer %pK\n", "peer_unmap_event (soc:%pK) peer_id %d peer %pK\n",
@@ -1005,8 +1008,12 @@ dp_rx_peer_unmap_handler(void *soc_handle, uint16_t peer_id)
* If the peer ID is for a vdev, then the peer pointer stored * If the peer ID is for a vdev, then the peer pointer stored
* in peer_id_to_obj_map will be NULL. * in peer_id_to_obj_map will be NULL.
*/ */
if (!peer) if (!peer) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"%s: Received unmap event for invalid peer_id"
" %u\n", __func__, peer_id);
return; return;
}
soc->peer_id_to_obj_map[peer_id] = NULL; soc->peer_id_to_obj_map[peer_id] = NULL;
for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) { for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) {

View File

@@ -23,9 +23,8 @@
#include "dp_types.h" #include "dp_types.h"
#define DP_INVALID_PEER_ID 0xffff #define DP_INVALID_PEER_ID 0xffff
/** /**
* dp_peer_find_by_id() - Returns peer object given the peer id * __dp_peer_find_by_id() - Returns peer object given the peer id
* *
* @soc : core DP soc context * @soc : core DP soc context
* @peer_id : peer id from peer object can be retrieved * @peer_id : peer id from peer object can be retrieved
@@ -33,7 +32,7 @@
* Return: struct dp_peer*: Pointer to DP peer object * Return: struct dp_peer*: Pointer to DP peer object
*/ */
static inline struct dp_peer * static inline struct dp_peer *
dp_peer_find_by_id(struct dp_soc *soc, __dp_peer_find_by_id(struct dp_soc *soc,
uint16_t peer_id) uint16_t peer_id)
{ {
struct dp_peer *peer; struct dp_peer *peer;
@@ -53,6 +52,30 @@ dp_peer_find_by_id(struct dp_soc *soc,
return peer; return peer;
} }
/**
* dp_peer_find_by_id() - Returns peer object given the peer id
* if delete_in_progress in not set for peer
*
* @soc : core DP soc context
* @peer_id : peer id from peer object can be retrieved
*
* Return: struct dp_peer*: Pointer to DP peer object
*/
static inline struct dp_peer *
dp_peer_find_by_id(struct dp_soc *soc,
uint16_t peer_id)
{
struct dp_peer *peer;
peer = __dp_peer_find_by_id (soc, peer_id);
if (peer && peer->delete_in_progress) {
return NULL;
}
return peer;
}
void dp_rx_peer_map_handler(void *soc_handle, uint16_t peer_id, void dp_rx_peer_map_handler(void *soc_handle, uint16_t peer_id,
uint16_t hw_peer_id, uint8_t vdev_id, uint8_t *peer_mac_addr); uint16_t hw_peer_id, uint8_t vdev_id, uint8_t *peer_mac_addr);
void dp_rx_peer_unmap_handler(void *soc_handle, uint16_t peer_id); void dp_rx_peer_unmap_handler(void *soc_handle, uint16_t peer_id);

View File

@@ -317,12 +317,6 @@ dp_get_vdev_from_peer(struct dp_soc *soc,
} }
return vdev; return vdev;
} }
/*
* In case of LFR, this is an empty inline function
*/
static inline void dp_rx_peer_validity_check(struct dp_peer *peer)
{
}
#else #else
static inline struct dp_vdev * static inline struct dp_vdev *
dp_get_vdev_from_peer(struct dp_soc *soc, dp_get_vdev_from_peer(struct dp_soc *soc,
@@ -340,14 +334,6 @@ dp_get_vdev_from_peer(struct dp_soc *soc,
return peer->vdev; return peer->vdev;
} }
} }
/*
* Assert if PEER is NULL
*/
static inline void dp_rx_peer_validity_check(struct dp_peer *peer)
{
qdf_assert_always(peer);
}
#endif #endif
/** /**
@@ -723,6 +709,10 @@ uint8_t dp_rx_process_invalid_peer(struct dp_soc *soc, qdf_nbuf_t mpdu)
dp_rx_mon_deliver(soc, i, dp_rx_mon_deliver(soc, i,
pdev->invalid_peer_head_msdu, pdev->invalid_peer_head_msdu,
pdev->invalid_peer_tail_msdu); pdev->invalid_peer_tail_msdu);
pdev->invalid_peer_head_msdu = NULL;
pdev->invalid_peer_tail_msdu = NULL;
return 0; return 0;
} }
} }
@@ -1332,8 +1322,20 @@ done:
deliver_list_tail = NULL; deliver_list_tail = NULL;
} }
if (qdf_likely(peer != NULL)) if (qdf_likely(peer != NULL)) {
vdev = peer->vdev; vdev = peer->vdev;
} else {
qdf_nbuf_free(nbuf);
nbuf = next;
continue;
}
if (qdf_unlikely(vdev == NULL)) {
qdf_nbuf_free(nbuf);
nbuf = next;
DP_STATS_INC(soc, rx.err.invalid_vdev, 1);
continue;
}
/* /*
* Check if DMA completed -- msdu_done is the last bit * Check if DMA completed -- msdu_done is the last bit
@@ -1387,14 +1389,6 @@ done:
} }
} }
/*
* This is a redundant sanity check, Ideally peer
* should never be NULL here. if for any reason it
* is NULL we will assert.
* Do nothing for LFR case.
*/
dp_rx_peer_validity_check(peer);
if (!dp_wds_rx_policy_check(rx_tlv_hdr, vdev, peer, if (!dp_wds_rx_policy_check(rx_tlv_hdr, vdev, peer,
hal_rx_msdu_end_da_is_mcbc_get(rx_tlv_hdr))) { hal_rx_msdu_end_da_is_mcbc_get(rx_tlv_hdr))) {
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE(QDF_MODULE_ID_DP,