msm: ipa: Fix rndis client disconnection gracefully
if there are packets coming from rndis client to device IPA driver tries to gives those packets to network driver. If at the same time USB disconnection is in progress, there can be a possibility of race where callback is called with NULL private data and it can result in a undefined behavior at client driver. Make changes to add proper checks to handle the scenario gracefully. Change-Id: I7b3a5731ae21362dc67c53a2de464b17a223d4ba Signed-off-by: Praveen Kurapati <pkurapat@codeaurora.org> Signed-off-by: Chaitanya Pratapa <cpratapa@codeaurora.org>
This commit is contained in:
parent
e4022b8689
commit
a861d69435
4 changed files with 40 additions and 6 deletions
drivers/platform/msm/ipa
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
|
@ -659,13 +659,21 @@ static void ecm_ipa_packet_receive_notify
|
|||
packet_len = skb->len;
|
||||
ECM_IPA_DEBUG("packet RX, len=%d\n", skb->len);
|
||||
|
||||
if (unlikely(ecm_ipa_ctx == NULL)) {
|
||||
ECM_IPA_DEBUG("Private context is NULL. Drop SKB.\n");
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(ecm_ipa_ctx->state != ECM_IPA_CONNECTED_AND_UP)) {
|
||||
ECM_IPA_DEBUG("Missing pipe connected and/or iface up\n");
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(evt != IPA_RECEIVE)) {
|
||||
ECM_IPA_ERROR("A none IPA_RECEIVE event in ecm_ipa_receive\n");
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1122,6 +1122,12 @@ static void rndis_ipa_packet_receive_notify(
|
|||
("packet Rx, len=%d\n",
|
||||
skb->len);
|
||||
|
||||
if (unlikely(rndis_ipa_ctx == NULL)) {
|
||||
RNDIS_IPA_DEBUG("Private context is NULL. Drop SKB.\n");
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(rndis_ipa_ctx->rx_dump_enable))
|
||||
rndis_ipa_dump_skb(skb);
|
||||
|
||||
|
@ -1129,11 +1135,15 @@ static void rndis_ipa_packet_receive_notify(
|
|||
RNDIS_IPA_DEBUG("use connect()/up() before receive()\n");
|
||||
RNDIS_IPA_DEBUG("packet dropped (length=%d)\n",
|
||||
skb->len);
|
||||
rndis_ipa_ctx->rx_dropped++;
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
if (unlikely(evt != IPA_RECEIVE)) {
|
||||
RNDIS_IPA_ERROR("a none IPA_RECEIVE event in driver RX\n");
|
||||
rndis_ipa_ctx->rx_dropped++;
|
||||
dev_kfree_skb_any(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1467,7 +1467,10 @@ int ipa3_release_gsi_channel(u32 clnt_hdl)
|
|||
IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl));
|
||||
|
||||
/* Set the disconnect in progress flag to avoid calling cb.*/
|
||||
spin_lock(&ipa3_ctx->disconnect_lock);
|
||||
atomic_set(&ep->disconnect_in_progress, 1);
|
||||
spin_unlock(&ipa3_ctx->disconnect_lock);
|
||||
|
||||
|
||||
gsi_res = gsi_dealloc_channel(ep->gsi_chan_hdl);
|
||||
if (gsi_res != GSI_STATUS_SUCCESS) {
|
||||
|
@ -1487,7 +1490,9 @@ int ipa3_release_gsi_channel(u32 clnt_hdl)
|
|||
if (!ep->keep_ipa_awake)
|
||||
IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
|
||||
|
||||
spin_lock(&ipa3_ctx->disconnect_lock);
|
||||
memset(&ipa3_ctx->ep[clnt_hdl], 0, sizeof(struct ipa3_ep_context));
|
||||
spin_unlock(&ipa3_ctx->disconnect_lock);
|
||||
|
||||
IPADBG("exit\n");
|
||||
return 0;
|
||||
|
|
|
@ -3259,14 +3259,18 @@ void ipa3_lan_rx_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data)
|
|||
unsigned int src_pipe;
|
||||
u32 metadata;
|
||||
u8 ucp;
|
||||
void (*client_notify)(void *client_priv, enum ipa_dp_evt_type evt,
|
||||
unsigned long data);
|
||||
void *client_priv;
|
||||
|
||||
ipahal_pkt_status_parse_thin(rx_skb->data, &status);
|
||||
src_pipe = status.endp_src_idx;
|
||||
metadata = status.metadata;
|
||||
ucp = status.ucp;
|
||||
ep = &ipa3_ctx->ep[src_pipe];
|
||||
if (unlikely(src_pipe >= ipa3_ctx->ipa_num_pipes)) {
|
||||
IPAERR_RL("drop pipe=%d\n", src_pipe);
|
||||
if (unlikely(src_pipe >= ipa3_ctx->ipa_num_pipes) ||
|
||||
unlikely(atomic_read(&ep->disconnect_in_progress))) {
|
||||
IPAERR("drop pipe=%d\n", src_pipe);
|
||||
dev_kfree_skb_any(rx_skb);
|
||||
return;
|
||||
}
|
||||
|
@ -3288,12 +3292,19 @@ void ipa3_lan_rx_cb(void *priv, enum ipa_dp_evt_type evt, unsigned long data)
|
|||
metadata, *(u32 *)rx_skb->cb);
|
||||
IPADBG_LOW("ucp: %d\n", *(u8 *)(rx_skb->cb + 4));
|
||||
|
||||
spin_lock(&ipa3_ctx->disconnect_lock);
|
||||
if (likely((!atomic_read(&ep->disconnect_in_progress)) &&
|
||||
ep->valid && ep->client_notify))
|
||||
ep->client_notify(ep->priv, IPA_RECEIVE,
|
||||
ep->valid && ep->client_notify)) {
|
||||
client_notify = ep->client_notify;
|
||||
client_priv = ep->priv;
|
||||
spin_unlock(&ipa3_ctx->disconnect_lock);
|
||||
client_notify(client_priv, IPA_RECEIVE,
|
||||
(unsigned long)(rx_skb));
|
||||
else
|
||||
} else {
|
||||
spin_unlock(&ipa3_ctx->disconnect_lock);
|
||||
dev_kfree_skb_any(rx_skb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void ipa3_recycle_rx_wrapper(struct ipa3_rx_pkt_wrapper *rx_pkt)
|
||||
|
|
Loading…
Add table
Reference in a new issue