From 63d979273d4b8f5ab4fc550c1c3e12d899bf96fe Mon Sep 17 00:00:00 2001 From: Chaitanya Pratapa Date: Thu, 24 Oct 2019 19:45:20 -0700 Subject: [PATCH] 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 Signed-off-by: Chaitanya Pratapa --- .../platform/msm/ipa/ipa_clients/ecm_ipa.c | 8 +++++++ .../platform/msm/ipa/ipa_clients/rndis_ipa.c | 10 +++++++++ drivers/platform/msm/ipa/ipa_v3/ipa_client.c | 5 +++++ drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 21 ++++++++++++++----- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c index 8dfe1920c56b..0c319f951e5a 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c +++ b/drivers/platform/msm/ipa/ipa_clients/ecm_ipa.c @@ -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; } diff --git a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c index c201aa342084..8b93ee9b0e35 100644 --- a/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c +++ b/drivers/platform/msm/ipa/ipa_clients/rndis_ipa.c @@ -1135,6 +1135,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); @@ -1142,11 +1148,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 (evt != IPA_RECEIVE) { RNDIS_IPA_ERROR_RL("a none IPA_RECEIVE event in driver RX\n"); + rndis_ipa_ctx->rx_dropped++; + dev_kfree_skb_any(skb); return; } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 2b36491a5c5d..f4b4b24da406 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -1524,7 +1524,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) { @@ -1544,7 +1547,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; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index dd341697d6ea..298f4343ea4c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -3402,14 +3402,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; } @@ -3431,12 +3435,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)