From a6f6879bc6c8b805ac3167a6492f76cdd233f29d Mon Sep 17 00:00:00 2001 From: Komal Maheshwari Date: Fri, 20 Aug 2021 22:10:56 +0530 Subject: [PATCH 1/6] datarmnet: compilation fix for ks sync path Change-Id: Iae1161d91e6abaa0c307fde978824d3f46820ac9 --- core/Android.mk | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/Android.mk b/core/Android.mk index 9aad807d7d38..8df2c97d16ef 100644 --- a/core/Android.mk +++ b/core/Android.mk @@ -10,6 +10,10 @@ ifeq ($(call is-board-platform-in-list, $(RMNET_CORE_DLKM_PLATFORMS_LIST)),true) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) +ifeq ($(BOARD_COMMON_DIR),) + BOARD_COMMON_DIR := device/qcom/common +endif + LOCAL_CFLAGS := -Wno-macro-redefined -Wno-unused-function -Wall -Werror LOCAL_CLANG :=true @@ -30,7 +34,7 @@ LOCAL_SRC_FILES := \ wda_qmi.c RMNET_BLD_DIR := ../../vendor/qcom/opensource/datarmnet/core -DLKM_DIR := $(TOP)/device/qcom/common/dlkm +DLKM_DIR := $(TOP)/$(BOARD_COMMON_DIR)/dlkm KBUILD_OPTIONS := $(RMNET_BLD_DIR) @@ -51,7 +55,7 @@ LOCAL_SRC_FILES := \ rmnet_ctl_ipa.c RMNET_BLD_DIR := ../../vendor/qcom/opensource/datarmnet/core -DLKM_DIR := $(TOP)/device/qcom/common/dlkm +DLKM_DIR := $(TOP)/$(BOARD_COMMON_DIR)/dlkm KBUILD_OPTIONS := $(RMNET_BLD_DIR) From 37ee4eb551f7ad3f2550ac7a1322064d8dcd3b24 Mon Sep 17 00:00:00 2001 From: Weiyi Chen Date: Mon, 4 Oct 2021 10:33:27 -0700 Subject: [PATCH 2/6] dfc: not caching grant for removed bearers If a grant indication for a bearer has "removed" flag set, caching the bearer could lead to data stall for the next data call because modem will not send grant for this bearer during powersave. Do not cache grant for the removed or disabled bearers. Also make sure a bearer is flow enabled when it is associated with a tx queue. Change-Id: I7eca597e3cc7d5a0bfe523201c454fb45e66a3a0 Signed-off-by: Weiyi Chen --- core/dfc_qmi.c | 5 ++++- core/qmi_rmnet.c | 16 ++++++++++------ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/core/dfc_qmi.c b/core/dfc_qmi.c index f52d9e3e032f..2b10540564c6 100644 --- a/core/dfc_qmi.c +++ b/core/dfc_qmi.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1003,7 +1004,9 @@ static int dfc_update_fc_map(struct net_device *dev, struct qos_info *qos, u32 adjusted_grant; itm = qmi_rmnet_get_bearer_map(qos, fc_info->bearer_id); - if (!itm) + + /* cache the bearer assuming it is a new bearer */ + if (unlikely(!itm && !is_query && fc_info->num_bytes)) itm = qmi_rmnet_get_bearer_noref(qos, fc_info->bearer_id); if (itm) { diff --git a/core/qmi_rmnet.c b/core/qmi_rmnet.c index 84818c9b8f57..abeda1f4d84d 100644 --- a/core/qmi_rmnet.c +++ b/core/qmi_rmnet.c @@ -1,5 +1,6 @@ /* -* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -401,12 +402,15 @@ static void __qmi_rmnet_update_mq(struct net_device *dev, bearer->mq_idx = itm->mq_idx; } - qmi_rmnet_flow_control(dev, itm->mq_idx, - bearer->grant_size > 0 ? 1 : 0); - + /* Always enable flow for the newly associated bearer */ + if (!bearer->grant_size) { + bearer->grant_size = DEFAULT_GRANT; + bearer->grant_thresh = + qmi_rmnet_grant_per(DEFAULT_GRANT); + } + qmi_rmnet_flow_control(dev, itm->mq_idx, 1); if (dfc_mode == DFC_MODE_SA) - qmi_rmnet_flow_control(dev, bearer->ack_mq_idx, - bearer->grant_size > 0 ? 1 : 0); + qmi_rmnet_flow_control(dev, bearer->ack_mq_idx, 1); } } From 8c4afb2b42a0adf3c75b237d332182fc3bbc02f3 Mon Sep 17 00:00:00 2001 From: Weiyi Chen Date: Thu, 14 Oct 2021 12:31:07 -0700 Subject: [PATCH 3/6] dfc: reset tx queue When a bearer is removed, calling qdisc reset on a tx queue could have a race condition with qdisc dequeue for lockless qdisc such as pfifo_fast. This change uses a different mechanism not relying on qdisc implementation to achieve packet purge on bearer remove. Change-Id: I8f9201809853b07293896d6cb8e010e9e0904e46 Signed-off-by: Weiyi Chen --- core/qmi_rmnet.c | 51 +++++++++++++++++++++++++--------------------- core/qmi_rmnet.h | 10 +++++++++ core/qmi_rmnet_i.h | 2 ++ core/rmnet_vnd.c | 10 +++++++++ 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/core/qmi_rmnet.c b/core/qmi_rmnet.c index abeda1f4d84d..851d63c6f66b 100644 --- a/core/qmi_rmnet.c +++ b/core/qmi_rmnet.c @@ -222,21 +222,6 @@ int qmi_rmnet_flow_control(struct net_device *dev, u32 mq_idx, int enable) return 0; } -static void qmi_rmnet_reset_txq(struct net_device *dev, unsigned int txq) -{ - struct Qdisc *qdisc; - - if (unlikely(txq >= dev->num_tx_queues)) - return; - - qdisc = rtnl_dereference(netdev_get_tx_queue(dev, txq)->qdisc); - if (qdisc) { - spin_lock_bh(qdisc_lock(qdisc)); - qdisc_reset(qdisc); - spin_unlock_bh(qdisc_lock(qdisc)); - } -} - /** * qmi_rmnet_watchdog_fn - watchdog timer func */ @@ -362,15 +347,13 @@ static void __qmi_rmnet_bearer_put(struct net_device *dev, continue; mq->bearer = NULL; - if (reset) { - qmi_rmnet_reset_txq(dev, i); - qmi_rmnet_flow_control(dev, i, 1); + mq->drop_on_remove = reset; + smp_mb(); - if (dfc_mode == DFC_MODE_SA) { - j = i + ACK_MQ_OFFSET; - qmi_rmnet_reset_txq(dev, j); - qmi_rmnet_flow_control(dev, j, 1); - } + qmi_rmnet_flow_control(dev, i, 1); + if (dfc_mode == DFC_MODE_SA) { + j = i + ACK_MQ_OFFSET; + qmi_rmnet_flow_control(dev, j, 1); } } @@ -394,6 +377,8 @@ static void __qmi_rmnet_update_mq(struct net_device *dev, mq = &qos_info->mq[itm->mq_idx]; if (!mq->bearer) { mq->bearer = bearer; + mq->drop_on_remove = false; + smp_mb(); if (dfc_mode == DFC_MODE_SA) { bearer->mq_idx = itm->mq_idx; @@ -877,6 +862,26 @@ bool qmi_rmnet_all_flows_enabled(struct net_device *dev) EXPORT_SYMBOL(qmi_rmnet_all_flows_enabled); #ifdef CONFIG_QTI_QMI_DFC +bool qmi_rmnet_get_flow_state(struct net_device *dev, struct sk_buff *skb, + bool *drop) +{ + struct qos_info *qos = rmnet_get_qos_pt(dev); + int txq = skb->queue_mapping; + + if (txq > ACK_MQ_OFFSET) + txq -= ACK_MQ_OFFSET; + + if (unlikely(!qos || txq >= MAX_MQ_NUM)) + return false; + + /* If the bearer is gone, packets may need to be dropped */ + *drop = (txq != DEFAULT_MQ_NUM && !READ_ONCE(qos->mq[txq].bearer) && + READ_ONCE(qos->mq[txq].drop_on_remove)); + + return true; +} +EXPORT_SYMBOL(qmi_rmnet_get_flow_state); + void qmi_rmnet_burst_fc_check(struct net_device *dev, int ip_type, u32 mark, unsigned int len) { diff --git a/core/qmi_rmnet.h b/core/qmi_rmnet.h index 80689e807236..855817d39a6c 100644 --- a/core/qmi_rmnet.h +++ b/core/qmi_rmnet.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -59,6 +60,8 @@ void *qmi_rmnet_qos_init(struct net_device *real_dev, struct net_device *vnd_dev, u8 mux_id); void qmi_rmnet_qos_exit_pre(void *qos); void qmi_rmnet_qos_exit_post(void); +bool qmi_rmnet_get_flow_state(struct net_device *dev, struct sk_buff *skb, + bool *drop); void qmi_rmnet_burst_fc_check(struct net_device *dev, int ip_type, u32 mark, unsigned int len); int qmi_rmnet_get_queue(struct net_device *dev, struct sk_buff *skb); @@ -78,6 +81,13 @@ static inline void qmi_rmnet_qos_exit_post(void) { } +static inline bool qmi_rmnet_get_flow_state(struct net_device *dev, + struct sk_buff *skb, + bool *drop) +{ + return false; +} + static inline void qmi_rmnet_burst_fc_check(struct net_device *dev, int ip_type, u32 mark, unsigned int len) diff --git a/core/qmi_rmnet_i.h b/core/qmi_rmnet_i.h index 082351065686..dc50d30a2e73 100644 --- a/core/qmi_rmnet_i.h +++ b/core/qmi_rmnet_i.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -82,6 +83,7 @@ struct svc_info { struct mq_map { struct rmnet_bearer_map *bearer; + bool drop_on_remove; }; struct qos_info { diff --git a/core/rmnet_vnd.c b/core/rmnet_vnd.c index d5187be0497d..84e43271318f 100644 --- a/core/rmnet_vnd.c +++ b/core/rmnet_vnd.c @@ -1,4 +1,5 @@ /* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -68,6 +69,7 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, int ip_type; u32 mark; unsigned int len; + bool need_to_drop = false; priv = netdev_priv(dev); if (priv->real_dev) { @@ -76,6 +78,14 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, mark = skb->mark; len = skb->len; trace_rmnet_xmit_skb(skb); + + qmi_rmnet_get_flow_state(dev, skb, &need_to_drop); + if (unlikely(need_to_drop)) { + this_cpu_inc(priv->pcpu_stats->stats.tx_drops); + kfree_skb(skb); + return NETDEV_TX_OK; + } + rmnet_egress_handler(skb); qmi_rmnet_burst_fc_check(dev, ip_type, mark, len); qmi_rmnet_work_maybe_restart(rmnet_get_rmnet_port(dev)); From 21e13df826ed6569d15bea86fe8ee9815eb03844 Mon Sep 17 00:00:00 2001 From: Weiyi Chen Date: Tue, 7 Dec 2021 13:22:14 -0800 Subject: [PATCH 4/6] dfc: fix use-after-free When IPA failed to send a QMAP packet, the skb is freed in IPA so accessing the skb after IPA failure will result in use-after-free. Remove the skb access after IPA send failure. Change-Id: Id12894a8f4cc3d7bec717413d48f2430e1c959cf Signed-off-by: Weiyi Chen --- core/dfc_qmap.c | 9 ++++++--- core/rmnet_ctl_client.c | 9 +++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/core/dfc_qmap.c b/core/dfc_qmap.c index f371a0f6e7bf..6afc12cdb15f 100644 --- a/core/dfc_qmap.c +++ b/core/dfc_qmap.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -139,11 +140,13 @@ static void dfc_qmap_send_cmd(struct sk_buff *skb) { trace_dfc_qmap(skb->data, skb->len, false); - if (unlikely(!rmnet_ctl || !rmnet_ctl->send) || - rmnet_ctl->send(rmnet_ctl_handle, skb)) { - pr_err("Failed to send to rmnet ctl\n"); + if (unlikely(!rmnet_ctl || !rmnet_ctl->send)) { kfree_skb(skb); + return; } + + if (rmnet_ctl->send(rmnet_ctl_handle, skb)) + pr_err("Failed to send to rmnet ctl\n"); } static void dfc_qmap_send_inband_ack(struct dfc_qmi_data *dfc, diff --git a/core/rmnet_ctl_client.c b/core/rmnet_ctl_client.c index 4958deac1c75..1ec53dea3f18 100644 --- a/core/rmnet_ctl_client.c +++ b/core/rmnet_ctl_client.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * * RMNET_CTL client handlers * @@ -171,8 +172,10 @@ int rmnet_ctl_send_client(void *handle, struct sk_buff *skb) struct rmnet_ctl_dev *dev; int rc = -EINVAL; - if (client != rcu_dereference(ctl_ep.client)) + if (client != rcu_dereference(ctl_ep.client)) { + kfree_skb(skb); return rc; + } rmnet_ctl_log_info("TX", skb->data, skb->len); @@ -181,11 +184,13 @@ int rmnet_ctl_send_client(void *handle, struct sk_buff *skb) dev = rcu_dereference(ctl_ep.dev); if (dev && dev->xmit) rc = dev->xmit(dev, skb); + else + kfree_skb(skb); rcu_read_unlock(); if (rc) - rmnet_ctl_log_err("TXE", rc, skb->data, skb->len); + rmnet_ctl_log_err("TXE", rc, NULL, 0); return rc; } From c72e4b0e8392a845c70dd37c79775013c5f7355e Mon Sep 17 00:00:00 2001 From: Weiyi Chen Date: Wed, 19 Jan 2022 11:13:43 -0800 Subject: [PATCH 5/6] rmnet_core: fix race condition in rmnet_get_packets In rmnet powersave work, rmnet_get_packets() could access NULL dev pointer if rmnet_dellink() is nullifying the dev pointer at the same time. 18377 [ 72.651710][ T1527] Unable to handle kernel NULL pointer dereference at virtual address 00000000000009d0 18424 [ 72.653999][ T1527] Call trace: 18425 [ 72.654085][ T1527] rmnet_get_packets+0xc4/0x11c [rmnet_core] 18426 [ 72.654170][ T1527] qmi_rmnet_check_stats_2+0x80/0x410 [rmnet_core] 18427 [ 72.654180][ T1527] process_one_work+0x260/0x804 This change Uses the rcu variant of the hlist traversal function in rmnet_get_packet for safe concurrency with the hlist del primitives. It also checks dev pointer before accessing the dev private structure. The existing synchronize rcu call in rmnet_dellink ensures that the ep and dev structure are not freed while being referenced in rcu read session of rmnet_get_packets. Change-Id: Ib5f5aff6e76f9fffd9110a2aa924ad6ab090991f Signed-off-by: Weiyi Chen --- core/rmnet_config.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/rmnet_config.c b/core/rmnet_config.c index b341099c15b7..47cc316bd37c 100644 --- a/core/rmnet_config.c +++ b/core/rmnet_config.c @@ -1,4 +1,5 @@ /* Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -641,6 +642,7 @@ EXPORT_SYMBOL(rmnet_init_qmi_pt); void rmnet_get_packets(void *port, u64 *rx, u64 *tx) { + struct net_device *dev; struct rmnet_priv *priv; struct rmnet_pcpu_stats *ps; unsigned int cpu, start; @@ -654,8 +656,12 @@ void rmnet_get_packets(void *port, u64 *rx, u64 *tx) *tx = 0; *rx = 0; rcu_read_lock(); - hash_for_each(((struct rmnet_port *)port)->muxed_ep, bkt, ep, hlnode) { - priv = netdev_priv(ep->egress_dev); + hash_for_each_rcu(((struct rmnet_port *)port)->muxed_ep, bkt, ep, + hlnode) { + dev = ep->egress_dev; + if (!dev) + continue; + priv = netdev_priv(dev); for_each_possible_cpu(cpu) { ps = per_cpu_ptr(priv->pcpu_stats, cpu); do { From e7cdcf9e03034c4072795201f6d17c04a6cc7c77 Mon Sep 17 00:00:00 2001 From: Kaustubh Pandey Date: Mon, 31 Jan 2022 16:56:19 +0530 Subject: [PATCH 6/6] datarmnet: Remove monaco_go and monaco_go_aon from BOARD_PLATFORM_LIST For wearable line of devices derived from monaco, monaco will be used as TARGET_BOARD_PLATFORM. Change removes others variants which were added to support _go and _go_aon variants. Change-Id: Id3ef3aa94ad0c80701260417d92eecf1b96558dd Signed-off-by: Kaustubh Pandey --- core/Android.mk | 2 -- datarmnet_dlkm_vendor_board.mk | 2 -- 2 files changed, 4 deletions(-) diff --git a/core/Android.mk b/core/Android.mk index 8df2c97d16ef..f358d0b2ee38 100644 --- a/core/Android.mk +++ b/core/Android.mk @@ -2,8 +2,6 @@ ifneq ($(TARGET_PRODUCT),qssi) RMNET_CORE_DLKM_PLATFORMS_LIST := lahaina RMNET_CORE_DLKM_PLATFORMS_LIST += holi RMNET_CORE_DLKM_PLATFORMS_LIST += monaco -RMNET_CORE_DLKM_PLATFORMS_LIST += monaco_go -RMNET_CORE_DLKM_PLATFORMS_LIST += monaco_go_aon ifeq ($(call is-board-platform-in-list, $(RMNET_CORE_DLKM_PLATFORMS_LIST)),true) #Make file to create RMNET_CORE DLKM diff --git a/datarmnet_dlkm_vendor_board.mk b/datarmnet_dlkm_vendor_board.mk index 60a81a7d351b..3eb26a9fc94d 100644 --- a/datarmnet_dlkm_vendor_board.mk +++ b/datarmnet_dlkm_vendor_board.mk @@ -2,8 +2,6 @@ DATA_DLKM_BOARD_PLATFORMS_LIST := lahaina DATA_DLKM_BOARD_PLATFORMS_LIST += holi DATA_DLKM_BOARD_PLATFORMS_LIST += monaco -DATA_DLKM_BOARD_PLATFORMS_LIST += monaco_go -DATA_DLKM_BOARD_PLATFORMS_LIST += monaco_go_aon ifneq ($(TARGET_BOARD_AUTO),true) ifeq ($(call is-board-platform-in-list,$(DATA_DLKM_BOARD_PLATFORMS_LIST)),true) BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/rmnet_core.ko