浏览代码

datarmnet: Fastforward core from data-kernel.lnx.1.1 to data-kernel.lnx.1.2

Catches up to commit b4d76675a6feeb57f7188d5354e1cf82b7adb012.

Change-Id: Ib1f00be9799712bd4ab0381cde648287f98a61a1
Signed-off-by: Conner Huff <[email protected]>
Conner Huff 4 年之前
父节点
当前提交
4fe7a4add4
共有 15 个文件被更改,包括 202 次插入61 次删除
  1. 4 1
      core/Makefile
  2. 1 0
      core/dfc.h
  3. 12 4
      core/qmi_rmnet.c
  4. 5 1
      core/qmi_rmnet_i.h
  5. 12 2
      core/rmnet_config.c
  6. 17 3
      core/rmnet_config.h
  7. 72 9
      core/rmnet_descriptor.c
  8. 4 2
      core/rmnet_descriptor.h
  9. 34 18
      core/rmnet_handlers.c
  10. 18 6
      core/rmnet_map_data.c
  11. 2 3
      core/rmnet_trace.h
  12. 10 9
      core/rmnet_vnd.c
  13. 2 1
      core/rmnet_vnd.h
  14. 1 0
      core/wda.h
  15. 8 2
      core/wda_qmi.c

+ 4 - 1
core/Makefile

@@ -30,6 +30,9 @@ rmnet_ctl-y += 		rmnet_ctl_client.o \
 
 KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
 
+KBUILD_OPTIONS := RMNET_CORE_ROOT=$(PWD)
+KBUILD_OPTIONS += MODNAME?=rmnet_core
+
 all:
 	$(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS)
 
@@ -37,4 +40,4 @@ modules_install:
 	$(MAKE) -C $(KERNEL_SRC) M=$(M) modules_install
 
 clean:
-	$(MAKE) -C $(KERNEL_SRC) M=$(M) clean
+	$(MAKE) -C $(KERNEL_SRC) M=$(M) clean

+ 1 - 0
core/dfc.h

@@ -13,6 +13,7 @@
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM dfc
 #undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../../../vendor/qcom/opensource/datarmnet/core
 #ifdef RMNET_LA_PLATFORM
 #define TRACE_INCLUDE_PATH ../../../../vendor/qcom/opensource/datarmnet/core
 #elif RMNET_TRACE_INCLUDE_LE

+ 12 - 4
core/qmi_rmnet.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2021, The Linux Foundation. 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
@@ -11,6 +11,7 @@
  * GNU General Public License for more details.
  */
 #include <linux/soc/qcom/qmi.h>
+
 #include "qmi_rmnet_i.h"
 #include "qmi_rmnet.h"
 #include "rmnet_qmi.h"
@@ -707,6 +708,7 @@ void qmi_rmnet_change_link(struct net_device *dev, void *port, void *tcm_pt)
 {
 	struct qmi_info *qmi = (struct qmi_info *)rmnet_get_qmi_pt(port);
 	struct tcmsg *tcm = (struct tcmsg *)tcm_pt;
+	void *wda_data = NULL;
 
 	switch (tcm->tcm_family) {
 	case NLMSG_FLOW_ACTIVATE:
@@ -749,6 +751,11 @@ void qmi_rmnet_change_link(struct net_device *dev, void *port, void *tcm_pt)
 			return;
 		if (tcm->tcm_handle == 0) { /* instance 0 */
 			rmnet_clear_powersave_format(port);
+			if (qmi->wda_client)
+				wda_data = qmi->wda_client;
+			else if (qmi->wda_pending)
+				wda_data = qmi->wda_pending;
+			wda_qmi_client_release(wda_data);
 			qmi_rmnet_work_exit(port);
 		}
 		qmi_rmnet_delete_client(port, qmi, tcm);
@@ -779,13 +786,14 @@ void qmi_rmnet_qmi_exit(void *qmi_pt, void *port)
 
 	ASSERT_RTNL();
 
-	qmi_rmnet_work_exit(port);
-
 	if (qmi->wda_client)
 		data = qmi->wda_client;
 	else if (qmi->wda_pending)
 		data = qmi->wda_pending;
 
+	wda_qmi_client_release(data);
+	qmi_rmnet_work_exit(port);
+
 	if (data) {
 		wda_qmi_client_exit(data);
 		qmi->wda_client = NULL;
@@ -1245,7 +1253,7 @@ void qmi_rmnet_work_init(void *port)
 		return;
 
 	rmnet_ps_wq = alloc_workqueue("rmnet_powersave_work",
-					WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1);
+				      WQ_CPU_INTENSIVE, 1);
 
 	if (!rmnet_ps_wq)
 		return;

+ 5 - 1
core/qmi_rmnet_i.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2021, The Linux Foundation. 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
@@ -224,6 +224,7 @@ wda_qmi_client_init(void *port, struct svc_info *psvc, struct qmi_info *qmi);
 void wda_qmi_client_exit(void *wda_data);
 int wda_set_powersave_mode(void *wda_data, u8 enable);
 void qmi_rmnet_flush_ps_wq(void);
+void wda_qmi_client_release(void *wda_data);
 #else
 static inline int
 wda_qmi_client_init(void *port, struct svc_info *psvc, struct qmi_info *qmi)
@@ -242,5 +243,8 @@ static inline int wda_set_powersave_mode(void *wda_data, u8 enable)
 static inline void qmi_rmnet_flush_ps_wq(void)
 {
 }
+static inline void wda_qmi_client_release(void *wda_data)
+{
+}
 #endif
 #endif /*_RMNET_QMI_I_H*/

+ 12 - 2
core/rmnet_config.c

@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2021, The Linux Foundation. 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
@@ -30,6 +30,9 @@
 #define CONFIG_QTI_QMI_DFC  1
 #define CONFIG_QTI_QMI_POWER_COLLAPSE 1
 
+#define QMAP_SHS_MASK 0xFF
+#define QMAP_SHS_PKT_LIMIT 200
+
 /* Locking scheme -
  * The shared resource which needs to be protected is realdev->rx_handler_data.
  * For the writer path, this is using rtnl_lock(). The writer paths are
@@ -122,6 +125,11 @@ static int rmnet_register_real_device(struct net_device *real_dev)
 		return -ENOMEM;
 
 	port->dev = real_dev;
+	port->phy_shs_cfg.config = RMNET_SHS_NO_DLMKR |	RMNET_SHS_NO_PSH |
+				   RMNET_SHS_STMP_ALL;
+	port->phy_shs_cfg.map_mask = QMAP_SHS_MASK;
+	port->phy_shs_cfg.max_pkts = QMAP_SHS_PKT_LIMIT;
+
 	rc = netdev_rx_handler_register(real_dev, rmnet_rx_handler, port);
 	if (rc) {
 		kfree(port);
@@ -331,7 +339,9 @@ static int rmnet_config_notify_cb(struct notifier_block *nb,
 		netdev_dbg(dev, "Kernel unregister\n");
 		rmnet_force_unassociate_device(dev);
 		break;
-
+	case NETDEV_DOWN:
+		rmnet_vnd_reset_mac_addr(dev);
+		break;
 	default:
 		break;
 	}

+ 17 - 3
core/rmnet_config.h

@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, 2016-2020 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2014, 2016-2021 The Linux Foundation. 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
@@ -22,6 +22,19 @@
 #define RMNET_MAX_LOGICAL_EP 255
 #define RMNET_MAX_VEID 4
 
+#define RMNET_SHS_STMP_ALL BIT(0)
+#define RMNET_SHS_NO_PSH BIT(1)
+#define RMNET_SHS_NO_DLMKR BIT(2)
+
+struct rmnet_shs_clnt_s {
+	u16 config;
+	u16 map_mask;
+	u16 max_pkts;
+	union {
+		struct rmnet_port *port;
+	} info;
+};
+
 struct rmnet_endpoint {
 	u8 mux_id;
 	struct net_device *egress_dev;
@@ -96,6 +109,9 @@ struct rmnet_port {
 	struct list_head dl_list;
 	struct rmnet_port_priv_stats stats;
 	int dl_marker_flush;
+	/* Port Config for shs */
+	struct rmnet_shs_clnt_s shs_cfg;
+	struct rmnet_shs_clnt_s phy_shs_cfg;
 
 	/* Descriptor pool */
 	spinlock_t desc_pool_lock;
@@ -175,7 +191,6 @@ enum rmnet_dl_marker_prio {
 	RMNET_SHS,
 };
 
-#ifdef CONFIG_FTRACE
 enum rmnet_trace_func {
 	RMNET_MODULE,
 	NW_STACK_MODULE,
@@ -190,7 +205,6 @@ enum rmnet_trace_evt {
 	NW_STACK_RX,
 	NW_STACK_TX,
 };
-#endif
 
 int rmnet_is_real_dev_registered(const struct net_device *real_dev);
 struct rmnet_port *rmnet_get_port(struct net_device *real_dev);

+ 72 - 9
core/rmnet_descriptor.c

@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2021, The Linux Foundation. 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
@@ -340,7 +340,6 @@ int rmnet_frag_ipv6_skip_exthdr(struct rmnet_frag_descriptor *frag_desc,
 		if (!hp)
 			return -EINVAL;
 
-		hp = rmnet_frag_data_ptr(frag_desc) + start;
 		if (nexthdr == NEXTHDR_FRAGMENT) {
 			u32 off = offsetof(struct frag_hdr, frag_off);
 			__be16 *fp, __fp;
@@ -559,20 +558,36 @@ int rmnet_frag_flow_command(struct rmnet_frag_descriptor *frag_desc,
 }
 EXPORT_SYMBOL(rmnet_frag_flow_command);
 
-static int rmnet_frag_deaggregate_one(struct skb_shared_info *shinfo,
+static int rmnet_frag_deaggregate_one(struct sk_buff *skb,
 				      struct rmnet_port *port,
 				      struct list_head *list,
 				      u32 start_frag)
 {
+	struct skb_shared_info *shinfo = skb_shinfo(skb);
 	struct rmnet_frag_descriptor *frag_desc;
-	struct rmnet_map_header *maph;
+	struct rmnet_map_header *maph, __maph;
 	skb_frag_t *frag;
 	u32 i;
 	u32 pkt_len;
 	int rc;
 
 	frag = &shinfo->frags[start_frag];
-	maph = skb_frag_address(frag);
+	/* Grab the QMAP header. Careful, as there's no guarantee that it's
+	 * continugous!
+	 */
+	if (likely(skb_frag_size(frag) >= sizeof(*maph))) {
+		maph = skb_frag_address(frag);
+	} else {
+		/* The header's split across pages. We can rebuild it.
+		 * Probably not faster or stronger than before. But certainly
+		 * more linear.
+		 */
+		if (skb_copy_bits(skb, 0, &__maph, sizeof(__maph)) < 0)
+			return -1;
+
+		maph = &__maph;
+	}
+
 	pkt_len = ntohs(maph->pkt_len);
 	/* Catch empty frames */
 	if (!pkt_len)
@@ -591,9 +606,19 @@ static int rmnet_frag_deaggregate_one(struct skb_shared_info *shinfo,
 		u32 hsize = 0;
 		u8 type;
 
-		type = ((struct rmnet_map_v5_coal_header *)
-			(maph + 1))->header_type;
-		switch (type) {
+		/* Check the type. This seems like should be overkill for less
+		 * than a single byte, doesn't it?
+		 */
+		if (likely(skb_frag_size(frag) >= sizeof(*maph) + 1)) {
+			type = *((u8 *)maph + sizeof(*maph));
+		} else {
+			if (skb_copy_bits(skb, sizeof(*maph), &type,
+					  sizeof(type)) < 0)
+				return -1;
+		}
+
+		/* Type only uses the first 7 bits */
+		switch ((type & 0xFE) >> 1) {
 		case RMNET_MAP_HEADER_TYPE_COALESCING:
 			hsize = sizeof(struct rmnet_map_v5_coal_header);
 			break;
@@ -648,7 +673,7 @@ void rmnet_frag_deaggregate(struct sk_buff *skb, struct rmnet_port *port,
 	int rc;
 
 	while (i < shinfo->nr_frags) {
-		rc = rmnet_frag_deaggregate_one(shinfo, port, list, i);
+		rc = rmnet_frag_deaggregate_one(skb, port, list, i);
 		if (rc < 0)
 			return;
 
@@ -824,6 +849,16 @@ skip_frags:
 		th->seq = frag_desc->tcp_seq;
 	}
 
+	if (frag_desc->tcp_flags_set) {
+		struct tcphdr *th;
+		__be16 *flags;
+
+		th = (struct tcphdr *)
+		     (rmnet_map_data_ptr(head_skb) + frag_desc->ip_len);
+		flags = (__be16 *)&tcp_flag_word(th);
+		*flags = frag_desc->tcp_flags;
+	}
+
 	/* Handle csum offloading */
 	if (frag_desc->csum_valid && frag_desc->hdrs_valid) {
 		/* Set the partial checksum information */
@@ -959,6 +994,24 @@ static void __rmnet_frag_segment_data(struct rmnet_frag_descriptor *coal_desc,
 		new_desc->tcp_seq_set = 1;
 		new_desc->tcp_seq = htonl(ntohl(th->seq) +
 					  coal_desc->data_offset);
+
+		/* Don't allow any dangerous flags to appear in any segments
+		 * other than the last.
+		 */
+		if (th->fin || th->psh) {
+			if (offset + dlen < coal_desc->len) {
+				__be32 flag_word = tcp_flag_word(th);
+
+				/* Clear the FIN and PSH flags from this
+				 * segment.
+				 */
+				flag_word &= ~TCP_FLAG_FIN;
+				flag_word &= ~TCP_FLAG_PSH;
+
+				new_desc->tcp_flags_set = 1;
+				new_desc->tcp_flags = *((__be16 *)&flag_word);
+			}
+		}
 	} else if (coal_desc->trans_proto == IPPROTO_UDP) {
 		struct udphdr *uh, __uh;
 
@@ -1005,6 +1058,13 @@ static bool rmnet_frag_validate_csum(struct rmnet_frag_descriptor *frag_desc)
 	__wsum csum;
 	__sum16 pseudo;
 
+	/* Keep analysis tools happy, since they will see that
+	 * rmnet_frag_data_ptr() could return NULL. It can't in this case,
+	 * since we can't get this far otherwise...
+	 */
+	if (unlikely(!data))
+		return false;
+
 	datagram_len = frag_desc->len - frag_desc->ip_len;
 	if (frag_desc->ip_proto == 4) {
 		struct iphdr *iph = (struct iphdr *)data;
@@ -1061,6 +1121,9 @@ rmnet_frag_segment_coal_data(struct rmnet_frag_descriptor *coal_desc,
 	 * for it.
 	*/
 	version = rmnet_frag_data_ptr(coal_desc);
+	if (unlikely(!version))
+		return;
+
 	if ((*version & 0xF0) == 0x40) {
 		struct iphdr *iph, __iph;
 

+ 4 - 2
core/rmnet_descriptor.h

@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2021, The Linux Foundation. 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
@@ -40,6 +40,7 @@ struct rmnet_frag_descriptor {
 	u32 hash;
 	__be32 tcp_seq;
 	__be16 ip_id;
+	__be16 tcp_flags;
 	u16 data_offset;
 	u16 gso_size;
 	u16 gso_segs;
@@ -53,7 +54,8 @@ struct rmnet_frag_descriptor {
 	   ip_id_set:1,
 	   tcp_seq_set:1,
 	   flush_shs:1,
-	   reserved:3;
+	   tcp_flags_set:1,
+	   reserved:2;
 };
 
 /* Descriptor management */

+ 34 - 18
core/rmnet_handlers.c

@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2021, The Linux Foundation. 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
@@ -32,8 +32,6 @@
 
 #define RMNET_IP_VERSION_4 0x40
 #define RMNET_IP_VERSION_6 0x60
-
-#ifdef CONFIG_FTRACE
 #define CREATE_TRACE_POINTS
 #include "rmnet_trace.h"
 
@@ -52,7 +50,8 @@ EXPORT_TRACEPOINT_SYMBOL(rmnet_err);
 EXPORT_TRACEPOINT_SYMBOL(rmnet_freq_update);
 EXPORT_TRACEPOINT_SYMBOL(rmnet_freq_reset);
 EXPORT_TRACEPOINT_SYMBOL(rmnet_freq_boost);
-#endif
+
+
 
 /* Helper Functions */
 
@@ -89,12 +88,17 @@ EXPORT_SYMBOL(rmnet_slow_start_on);
 
 /* Shs hook handler */
 int (*rmnet_shs_skb_entry)(struct sk_buff *skb,
-			   struct rmnet_port *port) __rcu __read_mostly;
+			   struct rmnet_shs_clnt_s *cfg) __rcu __read_mostly;
 EXPORT_SYMBOL(rmnet_shs_skb_entry);
 
+int (*rmnet_shs_switch)(struct sk_buff *skb,
+			   struct rmnet_shs_clnt_s *cfg) __rcu __read_mostly;
+EXPORT_SYMBOL(rmnet_shs_switch);
+
+
 /* Shs hook handler for work queue*/
 int (*rmnet_shs_skb_entry_wq)(struct sk_buff *skb,
-			      struct rmnet_port *port) __rcu __read_mostly;
+			      struct rmnet_shs_clnt_s *cfg) __rcu __read_mostly;
 EXPORT_SYMBOL(rmnet_shs_skb_entry_wq);
 
 /* Generic handler */
@@ -102,12 +106,11 @@ EXPORT_SYMBOL(rmnet_shs_skb_entry_wq);
 void
 rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_port *port)
 {
-	int (*rmnet_shs_stamp)(struct sk_buff *skb, struct rmnet_port *port);
+	int (*rmnet_shs_stamp)(struct sk_buff *skb,
+			       struct rmnet_shs_clnt_s *cfg);
 
-#ifdef CONFIG_FTRACE
 	trace_rmnet_low(RMNET_MODULE, RMNET_DLVR_SKB, 0xDEF, 0xDEF,
 			0xDEF, 0xDEF, (void *)skb, NULL);
-#endif
 	skb_reset_transport_header(skb);
 	skb_reset_network_header(skb);
 	rmnet_vnd_rx_fixup(skb->dev, skb->len);
@@ -118,7 +121,7 @@ rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_port *port)
 	rcu_read_lock();
 	rmnet_shs_stamp = rcu_dereference(rmnet_shs_skb_entry);
 	if (rmnet_shs_stamp) {
-		rmnet_shs_stamp(skb, port);
+		rmnet_shs_stamp(skb, &port->shs_cfg);
 		rcu_read_unlock();
 		return;
 	}
@@ -133,13 +136,12 @@ void
 rmnet_deliver_skb_wq(struct sk_buff *skb, struct rmnet_port *port,
 		     enum rmnet_packet_context ctx)
 {
-	int (*rmnet_shs_stamp)(struct sk_buff *skb, struct rmnet_port *port);
+	int (*rmnet_shs_stamp)(struct sk_buff *skb,
+			       struct rmnet_shs_clnt_s *cfg);
 	struct rmnet_priv *priv = netdev_priv(skb->dev);
 
-#ifdef CONFIG_FTRACE
 	trace_rmnet_low(RMNET_MODULE, RMNET_DLVR_SKB, 0xDEF, 0xDEF,
 			0xDEF, 0xDEF, (void *)skb, NULL);
-#endif
 	skb_reset_transport_header(skb);
 	skb_reset_network_header(skb);
 	rmnet_vnd_rx_fixup(skb->dev, skb->len);
@@ -154,7 +156,7 @@ rmnet_deliver_skb_wq(struct sk_buff *skb, struct rmnet_port *port,
 	rmnet_shs_stamp = (!ctx) ? rcu_dereference(rmnet_shs_skb_entry) :
 				   rcu_dereference(rmnet_shs_skb_entry_wq);
 	if (rmnet_shs_stamp) {
-		rmnet_shs_stamp(skb, port);
+		rmnet_shs_stamp(skb, &port->shs_cfg);
 		rcu_read_unlock();
 		return;
 	}
@@ -393,6 +395,8 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
 	struct sk_buff *skb = *pskb;
 	struct rmnet_port *port;
 	struct net_device *dev;
+	int (*rmnet_core_shs_switch)(struct sk_buff *skb,
+				     struct rmnet_shs_clnt_s *cfg);
 
 	if (!skb)
 		goto done;
@@ -400,15 +404,29 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
 	if (skb->pkt_type == PACKET_LOOPBACK)
 		return RX_HANDLER_PASS;
 
-#ifdef CONFIG_FTRACE
 	trace_rmnet_low(RMNET_MODULE, RMNET_RCV_FROM_PND, 0xDEF,
 			0xDEF, 0xDEF, 0xDEF, NULL, NULL);
-#endif
 	dev = skb->dev;
 	port = rmnet_get_port(dev);
+	if (unlikely(!port)) {
+		atomic_long_inc(&skb->dev->rx_nohandler);
+		kfree_skb(skb);
+		goto done;
+	}
 
 	switch (port->rmnet_mode) {
 	case RMNET_EPMODE_VND:
+
+		rcu_read_lock();
+		rmnet_core_shs_switch = rcu_dereference(rmnet_shs_switch);
+		if (rmnet_core_shs_switch && !skb->cb[1]) {
+			skb->cb[1] = 1;
+			rmnet_core_shs_switch(skb, &port->phy_shs_cfg);
+			rcu_read_unlock();
+			return RX_HANDLER_CONSUMED;
+		}
+		rcu_read_unlock();
+
 		rmnet_map_ingress_handler(skb, port);
 		break;
 	case RMNET_EPMODE_BRIDGE:
@@ -434,10 +452,8 @@ void rmnet_egress_handler(struct sk_buff *skb)
 	int err;
 	u32 skb_len;
 
-#ifdef CONFIG_FTRACE
 	trace_rmnet_low(RMNET_MODULE, RMNET_TX_UL_PKT, 0xDEF, 0xDEF, 0xDEF,
 			0xDEF, (void *)skb, NULL);
-#endif
 	sk_pacing_shift_update(skb->sk, 8);
 
 	orig_dev = skb->dev;

+ 18 - 6
core/rmnet_map_data.c

@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2021, The Linux Foundation. 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
@@ -744,22 +744,23 @@ __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb,
 	struct rmnet_priv *priv = netdev_priv(coal_skb->dev);
 	__sum16 *check = NULL;
 	u32 alloc_len;
+	u32 dlen = coal_meta->data_len * coal_meta->pkt_count;
+	u32 hlen = coal_meta->ip_len + coal_meta->trans_len;
 	bool zero_csum = false;
 
 	/* We can avoid copying the data if the SKB we got from the lower-level
 	 * drivers was nonlinear.
 	 */
 	if (skb_is_nonlinear(coal_skb))
-		alloc_len = coal_meta->ip_len + coal_meta->trans_len;
+		alloc_len = hlen;
 	else
-		alloc_len = coal_meta->ip_len + coal_meta->trans_len +
-			    (coal_meta->data_len * coal_meta->pkt_count);
+		alloc_len = hlen + dlen;
 
 	skbn = alloc_skb(alloc_len, GFP_ATOMIC);
 	if (!skbn)
 		return;
 
-	skb_reserve(skbn, coal_meta->ip_len + coal_meta->trans_len);
+	skb_reserve(skbn, hlen);
 	rmnet_map_nonlinear_copy(coal_skb, coal_meta, skbn);
 
 	/* Push transport header and update necessary fields */
@@ -771,6 +772,17 @@ __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb,
 
 		th->seq = htonl(ntohl(th->seq) + coal_meta->data_offset);
 		check = &th->check;
+
+		/* Don't allow dangerous flags to be set in any segment but the
+		 * last one.
+		 */
+		if (th->fin || th->psh) {
+			if (hlen + coal_meta->data_offset + dlen <
+			    coal_skb->len) {
+				th->fin = 0;
+				th->psh = 0;
+			}
+		}
 	} else if (coal_meta->trans_proto == IPPROTO_UDP) {
 		struct udphdr *uh = udp_hdr(skbn);
 
@@ -846,7 +858,7 @@ __rmnet_map_segment_coal_skb(struct sk_buff *coal_skb,
 	__skb_queue_tail(list, skbn);
 
 	/* Update meta information to move past the data we just segmented */
-	coal_meta->data_offset += coal_meta->data_len * coal_meta->pkt_count;
+	coal_meta->data_offset += dlen;
 	coal_meta->pkt_id = pkt_id + 1;
 	coal_meta->pkt_count = 0;
 }

+ 2 - 3
core/rmnet_trace.h

@@ -1,10 +1,11 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
  */
-#ifdef CONFIG_FTRACE
+
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM rmnet
 #undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../../../vendor/qcom/opensource/datarmnet/core
 #ifdef RMNET_LA_PLATFORM
 #define TRACE_INCLUDE_PATH ../../../../vendor/qcom/opensource/datarmnet/core
 #elif RMNET_TRACE_INCLUDE_LE
@@ -284,5 +285,3 @@ TP_printk("freq policy update core:%u policy freq floor :%u freq ceil :%u",
 #endif /* _TRACE_RMNET_H */
 
 #include <trace/define_trace.h>
-
-#endif

+ 10 - 9
core/rmnet_vnd.c

@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2020, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2021, The Linux Foundation. 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
@@ -29,10 +29,7 @@
 
 #include "qmi_rmnet.h"
 #include "rmnet_qmi.h"
-
-#ifdef CONFIG_FTRACE
 #include "rmnet_trace.h"
-#endif
 
 /* RX/TX Fixup */
 
@@ -78,9 +75,7 @@ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb,
 					AF_INET : AF_INET6;
 		mark = skb->mark;
 		len = skb->len;
-#ifdef CONFIG_FTRACE
 		trace_rmnet_xmit_skb(skb);
-#endif
 		rmnet_egress_handler(skb);
 		qmi_rmnet_burst_fc_check(dev, ip_type, mark, len);
 		qmi_rmnet_work_maybe_restart(rmnet_get_rmnet_port(dev));
@@ -178,7 +173,6 @@ static u16 rmnet_vnd_select_queue(struct net_device *dev,
 	int boost_trigger = 0;
 	int txq = 0;
 
-#ifdef CONFIG_FTRACE
 	if (trace_print_skb_gso_enabled()) {
 		if (!skb_shinfo(skb)->gso_size)
 			goto skip_trace;
@@ -198,7 +192,6 @@ static u16 rmnet_vnd_select_queue(struct net_device *dev,
 	}
 
 skip_trace:
-#endif
 	if (priv->real_dev)
 		txq = qmi_rmnet_get_queue(dev, skb);
 
@@ -364,7 +357,7 @@ void rmnet_vnd_setup(struct net_device *rmnet_dev)
 	rmnet_dev->netdev_ops = &rmnet_vnd_ops;
 	rmnet_dev->mtu = RMNET_DFLT_PACKET_SIZE;
 	rmnet_dev->needed_headroom = RMNET_NEEDED_HEADROOM;
-	random_ether_addr(rmnet_dev->dev_addr);
+	random_ether_addr(rmnet_dev->perm_addr);
 	rmnet_dev->tx_queue_len = RMNET_TX_QUEUE_LEN;
 
 	/* Raw IP mode */
@@ -451,3 +444,11 @@ int rmnet_vnd_do_flow_control(struct net_device *rmnet_dev, int enable)
 
 	return 0;
 }
+
+void rmnet_vnd_reset_mac_addr(struct net_device *dev)
+{
+	if (dev->netdev_ops != &rmnet_vnd_ops)
+		return;
+
+	random_ether_addr(dev->perm_addr);
+}

+ 2 - 1
core/rmnet_vnd.h

@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, 2020-2021 The Linux Foundation. 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
@@ -27,4 +27,5 @@ void rmnet_vnd_rx_fixup(struct net_device *dev, u32 skb_len);
 void rmnet_vnd_tx_fixup(struct net_device *dev, u32 skb_len);
 u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev);
 void rmnet_vnd_setup(struct net_device *dev);
+void rmnet_vnd_reset_mac_addr(struct net_device *dev);
 #endif /* _RMNET_VND_H_ */

+ 1 - 0
core/wda.h

@@ -5,6 +5,7 @@
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM wda
 #undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../../../vendor/qcom/opensource/datarmnet/core
 #ifdef RMNET_LA_PLATFORM
 #define TRACE_INCLUDE_PATH ../../../../vendor/qcom/opensource/datarmnet/core
 #elif RMNET_TRACE_INCLUDE_LE

+ 8 - 2
core/wda_qmi.c

@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018-2021, The Linux Foundation. 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
@@ -461,7 +461,6 @@ void wda_qmi_client_exit(void *wda_data)
 
 	data->restart_state = 1;
 	trace_wda_client_state_down(0);
-	qmi_handle_release(&data->handle);
 	destroy_workqueue(data->wda_wq);
 	kfree(data);
 }
@@ -471,3 +470,10 @@ int wda_set_powersave_mode(void *wda_data, uint8_t enable)
 	trace_wda_set_powersave_mode(enable);
 	return wda_set_powersave_mode_req(wda_data, enable);
 }
+
+void wda_qmi_client_release(void *wda_data)
+{
+	if (!wda_data)
+		return;
+	qmi_handle_release(&((struct wda_qmi_data *)wda_data)->handle);
+}