qcacld-3.0: Introduce SSR protection wrapper to IPA callback APIs
IPA driver calling WLAN driver callback, and in parallel WLAN driver is unloading and freeing this callback, which leads to a use after free scenario Add SSR protection wrapper to all of IPA callback APIs in driver to avoid racing against driver unload or SSR or self recovery Change-Id: I5dcdfe4749b89104ec79eac060e60fe5aa7c2335 Crs-Fixed: 2307365
This commit is contained in:
@@ -322,8 +322,8 @@ QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx,
|
|||||||
struct op_msg_type *op_msg);
|
struct op_msg_type *op_msg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wlan_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
|
* wlan_ipa_wdi_meter_notifier_cb() - SSR wrapper for
|
||||||
* IPA calls to get WLAN stats or set quota limit.
|
* __wlan_ipa_wdi_meter_notifier_cb
|
||||||
* @priv: pointer to private data registered with IPA (we register a
|
* @priv: pointer to private data registered with IPA (we register a
|
||||||
* pointer to the global IPA context)
|
* pointer to the global IPA context)
|
||||||
* @evt: the IPA event which triggered the callback
|
* @evt: the IPA event which triggered the callback
|
||||||
@@ -332,7 +332,7 @@ QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx,
|
|||||||
* Return: None
|
* Return: None
|
||||||
*/
|
*/
|
||||||
void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
|
void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
|
||||||
void *data);
|
void *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wlan_ipa_init_metering() - IPA metering stats completion event reset
|
* wlan_ipa_init_metering() - IPA metering stats completion event reset
|
||||||
|
@@ -743,7 +743,7 @@ static enum wlan_ipa_forward_type wlan_ipa_intrabss_forward(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wlan_ipa_w2i_cb() - WLAN to IPA callback handler
|
* __wlan_ipa_w2i_cb() - WLAN to IPA callback handler
|
||||||
* @priv: pointer to private data registered with IPA (we register a
|
* @priv: pointer to private data registered with IPA (we register a
|
||||||
* pointer to the global IPA context)
|
* pointer to the global IPA context)
|
||||||
* @evt: the IPA event which triggered the callback
|
* @evt: the IPA event which triggered the callback
|
||||||
@@ -751,8 +751,8 @@ static enum wlan_ipa_forward_type wlan_ipa_intrabss_forward(
|
|||||||
*
|
*
|
||||||
* Return: None
|
* Return: None
|
||||||
*/
|
*/
|
||||||
static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
|
static void __wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
|
||||||
unsigned long data)
|
unsigned long data)
|
||||||
{
|
{
|
||||||
struct wlan_ipa_priv *ipa_ctx = NULL;
|
struct wlan_ipa_priv *ipa_ctx = NULL;
|
||||||
qdf_nbuf_t skb;
|
qdf_nbuf_t skb;
|
||||||
@@ -761,6 +761,11 @@ static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
|
|||||||
struct wlan_ipa_iface_context *iface_context;
|
struct wlan_ipa_iface_context *iface_context;
|
||||||
uint8_t fw_desc;
|
uint8_t fw_desc;
|
||||||
|
|
||||||
|
if (qdf_is_module_state_transitioning()) {
|
||||||
|
ipa_err("Module transition in progress");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ipa_ctx = (struct wlan_ipa_priv *)priv;
|
ipa_ctx = (struct wlan_ipa_priv *)priv;
|
||||||
|
|
||||||
if (!ipa_ctx)
|
if (!ipa_ctx)
|
||||||
@@ -834,7 +839,24 @@ static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wlan_ipa_i2w_cb() - IPA to WLAN callback
|
* wlan_ipa_w2i_cb() - SSR wrapper for __wlan_ipa_w2i_cb
|
||||||
|
* @priv: pointer to private data registered with IPA (we register a
|
||||||
|
* pointer to the global IPA context)
|
||||||
|
* @evt: the IPA event which triggered the callback
|
||||||
|
* @data: data associated with the event
|
||||||
|
*
|
||||||
|
* Return: None
|
||||||
|
*/
|
||||||
|
static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
|
||||||
|
unsigned long data)
|
||||||
|
{
|
||||||
|
qdf_ssr_protect(__func__);
|
||||||
|
__wlan_ipa_w2i_cb(priv, evt, data);
|
||||||
|
qdf_ssr_unprotect(__func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __wlan_ipa_i2w_cb() - IPA to WLAN callback
|
||||||
* @priv: pointer to private data registered with IPA (we register a
|
* @priv: pointer to private data registered with IPA (we register a
|
||||||
* pointer to the interface-specific IPA context)
|
* pointer to the interface-specific IPA context)
|
||||||
* @evt: the IPA event which triggered the callback
|
* @evt: the IPA event which triggered the callback
|
||||||
@@ -842,8 +864,8 @@ static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
|
|||||||
*
|
*
|
||||||
* Return: None
|
* Return: None
|
||||||
*/
|
*/
|
||||||
static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
|
static void __wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
|
||||||
unsigned long data)
|
unsigned long data)
|
||||||
{
|
{
|
||||||
struct wlan_ipa_priv *ipa_ctx = NULL;
|
struct wlan_ipa_priv *ipa_ctx = NULL;
|
||||||
qdf_ipa_rx_data_t *ipa_tx_desc;
|
qdf_ipa_rx_data_t *ipa_tx_desc;
|
||||||
@@ -851,6 +873,11 @@ static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
|
|||||||
qdf_nbuf_t skb;
|
qdf_nbuf_t skb;
|
||||||
struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
|
struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL;
|
||||||
|
|
||||||
|
if (qdf_is_module_state_transitioning()) {
|
||||||
|
ipa_err("Module transition in progress");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
iface_context = (struct wlan_ipa_iface_context *)priv;
|
iface_context = (struct wlan_ipa_iface_context *)priv;
|
||||||
ipa_tx_desc = (qdf_ipa_rx_data_t *)data;
|
ipa_tx_desc = (qdf_ipa_rx_data_t *)data;
|
||||||
ipa_ctx = iface_context->ipa_ctx;
|
ipa_ctx = iface_context->ipa_ctx;
|
||||||
@@ -903,6 +930,23 @@ static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
|
|||||||
return wlan_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
|
return wlan_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wlan_ipa_i2w_cb() - IPA to WLAN callback
|
||||||
|
* @priv: pointer to private data registered with IPA (we register a
|
||||||
|
* pointer to the interface-specific IPA context)
|
||||||
|
* @evt: the IPA event which triggered the callback
|
||||||
|
* @data: data associated with the event
|
||||||
|
*
|
||||||
|
* Return: None
|
||||||
|
*/
|
||||||
|
static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt,
|
||||||
|
unsigned long data)
|
||||||
|
{
|
||||||
|
qdf_ssr_protect(__func__);
|
||||||
|
__wlan_ipa_i2w_cb(priv, evt, data);
|
||||||
|
qdf_ssr_unprotect(__func__);
|
||||||
|
}
|
||||||
|
|
||||||
QDF_STATUS wlan_ipa_suspend(struct wlan_ipa_priv *ipa_ctx)
|
QDF_STATUS wlan_ipa_suspend(struct wlan_ipa_priv *ipa_ctx)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -2674,18 +2718,23 @@ static void wlan_ipa_uc_op_cb(struct op_msg_type *op_msg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wlan_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
|
* __wlan_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler
|
||||||
* @work: uC OP work
|
* @data: uC OP work
|
||||||
*
|
*
|
||||||
* Return: None
|
* Return: None
|
||||||
*/
|
*/
|
||||||
static void wlan_ipa_uc_fw_op_event_handler(void *data)
|
static void __wlan_ipa_uc_fw_op_event_handler(void *data)
|
||||||
{
|
{
|
||||||
struct op_msg_type *msg;
|
struct op_msg_type *msg;
|
||||||
struct uc_op_work_struct *uc_op_work =
|
struct uc_op_work_struct *uc_op_work =
|
||||||
(struct uc_op_work_struct *)data;
|
(struct uc_op_work_struct *)data;
|
||||||
struct wlan_ipa_priv *ipa_ctx = gp_ipa;
|
struct wlan_ipa_priv *ipa_ctx = gp_ipa;
|
||||||
|
|
||||||
|
if (qdf_is_module_state_transitioning()) {
|
||||||
|
ipa_err("Module transition in progress");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
msg = uc_op_work->msg;
|
msg = uc_op_work->msg;
|
||||||
uc_op_work->msg = NULL;
|
uc_op_work->msg = NULL;
|
||||||
ipa_debug("posted msg %d", msg->op_code);
|
ipa_debug("posted msg %d", msg->op_code);
|
||||||
@@ -2693,6 +2742,20 @@ static void wlan_ipa_uc_fw_op_event_handler(void *data)
|
|||||||
wlan_ipa_uc_op_cb(msg, ipa_ctx);
|
wlan_ipa_uc_op_cb(msg, ipa_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wlan_ipa_uc_fw_op_event_handler - SSR wrapper for
|
||||||
|
* __wlan_ipa_uc_fw_op_event_handler
|
||||||
|
* @data: uC OP work
|
||||||
|
*
|
||||||
|
* Return: None
|
||||||
|
*/
|
||||||
|
static void wlan_ipa_uc_fw_op_event_handler(void *data)
|
||||||
|
{
|
||||||
|
qdf_ssr_protect(__func__);
|
||||||
|
__wlan_ipa_uc_fw_op_event_handler(data);
|
||||||
|
qdf_ssr_unprotect(__func__);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wlan_ipa_uc_op_event_handler() - IPA UC OP event handler
|
* wlan_ipa_uc_op_event_handler() - IPA UC OP event handler
|
||||||
* @op_msg: operation message received from firmware
|
* @op_msg: operation message received from firmware
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#include "wlan_ipa_main.h"
|
#include "wlan_ipa_main.h"
|
||||||
#include "wlan_ipa_core.h"
|
#include "wlan_ipa_core.h"
|
||||||
#include "cdp_txrx_ipa.h"
|
#include "cdp_txrx_ipa.h"
|
||||||
|
#include "qdf_platform.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wlan_ipa_uc_rt_debug_host_fill - fill rt debug buffer
|
* wlan_ipa_uc_rt_debug_host_fill - fill rt debug buffer
|
||||||
@@ -845,7 +846,7 @@ QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* wlan_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
|
* __wlan_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler.
|
||||||
* IPA calls to get WLAN stats or set quota limit.
|
* IPA calls to get WLAN stats or set quota limit.
|
||||||
* @priv: pointer to private data registered with IPA (we register a
|
* @priv: pointer to private data registered with IPA (we register a
|
||||||
* pointer to the IPA context)
|
* pointer to the IPA context)
|
||||||
@@ -854,8 +855,8 @@ QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx,
|
|||||||
*
|
*
|
||||||
* Return: None
|
* Return: None
|
||||||
*/
|
*/
|
||||||
void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
|
static void __wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
struct wlan_ipa_priv *ipa_ctx = wlan_ipa_get_obj_context();
|
struct wlan_ipa_priv *ipa_ctx = wlan_ipa_get_obj_context();
|
||||||
struct wlan_ipa_iface_context *iface_ctx;
|
struct wlan_ipa_iface_context *iface_ctx;
|
||||||
@@ -865,6 +866,11 @@ void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
|
|||||||
|
|
||||||
ipa_debug("event=%d", evt);
|
ipa_debug("event=%d", evt);
|
||||||
|
|
||||||
|
if (qdf_is_module_state_transitioning()) {
|
||||||
|
ipa_err("Module transition in progress");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
|
iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE);
|
||||||
if (!iface_ctx) {
|
if (!iface_ctx) {
|
||||||
ipa_err("IPA uC share stats failed - no iface");
|
ipa_err("IPA uC share stats failed - no iface");
|
||||||
@@ -937,4 +943,23 @@ void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wlan_ipa_wdi_meter_notifier_cb() - SSR wrapper for
|
||||||
|
* __wlan_ipa_wdi_meter_notifier_cb
|
||||||
|
* @priv: pointer to private data registered with IPA (we register a
|
||||||
|
* pointer to the IPA context)
|
||||||
|
* @evt: the IPA event which triggered the callback
|
||||||
|
* @data: data associated with the event
|
||||||
|
*
|
||||||
|
* Return: None
|
||||||
|
*/
|
||||||
|
void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
qdf_ssr_protect(__func__);
|
||||||
|
__wlan_ipa_wdi_meter_notifier_cb(evt, data);
|
||||||
|
qdf_ssr_unprotect(__func__);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* FEATURE_METERING */
|
#endif /* FEATURE_METERING */
|
||||||
|
Reference in New Issue
Block a user