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:

committed by
nshrivas

parent
3053deedfa
commit
974da2640a
@@ -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++) {
|
||||||
|
@@ -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);
|
||||||
|
@@ -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,
|
||||||
|
Reference in New Issue
Block a user