Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73818d73 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drivers: add RmNet snapshot"

parents d3394d4f 14eee844
Loading
Loading
Loading
Loading
+171 −20
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2013-2018, 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
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * RMNET configuration engine
 *
@@ -21,6 +13,9 @@
#include "rmnet_handlers.h"
#include "rmnet_vnd.h"
#include "rmnet_private.h"
#include "rmnet_map.h"
#include <soc/qcom/rmnet_qmi.h>
#include <soc/qcom/qmi_rmnet.h>

/* Locking scheme -
 * The shared resource which needs to be protected is realdev->rx_handler_data.
@@ -43,15 +38,17 @@

/* Local Definitions and Declarations */

static const struct nla_policy rmnet_policy[IFLA_RMNET_MAX + 1] = {
static const struct nla_policy rmnet_policy[IFLA_RMNET_MAX + 2] = {
	[IFLA_RMNET_MUX_ID]	= { .type = NLA_U16 },
	[IFLA_RMNET_FLAGS]	= { .len = sizeof(struct ifla_rmnet_flags) },
	[IFLA_VLAN_EGRESS_QOS]	= { .len = sizeof(struct tcmsg) },
};

static int rmnet_is_real_dev_registered(const struct net_device *real_dev)
int rmnet_is_real_dev_registered(const struct net_device *real_dev)
{
	return rcu_access_pointer(real_dev->rx_handler) == rmnet_rx_handler;
}
EXPORT_SYMBOL(rmnet_is_real_dev_registered);

/* Needs rtnl lock */
static struct rmnet_port*
@@ -66,6 +63,9 @@ static int rmnet_unregister_real_device(struct net_device *real_dev,
	if (port->nr_rmnet_devs)
		return -EINVAL;

	rmnet_map_cmd_exit(port);
	rmnet_map_tx_aggregate_exit(port);

	kfree(port);

	netdev_rx_handler_unregister(real_dev);
@@ -97,13 +97,15 @@ static int rmnet_register_real_device(struct net_device *real_dev)
		kfree(port);
		return -EBUSY;
	}

	/* hold on to real dev for MAP data */
	dev_hold(real_dev);

	for (entry = 0; entry < RMNET_MAX_LOGICAL_EP; entry++)
		INIT_HLIST_HEAD(&port->muxed_ep[entry]);

	rmnet_map_tx_aggregate_init(port);
	rmnet_map_cmd_init(port);

	netdev_dbg(real_dev, "registered with rmnet\n");
	return 0;
}
@@ -211,6 +213,7 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head)
		hlist_del_init_rcu(&ep->hlnode);
		rmnet_unregister_bridge(dev, port);
		rmnet_vnd_dellink(mux_id, port, ep);
		synchronize_rcu();
		kfree(ep);
	}
	rmnet_unregister_real_device(real_dev, port);
@@ -234,7 +237,6 @@ static void rmnet_force_unassociate_device(struct net_device *dev)

	port = rmnet_get_port_rtnl(dev);

	rcu_read_lock();
	rmnet_unregister_bridge(dev, port);

	hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
@@ -242,12 +244,14 @@ static void rmnet_force_unassociate_device(struct net_device *dev)
		rmnet_vnd_dellink(ep->mux_id, port, ep);

		hlist_del_init_rcu(&ep->hlnode);
		synchronize_rcu();
		kfree(ep);
	}

	rcu_read_unlock();
	unregister_netdevice_many(&list);

	qmi_rmnet_qmi_exit(port->qmi_info, port);

	rmnet_unregister_real_device(real_dev, port);
}

@@ -281,12 +285,15 @@ static int rmnet_rtnl_validate(struct nlattr *tb[], struct nlattr *data[],
{
	u16 mux_id;

	if (!data || !data[IFLA_RMNET_MUX_ID])
	if (!data) {
		return -EINVAL;

	} else {
		if (data[IFLA_RMNET_MUX_ID]) {
			mux_id = nla_get_u16(data[IFLA_RMNET_MUX_ID]);
			if (mux_id > (RMNET_MAX_LOGICAL_EP - 1))
				return -ERANGE;
		}
	}

	return 0;
}
@@ -329,6 +336,13 @@ static int rmnet_changelink(struct net_device *dev, struct nlattr *tb[],
		port->data_format = flags->flags & flags->mask;
	}

	if (data[IFLA_VLAN_EGRESS_QOS]) {
		struct tcmsg *tcm;

		tcm = nla_data(data[IFLA_VLAN_EGRESS_QOS]);
		qmi_rmnet_change_link(dev, port, tcm);
	}

	return 0;
}

@@ -338,7 +352,8 @@ static size_t rmnet_get_size(const struct net_device *dev)
		/* IFLA_RMNET_MUX_ID */
		nla_total_size(2) +
		/* IFLA_RMNET_FLAGS */
		nla_total_size(sizeof(struct ifla_rmnet_flags));
		nla_total_size(sizeof(struct ifla_rmnet_flags)) +
		nla_total_size(sizeof(struct tcmsg));
}

static int rmnet_fill_info(struct sk_buff *skb, const struct net_device *dev)
@@ -393,6 +408,7 @@ struct rmnet_port *rmnet_get_port(struct net_device *real_dev)
	else
		return NULL;
}
EXPORT_SYMBOL(rmnet_get_port);

struct rmnet_endpoint *rmnet_get_endpoint(struct rmnet_port *port, u8 mux_id)
{
@@ -405,6 +421,7 @@ struct rmnet_endpoint *rmnet_get_endpoint(struct rmnet_port *port, u8 mux_id)

	return NULL;
}
EXPORT_SYMBOL(rmnet_get_endpoint);

int rmnet_add_bridge(struct net_device *rmnet_dev,
		     struct net_device *slave_dev,
@@ -459,6 +476,140 @@ int rmnet_del_bridge(struct net_device *rmnet_dev,
	return 0;
}

#ifdef CONFIG_QCOM_QMI_RMNET
void *rmnet_get_qmi_pt(void *port)
{
	if (port)
		return ((struct rmnet_port *)port)->qmi_info;

	return NULL;
}
EXPORT_SYMBOL(rmnet_get_qmi_pt);

void *rmnet_get_qos_pt(struct net_device *dev)
{
	struct rmnet_priv *priv;

	if (dev) {
		priv = netdev_priv(dev);
		return rcu_dereference(priv->qos_info);
	}

	return NULL;
}
EXPORT_SYMBOL(rmnet_get_qos_pt);

void *rmnet_get_rmnet_port(struct net_device *dev)
{
	struct rmnet_priv *priv;

	if (dev) {
		priv = netdev_priv(dev);
		return (void *)rmnet_get_port(priv->real_dev);
	}

	return NULL;
}
EXPORT_SYMBOL(rmnet_get_rmnet_port);

struct net_device *rmnet_get_rmnet_dev(void *port, u8 mux_id)
{
	struct rmnet_endpoint *ep;

	if (port) {
		ep = rmnet_get_endpoint((struct rmnet_port *)port, mux_id);
		if (ep)
			return ep->egress_dev;
	}

	return NULL;
}
EXPORT_SYMBOL(rmnet_get_rmnet_dev);

void rmnet_reset_qmi_pt(void *port)
{
	if (port)
		((struct rmnet_port *)port)->qmi_info = NULL;
}
EXPORT_SYMBOL(rmnet_reset_qmi_pt);

void rmnet_init_qmi_pt(void *port, void *qmi)
{
	if (port)
		((struct rmnet_port *)port)->qmi_info = qmi;
}
EXPORT_SYMBOL(rmnet_init_qmi_pt);

void rmnet_get_packets(void *port, u64 *rx, u64 *tx)
{
	struct rmnet_priv *priv;
	struct rmnet_pcpu_stats *ps;
	unsigned int cpu, start;

	struct rmnet_endpoint *ep;
	unsigned long bkt;

	if (!port || !tx || !rx)
		return;

	*tx = 0;
	*rx = 0;
	hash_for_each(((struct rmnet_port *)port)->muxed_ep, bkt, ep, hlnode) {
		priv = netdev_priv(ep->egress_dev);
		for_each_possible_cpu(cpu) {
			ps = per_cpu_ptr(priv->pcpu_stats, cpu);
			do {
				start = u64_stats_fetch_begin_irq(&ps->syncp);
				*tx += ps->stats.tx_pkts;
				*rx += ps->stats.rx_pkts;
			} while (u64_stats_fetch_retry_irq(&ps->syncp, start));
		}
	}
}
EXPORT_SYMBOL(rmnet_get_packets);

void  rmnet_set_powersave_format(void *port)
{
	if (!port)
		return;
	((struct rmnet_port *)port)->data_format |= RMNET_INGRESS_FORMAT_PS;
}
EXPORT_SYMBOL(rmnet_set_powersave_format);

void  rmnet_clear_powersave_format(void *port)
{
	if (!port)
		return;
	((struct rmnet_port *)port)->data_format &= ~RMNET_INGRESS_FORMAT_PS;
}
EXPORT_SYMBOL(rmnet_clear_powersave_format);

void rmnet_enable_all_flows(void *port)
{
	struct rmnet_endpoint *ep;
	unsigned long bkt;

	if (unlikely(!port))
		return;

	rcu_read_lock();
	hash_for_each_rcu(((struct rmnet_port *)port)->muxed_ep,
			  bkt, ep, hlnode) {
		qmi_rmnet_enable_all_flows(ep->egress_dev);
	}
	rcu_read_unlock();
}
EXPORT_SYMBOL(rmnet_enable_all_flows);

int rmnet_get_powersave_notif(void *port)
{
	if (!port)
		return 0;
	return ((struct rmnet_port *)port)->data_format & RMNET_FORMAT_PS_NOTIF;
}
EXPORT_SYMBOL(rmnet_get_powersave_notif);
#endif

/* Startup/Shutdown */

static int __init rmnet_init(void)
+53 −9
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2013-2014, 2016-2018 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
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * RMNET Data configuration engine
 *
@@ -27,6 +19,20 @@ struct rmnet_endpoint {
	struct hlist_node hlnode;
};

struct rmnet_port_priv_stats {
	u64 dl_hdr_last_seq;
	u64 dl_hdr_last_bytes;
	u64 dl_hdr_last_pkts;
	u64 dl_hdr_last_flows;
	u64 dl_hdr_count;
	u64 dl_hdr_total_bytes;
	u64 dl_hdr_total_pkts;
	u64 dl_hdr_avg_bytes;
	u64 dl_hdr_avg_pkts;
	u64 dl_trl_last_seq;
	u64 dl_trl_count;
};

/* One instance of this structure is instantiated for each real_dev associated
 * with rmnet.
 */
@@ -37,6 +43,27 @@ struct rmnet_port {
	u8 rmnet_mode;
	struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP];
	struct net_device *bridge_ep;
	void *rmnet_perf;

	u16 egress_agg_size;
	u16 egress_agg_count;

	/* Protect aggregation related elements */
	spinlock_t agg_lock;

	struct sk_buff *agg_skb;
	int agg_state;
	u8 agg_count;
	struct timespec agg_time;
	struct timespec agg_last;
	struct hrtimer hrtimer;

	void *qmi_info;

	/* dl marker elements */
	struct list_head dl_list;
	struct rmnet_port_priv_stats stats;
	int dl_marker_flush;
};

extern struct rtnl_link_ops rmnet_link_ops;
@@ -72,8 +99,25 @@ struct rmnet_priv {
	struct rmnet_pcpu_stats __percpu *pcpu_stats;
	struct gro_cells gro_cells;
	struct rmnet_priv_stats stats;
	void __rcu *qos_info;
};

enum rmnet_trace_func {
	RMNET_MODULE,
	NW_STACK_MODULE,
};

enum rmnet_trace_evt {
	RMNET_DLVR_SKB,
	RMNET_RCV_FROM_PND,
	RMNET_TX_UL_PKT,
	NW_STACK_DEV_Q_XMIT,
	NW_STACK_NAPI_GRO_FLUSH,
	NW_STACK_RX,
	NW_STACK_TX,
};

int rmnet_is_real_dev_registered(const struct net_device *real_dev);
struct rmnet_port *rmnet_get_port(struct net_device *real_dev);
struct rmnet_endpoint *rmnet_get_endpoint(struct rmnet_port *port, u8 mux_id);
int rmnet_add_bridge(struct net_device *rmnet_dev,
+156 −23
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2013-2018, 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
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * RMNET Data ingress/egress handler
 *
@@ -16,19 +8,58 @@
#include <linux/netdevice.h>
#include <linux/netdev_features.h>
#include <linux/if_arp.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/sock.h>
#include <linux/tracepoint.h>
#include "rmnet_private.h"
#include "rmnet_config.h"
#include "rmnet_vnd.h"
#include "rmnet_map.h"
#include "rmnet_handlers.h"
#ifdef CONFIG_QCOM_QMI_HELPERS
#include <soc/qcom/rmnet_qmi.h>
#include <soc/qcom/qmi_rmnet.h>

#endif

#define RMNET_IP_VERSION_4 0x40
#define RMNET_IP_VERSION_6 0x60
#define CREATE_TRACE_POINTS
#include <trace/events/rmnet.h>

EXPORT_TRACEPOINT_SYMBOL(rmnet_shs_low);
EXPORT_TRACEPOINT_SYMBOL(rmnet_shs_high);
EXPORT_TRACEPOINT_SYMBOL(rmnet_shs_err);
EXPORT_TRACEPOINT_SYMBOL(rmnet_shs_wq_low);
EXPORT_TRACEPOINT_SYMBOL(rmnet_shs_wq_high);
EXPORT_TRACEPOINT_SYMBOL(rmnet_shs_wq_err);
EXPORT_TRACEPOINT_SYMBOL(rmnet_perf_low);
EXPORT_TRACEPOINT_SYMBOL(rmnet_perf_high);
EXPORT_TRACEPOINT_SYMBOL(rmnet_perf_err);
EXPORT_TRACEPOINT_SYMBOL(rmnet_low);
EXPORT_TRACEPOINT_SYMBOL(rmnet_high);
EXPORT_TRACEPOINT_SYMBOL(rmnet_err);

/* Helper Functions */

static void rmnet_set_skb_proto(struct sk_buff *skb)
static int rmnet_check_skb_can_gro(struct sk_buff *skb)
{
	switch (skb->protocol) {
	case htons(ETH_P_IP):
		if (ip_hdr(skb)->protocol == IPPROTO_TCP)
			return 0;
		break;
	case htons(ETH_P_IPV6):
		if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
			return 0;
		/* Fall through */
	}

	return -EPROTONOSUPPORT;
}

void rmnet_set_skb_proto(struct sk_buff *skb)
{
	switch (skb->data[0] & 0xF0) {
	case RMNET_IP_VERSION_4:
@@ -42,22 +73,55 @@ static void rmnet_set_skb_proto(struct sk_buff *skb)
		break;
	}
}
EXPORT_SYMBOL(rmnet_set_skb_proto);

/* Shs hook handler */

int (*rmnet_shs_skb_entry)(struct sk_buff *skb,
			   struct rmnet_port *port) __rcu __read_mostly;
EXPORT_SYMBOL(rmnet_shs_skb_entry);

/* Generic handler */

static void
rmnet_deliver_skb(struct sk_buff *skb)
void
rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_port *port)
{
	int (*rmnet_shs_stamp)(struct sk_buff *skb, struct rmnet_port *port);
	struct rmnet_priv *priv = netdev_priv(skb->dev);

	trace_rmnet_low(RMNET_MODULE, RMNET_DLVR_SKB, 0xDEF, 0xDEF,
			0xDEF, 0xDEF, (void *)skb, NULL);
	skb_reset_transport_header(skb);
	skb_reset_network_header(skb);
	rmnet_vnd_rx_fixup(skb, skb->dev);
	rmnet_vnd_rx_fixup(skb->dev, skb->len);

	skb->pkt_type = PACKET_HOST;
	skb_set_mac_header(skb, 0);

	rmnet_shs_stamp = rcu_dereference(rmnet_shs_skb_entry);
	if (rmnet_shs_stamp) {
		rmnet_shs_stamp(skb, port);
		return;
	}

	if (port->data_format & RMNET_INGRESS_FORMAT_DL_MARKER) {
		if (!rmnet_check_skb_can_gro(skb) &&
		    port->dl_marker_flush >= 0) {
			struct napi_struct *napi = get_current_napi_context();

			napi_gro_receive(napi, skb);
			port->dl_marker_flush++;
		} else {
			netif_receive_skb(skb);
		}
	} else {
		if (!rmnet_check_skb_can_gro(skb))
			gro_cells_receive(&priv->gro_cells, skb);
		else
			netif_receive_skb(skb);
	}
}
EXPORT_SYMBOL(rmnet_deliver_skb);

/* MAP handler */

@@ -70,6 +134,11 @@ __rmnet_map_ingress_handler(struct sk_buff *skb,
	u8 mux_id;

	if (RMNET_MAP_GET_CD_BIT(skb)) {
		if (port->data_format & RMNET_INGRESS_FORMAT_DL_MARKER) {
			if (!rmnet_map_flow_command(skb, port, false))
				return;
		}

		if (port->data_format & RMNET_FLAGS_INGRESS_MAP_COMMANDS)
			return rmnet_map_command(skb, port);

@@ -98,19 +167,27 @@ __rmnet_map_ingress_handler(struct sk_buff *skb,
			skb->ip_summed = CHECKSUM_UNNECESSARY;
	}

#ifdef CONFIG_QCOM_QMI_HELPERS
	if (port->data_format & RMNET_INGRESS_FORMAT_PS)
		qmi_rmnet_work_maybe_restart(port);
#endif

	skb_trim(skb, len);
	rmnet_deliver_skb(skb);
	rmnet_deliver_skb(skb, port);
	return;

free_skb:
	kfree_skb(skb);
}

int (*rmnet_perf_deag_entry)(struct sk_buff *skb,
			     struct rmnet_port *port) __rcu __read_mostly;
EXPORT_SYMBOL(rmnet_perf_deag_entry);

static void
rmnet_map_ingress_handler(struct sk_buff *skb,
			  struct rmnet_port *port)
{
	struct sk_buff *skbn;

	if (skb->dev->type == ARPHRD_ETHER) {
		if (pskb_expand_head(skb, ETH_HLEN, 0, GFP_ATOMIC)) {
@@ -122,10 +199,30 @@ rmnet_map_ingress_handler(struct sk_buff *skb,
	}

	if (port->data_format & RMNET_FLAGS_INGRESS_DEAGGREGATION) {
		while ((skbn = rmnet_map_deaggregate(skb, port)) != NULL)
			__rmnet_map_ingress_handler(skbn, port);
		int (*rmnet_perf_core_deaggregate)(struct sk_buff *skb,
						   struct rmnet_port *port);
		/* Deaggregation and freeing of HW originating
		 * buffers is done within here
		 */
		rmnet_perf_core_deaggregate =
					rcu_dereference(rmnet_perf_deag_entry);
		if (rmnet_perf_core_deaggregate) {
			rmnet_perf_core_deaggregate(skb, port);
		} else {
			struct sk_buff *skbn;

			while (skb) {
				struct sk_buff *skb_frag =
						skb_shinfo(skb)->frag_list;

				skb_shinfo(skb)->frag_list = NULL;
				while ((skbn = rmnet_map_deaggregate(skb, port))
					!= NULL)
					__rmnet_map_ingress_handler(skbn, port);
				consume_skb(skb);
				skb = skb_frag;
			}
		}
	} else {
		__rmnet_map_ingress_handler(skb, port);
	}
@@ -151,6 +248,11 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,
			return -ENOMEM;
	}

#ifdef CONFIG_QCOM_QMI_HELPERS
	if (port->data_format & RMNET_INGRESS_FORMAT_PS)
		qmi_rmnet_work_maybe_restart(port);
#endif

	if (port->data_format & RMNET_FLAGS_EGRESS_MAP_CKSUMV4)
		rmnet_map_checksum_uplink_packet(skb, orig_dev);

@@ -160,8 +262,26 @@ static int rmnet_map_egress_handler(struct sk_buff *skb,

	map_header->mux_id = mux_id;

	skb->protocol = htons(ETH_P_MAP);
	if (port->data_format & RMNET_EGRESS_FORMAT_AGGREGATION) {
		int non_linear_skb;

		if (rmnet_map_tx_agg_skip(skb, required_headroom))
			goto done;

		non_linear_skb = (orig_dev->features & NETIF_F_GSO) &&
				 skb_is_nonlinear(skb);

		if (non_linear_skb) {
			if (unlikely(__skb_linearize(skb)))
				goto done;
		}

		rmnet_map_tx_aggregate(skb, port);
		return -EINPROGRESS;
	}

done:
	skb->protocol = htons(ETH_P_MAP);
	return 0;
}

@@ -192,6 +312,8 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
	if (skb->pkt_type == PACKET_LOOPBACK)
		return RX_HANDLER_PASS;

	trace_rmnet_low(RMNET_MODULE, RMNET_RCV_FROM_PND, 0xDEF,
			0xDEF, 0xDEF, 0xDEF, NULL, NULL);
	dev = skb->dev;
	port = rmnet_get_port(dev);

@@ -207,6 +329,7 @@ rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
done:
	return RX_HANDLER_CONSUMED;
}
EXPORT_SYMBOL(rmnet_rx_handler);

/* Modifies packet as per logical endpoint configuration and egress data format
 * for egress device configured in logical endpoint. Packet is then transmitted
@@ -218,7 +341,11 @@ void rmnet_egress_handler(struct sk_buff *skb)
	struct rmnet_port *port;
	struct rmnet_priv *priv;
	u8 mux_id;
	int err;
	u32 skb_len;

	trace_rmnet_low(RMNET_MODULE, RMNET_TX_UL_PKT, 0xDEF, 0xDEF, 0xDEF,
			0xDEF, (void *)skb, NULL);
	sk_pacing_shift_update(skb->sk, 8);

	orig_dev = skb->dev;
@@ -230,10 +357,16 @@ void rmnet_egress_handler(struct sk_buff *skb)
	if (!port)
		goto drop;

	if (rmnet_map_egress_handler(skb, port, mux_id, orig_dev))
	skb_len = skb->len;
	err = rmnet_map_egress_handler(skb, port, mux_id, orig_dev);
	if (err == -ENOMEM) {
		goto drop;
	} else if (err == -EINPROGRESS) {
		rmnet_vnd_tx_fixup(orig_dev, skb_len);
		return;
	}

	rmnet_vnd_tx_fixup(skb, orig_dev);
	rmnet_vnd_tx_fixup(orig_dev, skb_len);

	dev_queue_xmit(skb);
	return;
+6 −11
Original line number Diff line number Diff line
/* Copyright (c) 2013, 2016-2017 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
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2013, 2016-2018 The Linux Foundation. All rights reserved.
 *
 * RMNET Data ingress/egress handler
 *
@@ -19,7 +11,10 @@
#include "rmnet_config.h"

void rmnet_egress_handler(struct sk_buff *skb);

void rmnet_deliver_skb(struct sk_buff *skb, struct rmnet_port *port);
void rmnet_set_skb_proto(struct sk_buff *skb);
rx_handler_result_t _rmnet_map_ingress_handler(struct sk_buff *skb,
					       struct rmnet_port *port);
rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb);

#endif /* _RMNET_HANDLERS_H_ */
+75 −12
Original line number Diff line number Diff line
/* Copyright (c) 2013-2018, 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
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. */

#ifndef _RMNET_MAP_H_
#define _RMNET_MAP_H_
#include "rmnet_config.h"

struct rmnet_map_control_command {
	u8  command_name;
@@ -34,6 +26,8 @@ enum rmnet_map_commands {
	RMNET_MAP_COMMAND_NONE,
	RMNET_MAP_COMMAND_FLOW_DISABLE,
	RMNET_MAP_COMMAND_FLOW_ENABLE,
	RMNET_MAP_COMMAND_FLOW_START = 7,
	RMNET_MAP_COMMAND_FLOW_END = 8,
	/* These should always be the last 2 elements */
	RMNET_MAP_COMMAND_UNKNOWN,
	RMNET_MAP_COMMAND_ENUM_LENGTH
@@ -63,6 +57,60 @@ struct rmnet_map_ul_csum_header {
	u16 csum_enabled:1;
} __aligned(1);

struct rmnet_map_control_command_header {
	u8  command_name;
	u8  cmd_type:2;
	u8  reserved:6;
	u16 reserved2;
	u32 transaction_id;
}  __aligned(1);

struct rmnet_map_flow_info_le {
	__be32 mux_id;
	__be32 flow_id;
	__be32 bytes;
	__be32 pkts;
} __aligned(1);

struct rmnet_map_flow_info_be {
	u32 mux_id;
	u32 flow_id;
	u32 bytes;
	u32 pkts;
} __aligned(1);

struct rmnet_map_dl_ind_hdr {
	union {
		struct {
			u32 seq;
			u32 bytes;
			u32 pkts;
			u32 flows;
			struct rmnet_map_flow_info_le flow[0];
		} le __aligned(1);
		struct {
			__be32 seq;
			__be32 bytes;
			__be32 pkts;
			__be32 flows;
			struct rmnet_map_flow_info_be flow[0];
		} be __aligned(1);
	} __aligned(1);
} __aligned(1);

struct rmnet_map_dl_ind_trl {
	union {
		__be32 seq_be;
		u32 seq_le;
	} __aligned(1);
} __aligned(1);

struct rmnet_map_dl_ind {
	void (*dl_hdr_handler)(struct rmnet_map_dl_ind_hdr *dlhdr);
	void (*dl_trl_handler)(struct rmnet_map_dl_ind_trl *dltrl);
	struct list_head list;
};

#define RMNET_MAP_GET_MUX_ID(Y) (((struct rmnet_map_header *) \
				 (Y)->data)->mux_id)
#define RMNET_MAP_GET_CD_BIT(Y) (((struct rmnet_map_header *) \
@@ -75,6 +123,9 @@ struct rmnet_map_ul_csum_header {
#define RMNET_MAP_GET_LENGTH(Y) (ntohs(((struct rmnet_map_header *) \
					(Y)->data)->pkt_len))

#define RMNET_MAP_DEAGGR_SPACING  64
#define RMNET_MAP_DEAGGR_HEADROOM (RMNET_MAP_DEAGGR_SPACING / 2)

#define RMNET_MAP_COMMAND_REQUEST     0
#define RMNET_MAP_COMMAND_ACK         1
#define RMNET_MAP_COMMAND_UNSUPPORTED 2
@@ -91,5 +142,17 @@ void rmnet_map_command(struct sk_buff *skb, struct rmnet_port *port);
int rmnet_map_checksum_downlink_packet(struct sk_buff *skb, u16 len);
void rmnet_map_checksum_uplink_packet(struct sk_buff *skb,
				      struct net_device *orig_dev);

int rmnet_map_tx_agg_skip(struct sk_buff *skb, int offset);
void rmnet_map_tx_aggregate(struct sk_buff *skb, struct rmnet_port *port);
void rmnet_map_tx_aggregate_init(struct rmnet_port *port);
void rmnet_map_tx_aggregate_exit(struct rmnet_port *port);
int rmnet_map_flow_command(struct sk_buff *skb,
			   struct rmnet_port *port,
			   bool rmnet_perf);
void rmnet_map_cmd_init(struct rmnet_port *port);
int rmnet_map_dl_ind_register(struct rmnet_port *port,
			      struct rmnet_map_dl_ind *dl_ind);
int rmnet_map_dl_ind_deregister(struct rmnet_port *port,
				struct rmnet_map_dl_ind *dl_ind);
void rmnet_map_cmd_exit(struct rmnet_port *port);
#endif /* _RMNET_MAP_H_ */
Loading