net: rmnet_data: Add snapshot of rmnet_data driver

This is a snapshot of the rmnet_data driver taken as of msm-4.4.
commit 5da00923b1544ba ("rmnet_data: Changing format specifier to
%pK").

Additionally, fix some style issues reported by checkpatch.

CRs-Fixed: 1078373
Change-Id: Idb2df22e61803e04a01db64ea5e9d1e93ae92e09
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
This commit is contained in:
Subash Abhinov Kasiviswanathan 2016-10-14 11:01:48 -06:00
commit 2139ce8a5c
24 changed files with 5489 additions and 1 deletions

View file

@ -0,0 +1,47 @@
/* Copyright (c) 2016, 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 config definition
*/
#ifndef _RMNET_CONFIG_H_
#define _RMNET_CONFIG_H_
#include <linux/skbuff.h>
struct rmnet_phys_ep_conf_s {
void (*recycle)(struct sk_buff *); /* Destruct function */
void *config;
};
struct rmnet_map_header_s {
#ifndef RMNET_USE_BIG_ENDIAN_STRUCTS
uint8_t pad_len:6;
uint8_t reserved_bit:1;
uint8_t cd_bit:1;
#else
uint8_t cd_bit:1;
uint8_t reserved_bit:1;
uint8_t pad_len:6;
#endif /* RMNET_USE_BIG_ENDIAN_STRUCTS */
uint8_t mux_id;
uint16_t pkt_len;
} __aligned(1);
#define RMNET_MAP_GET_MUX_ID(Y) (((struct rmnet_map_header_s *)Y->data)->mux_id)
#define RMNET_MAP_GET_CD_BIT(Y) (((struct rmnet_map_header_s *)Y->data)->cd_bit)
#define RMNET_MAP_GET_PAD(Y) (((struct rmnet_map_header_s *)Y->data)->pad_len)
#define RMNET_MAP_GET_CMD_START(Y) ((struct rmnet_map_control_command_s *) \
(Y->data + sizeof(struct rmnet_map_header_s)))
#define RMNET_MAP_GET_LENGTH(Y) (ntohs( \
((struct rmnet_map_header_s *)Y->data)->pkt_len))
#endif /* _RMNET_CONFIG_H_ */

View file

@ -279,6 +279,7 @@ header-y += mroute6.h
header-y += mroute.h
header-y += msdos_fs.h
header-y += msg.h
header-y += msm_rmnet.h
header-y += mtio.h
header-y += nbd.h
header-y += ncp_fs.h
@ -300,6 +301,7 @@ header-y += net.h
header-y += netlink_diag.h
header-y += netlink.h
header-y += netrom.h
header-y += net_map.h
header-y += net_namespace.h
header-y += net_tstamp.h
header-y += nfc.h
@ -365,6 +367,7 @@ header-y += rfkill.h
header-y += rio_cm_cdev.h
header-y += rio_mport_cdev.h
header-y += romfs_fs.h
header-y += rmnet_data.h
header-y += rose.h
header-y += route.h
header-y += rtc.h

View file

@ -103,7 +103,9 @@
#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is less than this value
* then the frame is Ethernet II. Else it is 802.3 */
#define ETH_P_MAP 0xDA1A /* Multiplexing and Aggregation Protocol
* NOT AN OFFICIALLY REGISTERED ID ]
*/
/*
* Non DIX types. Won't clash for 1500 types.
*/

View file

@ -0,0 +1,152 @@
#ifndef _UAPI_MSM_RMNET_H_
#define _UAPI_MSM_RMNET_H_
/* Bitmap macros for RmNET driver operation mode. */
#define RMNET_MODE_NONE (0x00)
#define RMNET_MODE_LLP_ETH (0x01)
#define RMNET_MODE_LLP_IP (0x02)
#define RMNET_MODE_QOS (0x04)
#define RMNET_MODE_MASK (RMNET_MODE_LLP_ETH | \
RMNET_MODE_LLP_IP | \
RMNET_MODE_QOS)
#define RMNET_IS_MODE_QOS(mode) \
((mode & RMNET_MODE_QOS) == RMNET_MODE_QOS)
#define RMNET_IS_MODE_IP(mode) \
((mode & RMNET_MODE_LLP_IP) == RMNET_MODE_LLP_IP)
/* IOCTL commands
* Values chosen to not conflict with other drivers in the ecosystem
*/
#define RMNET_IOCTL_SET_LLP_ETHERNET 0x000089F1 /* Set Ethernet protocol */
#define RMNET_IOCTL_SET_LLP_IP 0x000089F2 /* Set RAWIP protocol */
#define RMNET_IOCTL_GET_LLP 0x000089F3 /* Get link protocol */
#define RMNET_IOCTL_SET_QOS_ENABLE 0x000089F4 /* Set QoS header enabled */
#define RMNET_IOCTL_SET_QOS_DISABLE 0x000089F5 /* Set QoS header disabled*/
#define RMNET_IOCTL_GET_QOS 0x000089F6 /* Get QoS header state */
#define RMNET_IOCTL_GET_OPMODE 0x000089F7 /* Get operation mode */
#define RMNET_IOCTL_OPEN 0x000089F8 /* Open transport port */
#define RMNET_IOCTL_CLOSE 0x000089F9 /* Close transport port */
#define RMNET_IOCTL_FLOW_ENABLE 0x000089FA /* Flow enable */
#define RMNET_IOCTL_FLOW_DISABLE 0x000089FB /* Flow disable */
#define RMNET_IOCTL_FLOW_SET_HNDL 0x000089FC /* Set flow handle */
#define RMNET_IOCTL_EXTENDED 0x000089FD /* Extended IOCTLs */
/* RmNet Data Required IOCTLs */
#define RMNET_IOCTL_GET_SUPPORTED_FEATURES 0x0000 /* Get features */
#define RMNET_IOCTL_SET_MRU 0x0001 /* Set MRU */
#define RMNET_IOCTL_GET_MRU 0x0002 /* Get MRU */
#define RMNET_IOCTL_GET_EPID 0x0003 /* Get endpoint ID */
#define RMNET_IOCTL_GET_DRIVER_NAME 0x0004 /* Get driver name */
#define RMNET_IOCTL_ADD_MUX_CHANNEL 0x0005 /* Add MUX ID */
#define RMNET_IOCTL_SET_EGRESS_DATA_FORMAT 0x0006 /* Set EDF */
#define RMNET_IOCTL_SET_INGRESS_DATA_FORMAT 0x0007 /* Set IDF */
#define RMNET_IOCTL_SET_AGGREGATION_COUNT 0x0008 /* Set agg count */
#define RMNET_IOCTL_GET_AGGREGATION_COUNT 0x0009 /* Get agg count */
#define RMNET_IOCTL_SET_AGGREGATION_SIZE 0x000A /* Set agg size */
#define RMNET_IOCTL_GET_AGGREGATION_SIZE 0x000B /* Get agg size */
#define RMNET_IOCTL_FLOW_CONTROL 0x000C /* Do flow control */
#define RMNET_IOCTL_GET_DFLT_CONTROL_CHANNEL 0x000D /* For legacy use */
#define RMNET_IOCTL_GET_HWSW_MAP 0x000E /* Get HW/SW map */
#define RMNET_IOCTL_SET_RX_HEADROOM 0x000F /* RX Headroom */
#define RMNET_IOCTL_GET_EP_PAIR 0x0010 /* Endpoint pair */
#define RMNET_IOCTL_SET_QOS_VERSION 0x0011 /* 8/6 byte QoS hdr*/
#define RMNET_IOCTL_GET_QOS_VERSION 0x0012 /* 8/6 byte QoS hdr*/
#define RMNET_IOCTL_GET_SUPPORTED_QOS_MODES 0x0013 /* Get QoS modes */
#define RMNET_IOCTL_SET_SLEEP_STATE 0x0014 /* Set sleep state */
#define RMNET_IOCTL_SET_XLAT_DEV_INFO 0x0015 /* xlat dev name */
#define RMNET_IOCTL_DEREGISTER_DEV 0x0016 /* Dereg a net dev */
#define RMNET_IOCTL_GET_SG_SUPPORT 0x0017 /* Query sg support*/
/* Return values for the RMNET_IOCTL_GET_SUPPORTED_FEATURES IOCTL */
#define RMNET_IOCTL_FEAT_NOTIFY_MUX_CHANNEL (1<<0)
#define RMNET_IOCTL_FEAT_SET_EGRESS_DATA_FORMAT (1<<1)
#define RMNET_IOCTL_FEAT_SET_INGRESS_DATA_FORMAT (1<<2)
#define RMNET_IOCTL_FEAT_SET_AGGREGATION_COUNT (1<<3)
#define RMNET_IOCTL_FEAT_GET_AGGREGATION_COUNT (1<<4)
#define RMNET_IOCTL_FEAT_SET_AGGREGATION_SIZE (1<<5)
#define RMNET_IOCTL_FEAT_GET_AGGREGATION_SIZE (1<<6)
#define RMNET_IOCTL_FEAT_FLOW_CONTROL (1<<7)
#define RMNET_IOCTL_FEAT_GET_DFLT_CONTROL_CHANNEL (1<<8)
#define RMNET_IOCTL_FEAT_GET_HWSW_MAP (1<<9)
/* Input values for the RMNET_IOCTL_SET_EGRESS_DATA_FORMAT IOCTL */
#define RMNET_IOCTL_EGRESS_FORMAT_MAP (1<<1)
#define RMNET_IOCTL_EGRESS_FORMAT_AGGREGATION (1<<2)
#define RMNET_IOCTL_EGRESS_FORMAT_MUXING (1<<3)
#define RMNET_IOCTL_EGRESS_FORMAT_CHECKSUM (1<<4)
/* Input values for the RMNET_IOCTL_SET_INGRESS_DATA_FORMAT IOCTL */
#define RMNET_IOCTL_INGRESS_FORMAT_MAP (1<<1)
#define RMNET_IOCTL_INGRESS_FORMAT_DEAGGREGATION (1<<2)
#define RMNET_IOCTL_INGRESS_FORMAT_DEMUXING (1<<3)
#define RMNET_IOCTL_INGRESS_FORMAT_CHECKSUM (1<<4)
#define RMNET_IOCTL_INGRESS_FORMAT_AGG_DATA (1<<5)
/* User space may not have this defined. */
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
struct rmnet_ioctl_extended_s {
uint32_t extended_ioctl;
union {
uint32_t data; /* Generic data field for most extended IOCTLs */
/* Return values for
* RMNET_IOCTL_GET_DRIVER_NAME
* RMNET_IOCTL_GET_DFLT_CONTROL_CHANNEL
*/
int8_t if_name[IFNAMSIZ];
/* Input values for the RMNET_IOCTL_ADD_MUX_CHANNEL IOCTL */
struct {
uint32_t mux_id;
int8_t vchannel_name[IFNAMSIZ];
} rmnet_mux_val;
/* Input values for the RMNET_IOCTL_FLOW_CONTROL IOCTL */
struct {
uint8_t flow_mode;
uint8_t mux_id;
} flow_control_prop;
/* Return values for RMNET_IOCTL_GET_EP_PAIR */
struct {
uint32_t consumer_pipe_num;
uint32_t producer_pipe_num;
} ipa_ep_pair;
struct {
uint32_t __data; /* Placeholder for legacy data*/
uint32_t agg_size;
uint32_t agg_count;
} ingress_format;
} u;
};
struct rmnet_ioctl_data_s {
union {
uint32_t operation_mode;
uint32_t tcm_handle;
} u;
};
#define RMNET_IOCTL_QOS_MODE_6 (1<<0)
#define RMNET_IOCTL_QOS_MODE_8 (1<<1)
/* QMI QoS header definition */
struct QMI_QOS_HDR_S {
unsigned char version;
unsigned char flags;
uint32_t flow_id;
} __attribute((__packed__));
/* QMI QoS 8-byte header. */
struct qmi_qos_hdr8_s {
struct QMI_QOS_HDR_S hdr;
uint8_t reserved[2];
} __attribute((__packed__));
#endif /* _UAPI_MSM_RMNET_H_ */

View file

@ -0,0 +1,8 @@
#ifndef _NET_MAP_H_
#define _NET_MAP_H_
#define RMNET_IP_VER_MASK 0xF0
#define RMNET_IPV4 0x40
#define RMNET_IPV6 0x60
#endif /* _NET_MAP_H_ */

View file

@ -0,0 +1,236 @@
/* Copyright (c) 2013-2016, 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 specification
*/
#ifndef _RMNET_DATA_H_
#define _RMNET_DATA_H_
/* Constants */
#define RMNET_LOCAL_LOGICAL_ENDPOINT -1
#define RMNET_EGRESS_FORMAT__RESERVED__ (1<<0)
#define RMNET_EGRESS_FORMAT_MAP (1<<1)
#define RMNET_EGRESS_FORMAT_AGGREGATION (1<<2)
#define RMNET_EGRESS_FORMAT_MUXING (1<<3)
#define RMNET_EGRESS_FORMAT_MAP_CKSUMV3 (1<<4)
#define RMNET_EGRESS_FORMAT_MAP_CKSUMV4 (1<<5)
#define RMNET_INGRESS_FIX_ETHERNET (1<<0)
#define RMNET_INGRESS_FORMAT_MAP (1<<1)
#define RMNET_INGRESS_FORMAT_DEAGGREGATION (1<<2)
#define RMNET_INGRESS_FORMAT_DEMUXING (1<<3)
#define RMNET_INGRESS_FORMAT_MAP_COMMANDS (1<<4)
#define RMNET_INGRESS_FORMAT_MAP_CKSUMV3 (1<<5)
#define RMNET_INGRESS_FORMAT_MAP_CKSUMV4 (1<<6)
/* Netlink API */
#define RMNET_NETLINK_PROTO 31
#define RMNET_MAX_STR_LEN 16
#define RMNET_NL_DATA_MAX_LEN 64
#define RMNET_NETLINK_MSG_COMMAND 0
#define RMNET_NETLINK_MSG_RETURNCODE 1
#define RMNET_NETLINK_MSG_RETURNDATA 2
struct rmnet_nl_msg_s {
uint16_t reserved;
uint16_t message_type;
uint16_t reserved2:14;
uint16_t crd:2;
union {
uint16_t arg_length;
uint16_t return_code;
};
union {
uint8_t data[RMNET_NL_DATA_MAX_LEN];
struct {
uint8_t dev[RMNET_MAX_STR_LEN];
uint32_t flags;
uint16_t agg_size;
uint16_t agg_count;
uint8_t tail_spacing;
} data_format;
struct {
uint8_t dev[RMNET_MAX_STR_LEN];
int32_t ep_id;
uint8_t operating_mode;
uint8_t next_dev[RMNET_MAX_STR_LEN];
} local_ep_config;
struct {
uint32_t id;
uint8_t vnd_name[RMNET_MAX_STR_LEN];
} vnd;
struct {
uint32_t id;
uint32_t map_flow_id;
uint32_t tc_flow_id;
} flow_control;
};
};
enum rmnet_netlink_message_types_e {
/* RMNET_NETLINK_ASSOCIATE_NETWORK_DEVICE - Register RMNET data driver
* on a particular device.
* Args: char[] dev_name: Null terminated ASCII string, max length: 15
* Returns: status code
*/
RMNET_NETLINK_ASSOCIATE_NETWORK_DEVICE,
/* RMNET_NETLINK_UNASSOCIATE_NETWORK_DEVICE - Unregister RMNET data
* driver on a particular
* device.
* Args: char[] dev_name: Null terminated ASCII string, max length: 15
* Returns: status code
*/
RMNET_NETLINK_UNASSOCIATE_NETWORK_DEVICE,
/* RMNET_NETLINK_GET_NETWORK_DEVICE_ASSOCIATED - Get if RMNET data
* driver is registered on a
* particular device.
* Args: char[] dev_name: Null terminated ASCII string, max length: 15
* Returns: 1 if registered, 0 if not
*/
RMNET_NETLINK_GET_NETWORK_DEVICE_ASSOCIATED,
/* RMNET_NETLINK_SET_LINK_EGRESS_DATA_FORMAT - Sets the egress data
* format for a particular
* link.
* Args: uint32_t egress_flags
* char[] dev_name: Null terminated ASCII string, max length: 15
* Returns: status code
*/
RMNET_NETLINK_SET_LINK_EGRESS_DATA_FORMAT,
/* RMNET_NETLINK_GET_LINK_EGRESS_DATA_FORMAT - Gets the egress data
* format for a particular
* link.
* Args: char[] dev_name: Null terminated ASCII string, max length: 15
* Returns: 4-bytes data: uint32_t egress_flags
*/
RMNET_NETLINK_GET_LINK_EGRESS_DATA_FORMAT,
/* RMNET_NETLINK_SET_LINK_INGRESS_DATA_FORMAT - Sets the ingress data
* format for a particular
* link.
* Args: uint32_t ingress_flags
* char[] dev_name: Null terminated ASCII string, max length: 15
* Returns: status code
*/
RMNET_NETLINK_SET_LINK_INGRESS_DATA_FORMAT,
/* RMNET_NETLINK_GET_LINK_INGRESS_DATA_FORMAT - Gets the ingress data
* format for a particular
* link.
* Args: char[] dev_name: Null terminated ASCII string, max length: 15
* Returns: 4-bytes data: uint32_t ingress_flags
*/
RMNET_NETLINK_GET_LINK_INGRESS_DATA_FORMAT,
/* RMNET_NETLINK_SET_LOGICAL_EP_CONFIG - Sets the logical endpoint
* configuration for a particular
* link.
* Args: char[] dev_name: Null terminated ASCII string, max length: 15
* int32_t logical_ep_id, valid values are -1 through 31
* uint8_t rmnet_mode: one of none, vnd, bridged
* char[] egress_dev_name: Egress device if operating in bridge mode
* Returns: status code
*/
RMNET_NETLINK_SET_LOGICAL_EP_CONFIG,
/* RMNET_NETLINK_UNSET_LOGICAL_EP_CONFIG - Un-sets the logical endpoint
* configuration for a particular
* link.
* Args: char[] dev_name: Null terminated ASCII string, max length: 15
* int32_t logical_ep_id, valid values are -1 through 31
* Returns: status code
*/
RMNET_NETLINK_UNSET_LOGICAL_EP_CONFIG,
/* RMNET_NETLINK_GET_LOGICAL_EP_CONFIG - Gets the logical endpoint
* configuration for a particular
* link.
* Args: char[] dev_name: Null terminated ASCII string, max length: 15
* int32_t logical_ep_id, valid values are -1 through 31
* Returns: uint8_t rmnet_mode: one of none, vnd, bridged
* char[] egress_dev_name: Egress device
*/
RMNET_NETLINK_GET_LOGICAL_EP_CONFIG,
/* RMNET_NETLINK_NEW_VND - Creates a new virtual network device node
* Args: int32_t node number
* Returns: status code
*/
RMNET_NETLINK_NEW_VND,
/* RMNET_NETLINK_NEW_VND_WITH_PREFIX - Creates a new virtual network
* device node with the specified
* prefix for the device name
* Args: int32_t node number
* char[] vnd_name - Use as prefix
* Returns: status code
*/
RMNET_NETLINK_NEW_VND_WITH_PREFIX,
/* RMNET_NETLINK_GET_VND_NAME - Gets the string name of a VND from ID
* Args: int32_t node number
* Returns: char[] vnd_name
*/
RMNET_NETLINK_GET_VND_NAME,
/* RMNET_NETLINK_FREE_VND - Removes virtual network device node
* Args: int32_t node number
* Returns: status code
*/
RMNET_NETLINK_FREE_VND,
/* RMNET_NETLINK_ADD_VND_TC_FLOW - Add flow control handle on VND
* Args: int32_t node number
* uint32_t MAP Flow Handle
* uint32_t TC Flow Handle
* Returns: status code
*/
RMNET_NETLINK_ADD_VND_TC_FLOW,
/* RMNET_NETLINK_DEL_VND_TC_FLOW - Removes flow control handle on VND
* Args: int32_t node number
* uint32_t MAP Flow Handle
* Returns: status code
*/
RMNET_NETLINK_DEL_VND_TC_FLOW
};
enum rmnet_config_endpoint_modes_e {
/* Pass the frame up the stack with no modifications to skb->dev */
RMNET_EPMODE_NONE,
/* Replace skb->dev to a virtual rmnet device and pass up the stack */
RMNET_EPMODE_VND,
/* Pass the frame directly to another device with dev_queue_xmit(). */
RMNET_EPMODE_BRIDGE,
/* Must be the last item in the list */
RMNET_EPMODE_LENGTH
};
enum rmnet_config_return_codes_e {
RMNET_CONFIG_OK,
RMNET_CONFIG_UNKNOWN_MESSAGE,
RMNET_CONFIG_UNKNOWN_ERROR,
RMNET_CONFIG_NOMEM,
RMNET_CONFIG_DEVICE_IN_USE,
RMNET_CONFIG_INVALID_REQUEST,
RMNET_CONFIG_NO_SUCH_DEVICE,
RMNET_CONFIG_BAD_ARGUMENTS,
RMNET_CONFIG_BAD_EGRESS_DEVICE,
RMNET_CONFIG_TC_HANDLE_FULL
};
#endif /* _RMNET_DATA_H_ */

View file

@ -244,6 +244,7 @@ source "net/switchdev/Kconfig"
source "net/l3mdev/Kconfig"
source "net/qrtr/Kconfig"
source "net/ncsi/Kconfig"
source "net/rmnet_data/Kconfig"
config RPS
bool

View file

@ -81,3 +81,4 @@ obj-y += l3mdev/
endif
obj-$(CONFIG_QRTR) += qrtr/
obj-$(CONFIG_NET_NCSI) += ncsi/
obj-$(CONFIG_RMNET_DATA) += rmnet_data/

29
net/rmnet_data/Kconfig Normal file
View file

@ -0,0 +1,29 @@
#
# RMNET Data and MAP driver
#
menuconfig RMNET_DATA
depends on NETDEVICES
bool "RmNet Data and MAP driver"
---help---
If you say Y here, then the rmnet_data module will be statically
compiled into the kernel. The rmnet data module provides MAP
functionality for embedded and bridged traffic.
if RMNET_DATA
config RMNET_DATA_FC
bool "RmNet Data Flow Control"
depends on NET_SCHED && NET_SCH_PRIO
---help---
Say Y here if you want RmNet data to handle in-band flow control and
ioctl based flow control. This depends on net scheduler and prio queue
capability being present in the kernel. In-band flow control requires
MAP protocol be used.
config RMNET_DATA_DEBUG_PKT
bool "Packet Debug Logging"
---help---
Say Y here if you want RmNet data to be able to log packets in main
system log. This should not be enabled on production builds as it can
impact system performance. Note that simply enabling it here will not
enable the logging; it must be enabled at run-time as well.
endif # RMNET_DATA

14
net/rmnet_data/Makefile Normal file
View file

@ -0,0 +1,14 @@
#
# Makefile for the RMNET Data module
#
rmnet_data-y := rmnet_data_main.o
rmnet_data-y += rmnet_data_config.o
rmnet_data-y += rmnet_data_vnd.o
rmnet_data-y += rmnet_data_handlers.o
rmnet_data-y += rmnet_map_data.o
rmnet_data-y += rmnet_map_command.o
rmnet_data-y += rmnet_data_stats.o
obj-$(CONFIG_RMNET_DATA) += rmnet_data.o
CFLAGS_rmnet_data_main.o := -I$(src)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,128 @@
/* Copyright (c) 2013-2014, 2016 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
*/
#include <linux/types.h>
#include <linux/time.h>
#include <linux/spinlock.h>
#include <net/rmnet_config.h>
#ifndef _RMNET_DATA_CONFIG_H_
#define _RMNET_DATA_CONFIG_H_
#define RMNET_DATA_MAX_LOGICAL_EP 256
/**
* struct rmnet_logical_ep_conf_s - Logical end-point configuration
*
* @refcount: Reference count for this endpoint. 0 signifies the endpoint is not
* configured for use
* @rmnet_mode: Specifies how the traffic should be finally delivered. Possible
* options are available in enum rmnet_config_endpoint_modes_e
* @mux_id: Virtual channel ID used by MAP protocol
* @egress_dev: Next device to deliver the packet to. Exact usage of this
* parmeter depends on the rmnet_mode
*/
struct rmnet_logical_ep_conf_s {
u8 refcount;
u8 rmnet_mode;
u8 mux_id;
struct timespec flush_time;
struct net_device *egress_dev;
};
/**
* struct rmnet_phys_ep_conf_s - Physical endpoint configuration
* One instance of this structure is instantiated for each net_device associated
* with rmnet_data.
*
* @dev: The device which is associated with rmnet_data. Corresponds to this
* specific instance of rmnet_phys_ep_conf_s
* @local_ep: Default non-muxed endpoint. Used for non-MAP protocols/formats
* @muxed_ep: All multiplexed logical endpoints associated with this device
* @ingress_data_format: RMNET_INGRESS_FORMAT_* flags from rmnet_data.h
* @egress_data_format: RMNET_EGRESS_FORMAT_* flags from rmnet_data.h
*
* @egress_agg_size: Maximum size (bytes) of data which should be aggregated
* @egress_agg_count: Maximum count (packets) of data which should be aggregated
* Smaller of the two parameters above are chosen for
* aggregation
* @tail_spacing: Guaranteed padding (bytes) when de-aggregating ingress frames
* @agg_time: Wall clock time when aggregated frame was created
* @agg_last: Last time the aggregation routing was invoked
*/
struct rmnet_phys_ep_config {
struct net_device *dev;
struct rmnet_logical_ep_conf_s local_ep;
struct rmnet_logical_ep_conf_s muxed_ep[RMNET_DATA_MAX_LOGICAL_EP];
u32 ingress_data_format;
u32 egress_data_format;
/* MAP specific */
u16 egress_agg_size;
u16 egress_agg_count;
u8 tail_spacing;
/* MAP aggregation state machine
* - This is not sctrictly configuration and is updated at runtime
* Make sure all of these are protected by the agg_lock
*/
spinlock_t agg_lock;
struct sk_buff *agg_skb;
u8 agg_state;
u8 agg_count;
struct timespec agg_time;
struct timespec agg_last;
};
int rmnet_config_init(void);
void rmnet_config_exit(void);
int rmnet_unassociate_network_device(struct net_device *dev);
int rmnet_set_ingress_data_format(struct net_device *dev,
u32 ingress_data_format,
u8 tail_spacing);
int rmnet_set_egress_data_format(struct net_device *dev,
u32 egress_data_format,
u16 agg_size,
u16 agg_count);
int rmnet_associate_network_device(struct net_device *dev);
int _rmnet_set_logical_endpoint_config
(struct net_device *dev, int config_id,
struct rmnet_logical_ep_conf_s *epconfig);
int rmnet_set_logical_endpoint_config(struct net_device *dev,
int config_id,
u8 rmnet_mode,
struct net_device *egress_dev);
int _rmnet_unset_logical_endpoint_config(struct net_device *dev,
int config_id);
int rmnet_unset_logical_endpoint_config(struct net_device *dev,
int config_id);
int _rmnet_get_logical_endpoint_config
(struct net_device *dev, int config_id,
struct rmnet_logical_ep_conf_s *epconfig);
int rmnet_get_logical_endpoint_config(struct net_device *dev,
int config_id,
u8 *rmnet_mode,
u8 *egress_dev_name,
size_t egress_dev_name_size);
void rmnet_config_netlink_msg_handler (struct sk_buff *skb);
int rmnet_config_notify_cb(struct notifier_block *nb,
unsigned long event, void *data);
int rmnet_create_vnd(int id);
int rmnet_create_vnd_prefix(int id, const char *name);
int rmnet_free_vnd(int id);
struct rmnet_phys_ep_config *_rmnet_get_phys_ep_config
(struct net_device *dev);
#endif /* _RMNET_DATA_CONFIG_H_ */

View file

@ -0,0 +1,686 @@
/* Copyright (c) 2013-2016, 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
*/
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/rmnet_data.h>
#include <linux/net_map.h>
#include <linux/netdev_features.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/rmnet_config.h>
#include "rmnet_data_private.h"
#include "rmnet_data_config.h"
#include "rmnet_data_vnd.h"
#include "rmnet_map.h"
#include "rmnet_data_stats.h"
#include "rmnet_data_trace.h"
#include "rmnet_data_handlers.h"
RMNET_LOG_MODULE(RMNET_DATA_LOGMASK_HANDLER);
#ifdef CONFIG_RMNET_DATA_DEBUG_PKT
unsigned int dump_pkt_rx;
module_param(dump_pkt_rx, uint, 0644);
MODULE_PARM_DESC(dump_pkt_rx, "Dump packets entering ingress handler");
unsigned int dump_pkt_tx;
module_param(dump_pkt_tx, uint, 0644);
MODULE_PARM_DESC(dump_pkt_tx, "Dump packets exiting egress handler");
#endif /* CONFIG_RMNET_DATA_DEBUG_PKT */
/* Time in nano seconds. This number must be less that a second. */
long gro_flush_time __read_mostly = 10000L;
module_param(gro_flush_time, long, 0644);
MODULE_PARM_DESC(gro_flush_time, "Flush GRO when spaced more than this");
#define RMNET_DATA_IP_VERSION_4 0x40
#define RMNET_DATA_IP_VERSION_6 0x60
#define RMNET_DATA_GRO_RCV_FAIL 0
#define RMNET_DATA_GRO_RCV_PASS 1
/* Helper Functions */
/* __rmnet_data_set_skb_proto() - Set skb->protocol field
* @skb: packet being modified
*
* Peek at the first byte of the packet and set the protocol. There is not
* good way to determine if a packet has a MAP header. As of writing this,
* the reserved bit in the MAP frame will prevent it from overlapping with
* IPv4/IPv6 frames. This could change in the future!
*/
static inline void __rmnet_data_set_skb_proto(struct sk_buff *skb)
{
switch (skb->data[0] & 0xF0) {
case RMNET_DATA_IP_VERSION_4:
skb->protocol = htons(ETH_P_IP);
break;
case RMNET_DATA_IP_VERSION_6:
skb->protocol = htons(ETH_P_IPV6);
break;
default:
skb->protocol = htons(ETH_P_MAP);
break;
}
}
#ifdef CONFIG_RMNET_DATA_DEBUG_PKT
/* rmnet_print_packet() - Print packet / diagnostics
* @skb: Packet to print
* @printlen: Number of bytes to print
* @dev: Name of interface
* @dir: Character representing direction (e.g.. 'r' for receive)
*
* This function prints out raw bytes in an SKB. Use of this will have major
* performance impacts and may even trigger watchdog resets if too much is being
* printed. Hence, this should always be compiled out unless absolutely needed.
*/
void rmnet_print_packet(const struct sk_buff *skb, const char *dev, char dir)
{
char buffer[200];
unsigned int len, printlen;
int i, buffloc = 0;
switch (dir) {
case 'r':
printlen = dump_pkt_rx;
break;
case 't':
printlen = dump_pkt_tx;
break;
default:
printlen = 0;
break;
}
if (!printlen)
return;
pr_err("[%s][%c] - PKT skb->len=%d skb->head=%pK skb->data=%pK\n",
dev, dir, skb->len, (void *)skb->head, (void *)skb->data);
pr_err("[%s][%c] - PKT skb->tail=%pK skb->end=%pK\n",
dev, dir, skb_tail_pointer(skb), skb_end_pointer(skb));
if (skb->len > 0)
len = skb->len;
else
len = ((unsigned int)(uintptr_t)skb->end) -
((unsigned int)(uintptr_t)skb->data);
pr_err("[%s][%c] - PKT len: %d, printing first %d bytes\n",
dev, dir, len, printlen);
memset(buffer, 0, sizeof(buffer));
for (i = 0; (i < printlen) && (i < len); i++) {
if ((i % 16) == 0) {
pr_err("[%s][%c] - PKT%s\n", dev, dir, buffer);
memset(buffer, 0, sizeof(buffer));
buffloc = 0;
buffloc += snprintf(&buffer[buffloc],
sizeof(buffer) - buffloc, "%04X:",
i);
}
buffloc += snprintf(&buffer[buffloc], sizeof(buffer) - buffloc,
" %02x", skb->data[i]);
}
pr_err("[%s][%c] - PKT%s\n", dev, dir, buffer);
}
#else
void rmnet_print_packet(const struct sk_buff *skb, const char *dev, char dir)
{
}
#endif /* CONFIG_RMNET_DATA_DEBUG_PKT */
/* Generic handler */
/* rmnet_bridge_handler() - Bridge related functionality
*
* Return:
* - RX_HANDLER_CONSUMED in all cases
*/
static rx_handler_result_t rmnet_bridge_handler
(struct sk_buff *skb, struct rmnet_logical_ep_conf_s *ep)
{
if (!ep->egress_dev) {
LOGD("Missing egress device for packet arriving on %s",
skb->dev->name);
rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_BRDG_NO_EGRESS);
} else {
rmnet_egress_handler(skb, ep);
}
return RX_HANDLER_CONSUMED;
}
#ifdef NET_SKBUFF_DATA_USES_OFFSET
static void rmnet_reset_mac_header(struct sk_buff *skb)
{
skb->mac_header = 0;
skb->mac_len = 0;
}
#else
static void rmnet_reset_mac_header(struct sk_buff *skb)
{
skb->mac_header = skb->network_header;
skb->mac_len = 0;
}
#endif /*NET_SKBUFF_DATA_USES_OFFSET*/
/* rmnet_check_skb_can_gro() - Check is skb can be passed through GRO handler
*
* Determines whether to pass the skb to the GRO handler napi_gro_receive() or
* handle normally by passing to netif_receive_skb().
*
* Warning:
* This assumes that only TCP packets can be coalesced by the GRO handler which
* is not true in general. We lose the ability to use GRO for cases like UDP
* encapsulation protocols.
*
* Return:
* - RMNET_DATA_GRO_RCV_FAIL if packet is sent to netif_receive_skb()
* - RMNET_DATA_GRO_RCV_PASS if packet is sent to napi_gro_receive()
*/
static int rmnet_check_skb_can_gro(struct sk_buff *skb)
{
switch (skb->data[0] & 0xF0) {
case RMNET_DATA_IP_VERSION_4:
if (ip_hdr(skb)->protocol == IPPROTO_TCP)
return RMNET_DATA_GRO_RCV_PASS;
break;
case RMNET_DATA_IP_VERSION_6:
if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
return RMNET_DATA_GRO_RCV_PASS;
/* Fall through */
}
return RMNET_DATA_GRO_RCV_FAIL;
}
/* rmnet_optional_gro_flush() - Check if GRO handler needs to flush now
*
* Determines whether GRO handler needs to flush packets which it has
* coalesced so far.
*
* Tuning this parameter will trade TCP slow start performance for GRO coalesce
* ratio.
*/
static void rmnet_optional_gro_flush(struct napi_struct *napi,
struct rmnet_logical_ep_conf_s *ep)
{
struct timespec curr_time, diff;
if (!gro_flush_time)
return;
if (unlikely(ep->flush_time.tv_sec == 0)) {
getnstimeofday(&ep->flush_time);
} else {
getnstimeofday(&(curr_time));
diff = timespec_sub(curr_time, ep->flush_time);
if ((diff.tv_sec > 0) || (diff.tv_nsec > gro_flush_time)) {
napi_gro_flush(napi, false);
getnstimeofday(&ep->flush_time);
}
}
}
/* __rmnet_deliver_skb() - Deliver skb
*
* Determines where to deliver skb. Options are: consume by network stack,
* pass to bridge handler, or pass to virtual network device
*
* Return:
* - RX_HANDLER_CONSUMED if packet forwarded or dropped
* - RX_HANDLER_PASS if packet is to be consumed by network stack as-is
*/
static rx_handler_result_t __rmnet_deliver_skb
(struct sk_buff *skb, struct rmnet_logical_ep_conf_s *ep)
{
struct napi_struct *napi = NULL;
gro_result_t gro_res;
trace___rmnet_deliver_skb(skb);
switch (ep->rmnet_mode) {
case RMNET_EPMODE_NONE:
return RX_HANDLER_PASS;
case RMNET_EPMODE_BRIDGE:
return rmnet_bridge_handler(skb, ep);
case RMNET_EPMODE_VND:
skb_reset_transport_header(skb);
skb_reset_network_header(skb);
switch (rmnet_vnd_rx_fixup(skb, skb->dev)) {
case RX_HANDLER_CONSUMED:
return RX_HANDLER_CONSUMED;
case RX_HANDLER_PASS:
skb->pkt_type = PACKET_HOST;
rmnet_reset_mac_header(skb);
if (rmnet_check_skb_can_gro(skb) &&
(skb->dev->features & NETIF_F_GRO)) {
napi = get_current_napi_context();
if (napi) {
gro_res = napi_gro_receive(napi, skb);
trace_rmnet_gro_downlink(gro_res);
rmnet_optional_gro_flush(napi, ep);
} else {
WARN_ONCE(1, "current napi is NULL\n");
netif_receive_skb(skb);
}
} else {
netif_receive_skb(skb);
}
return RX_HANDLER_CONSUMED;
}
return RX_HANDLER_PASS;
default:
LOGD("Unknown ep mode %d", ep->rmnet_mode);
rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_DELIVER_NO_EP);
return RX_HANDLER_CONSUMED;
}
}
/* rmnet_ingress_deliver_packet() - Ingress handler for raw IP and bridged
* MAP packets.
* @skb: Packet needing a destination.
* @config: Physical end point configuration that the packet arrived on.
*
* Return:
* - RX_HANDLER_CONSUMED if packet forwarded/dropped
* - RX_HANDLER_PASS if packet should be passed up the stack by caller
*/
static rx_handler_result_t rmnet_ingress_deliver_packet
(struct sk_buff *skb, struct rmnet_phys_ep_config *config)
{
if (!config) {
LOGD("%s", "NULL physical EP provided");
kfree_skb(skb);
return RX_HANDLER_CONSUMED;
}
if (!(config->local_ep.refcount)) {
LOGD("Packet on %s has no local endpoint configuration",
skb->dev->name);
rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_IPINGRESS_NO_EP);
return RX_HANDLER_CONSUMED;
}
skb->dev = config->local_ep.egress_dev;
return __rmnet_deliver_skb(skb, &config->local_ep);
}
/* MAP handler */
/* _rmnet_map_ingress_handler() - Actual MAP ingress handler
* @skb: Packet being received
* @config: Physical endpoint configuration for the ingress device
*
* Most MAP ingress functions are processed here. Packets are processed
* individually; aggregated packets should use rmnet_map_ingress_handler()
*
* Return:
* - RX_HANDLER_CONSUMED if packet is dropped
* - result of __rmnet_deliver_skb() for all other cases
*/
static rx_handler_result_t _rmnet_map_ingress_handler
(struct sk_buff *skb, struct rmnet_phys_ep_config *config)
{
struct rmnet_logical_ep_conf_s *ep;
u8 mux_id;
u16 len;
int ckresult;
if (RMNET_MAP_GET_CD_BIT(skb)) {
if (config->ingress_data_format
& RMNET_INGRESS_FORMAT_MAP_COMMANDS)
return rmnet_map_command(skb, config);
LOGM("MAP command packet on %s; %s", skb->dev->name,
"Not configured for MAP commands");
rmnet_kfree_skb(skb,
RMNET_STATS_SKBFREE_INGRESS_NOT_EXPECT_MAPC);
return RX_HANDLER_CONSUMED;
}
mux_id = RMNET_MAP_GET_MUX_ID(skb);
len = RMNET_MAP_GET_LENGTH(skb)
- RMNET_MAP_GET_PAD(skb)
- config->tail_spacing;
if (mux_id >= RMNET_DATA_MAX_LOGICAL_EP) {
LOGD("Got packet on %s with bad mux id %d",
skb->dev->name, mux_id);
rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPINGRESS_BAD_MUX);
return RX_HANDLER_CONSUMED;
}
ep = &config->muxed_ep[mux_id];
if (!ep->refcount) {
LOGD("Packet on %s:%d; has no logical endpoint config",
skb->dev->name, mux_id);
rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPINGRESS_MUX_NO_EP);
return RX_HANDLER_CONSUMED;
}
if (config->ingress_data_format & RMNET_INGRESS_FORMAT_DEMUXING)
skb->dev = ep->egress_dev;
if ((config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV3) ||
(config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV4)) {
ckresult = rmnet_map_checksum_downlink_packet(skb);
trace_rmnet_map_checksum_downlink_packet(skb, ckresult);
rmnet_stats_dl_checksum(ckresult);
if (likely((ckresult == RMNET_MAP_CHECKSUM_OK) ||
(ckresult == RMNET_MAP_CHECKSUM_SKIPPED)))
skb->ip_summed |= CHECKSUM_UNNECESSARY;
else if (ckresult !=
RMNET_MAP_CHECKSUM_ERR_UNKNOWN_IP_VERSION &&
ckresult != RMNET_MAP_CHECKSUM_ERR_UNKNOWN_TRANSPORT &&
ckresult != RMNET_MAP_CHECKSUM_VALID_FLAG_NOT_SET &&
ckresult != RMNET_MAP_CHECKSUM_FRAGMENTED_PACKET) {
rmnet_kfree_skb
(skb, RMNET_STATS_SKBFREE_INGRESS_BAD_MAP_CKSUM);
return RX_HANDLER_CONSUMED;
}
}
/* Subtract MAP header */
skb_pull(skb, sizeof(struct rmnet_map_header_s));
skb_trim(skb, len);
__rmnet_data_set_skb_proto(skb);
return __rmnet_deliver_skb(skb, ep);
}
/* rmnet_map_ingress_handler() - MAP ingress handler
* @skb: Packet being received
* @config: Physical endpoint configuration for the ingress device
*
* Called if and only if MAP is configured in the ingress device's ingress data
* format. Deaggregation is done here, actual MAP processing is done in
* _rmnet_map_ingress_handler().
*
* Return:
* - RX_HANDLER_CONSUMED for aggregated packets
* - RX_HANDLER_CONSUMED for dropped packets
* - result of _rmnet_map_ingress_handler() for all other cases
*/
static rx_handler_result_t rmnet_map_ingress_handler
(struct sk_buff *skb, struct rmnet_phys_ep_config *config)
{
struct sk_buff *skbn;
int rc, co = 0;
if (config->ingress_data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) {
trace_rmnet_start_deaggregation(skb);
while ((skbn = rmnet_map_deaggregate(skb, config)) != 0) {
_rmnet_map_ingress_handler(skbn, config);
co++;
}
trace_rmnet_end_deaggregation(skb, co);
LOGD("De-aggregated %d packets", co);
rmnet_stats_deagg_pkts(co);
rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPINGRESS_AGGBUF);
rc = RX_HANDLER_CONSUMED;
} else {
rc = _rmnet_map_ingress_handler(skb, config);
}
return rc;
}
/* rmnet_map_egress_handler() - MAP egress handler
* @skb: Packet being sent
* @config: Physical endpoint configuration for the egress device
* @ep: logical endpoint configuration of the packet originator
* (e.g.. RmNet virtual network device)
* @orig_dev: The originator vnd device
*
* Called if and only if MAP is configured in the egress device's egress data
* format. Will expand skb if there is insufficient headroom for MAP protocol.
* Note: headroomexpansion will incur a performance penalty.
*
* Return:
* - 0 on success
* - 1 on failure
*/
static int rmnet_map_egress_handler(struct sk_buff *skb,
struct rmnet_phys_ep_config *config,
struct rmnet_logical_ep_conf_s *ep,
struct net_device *orig_dev)
{
int required_headroom, additional_header_length, ckresult;
struct rmnet_map_header_s *map_header;
additional_header_length = 0;
required_headroom = sizeof(struct rmnet_map_header_s);
if ((config->egress_data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV3) ||
(config->egress_data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV4)) {
required_headroom +=
sizeof(struct rmnet_map_ul_checksum_header_s);
additional_header_length +=
sizeof(struct rmnet_map_ul_checksum_header_s);
}
LOGD("headroom of %d bytes", required_headroom);
if (skb_headroom(skb) < required_headroom) {
if (pskb_expand_head(skb, required_headroom, 0, GFP_KERNEL)) {
LOGD("Failed to add headroom of %d bytes",
required_headroom);
return 1;
}
}
if ((config->egress_data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV3) ||
(config->egress_data_format & RMNET_EGRESS_FORMAT_MAP_CKSUMV4)) {
ckresult = rmnet_map_checksum_uplink_packet
(skb, orig_dev, config->egress_data_format);
trace_rmnet_map_checksum_uplink_packet(orig_dev, ckresult);
rmnet_stats_ul_checksum(ckresult);
}
if ((!(config->egress_data_format &
RMNET_EGRESS_FORMAT_AGGREGATION)) ||
((orig_dev->features & NETIF_F_GSO) && skb_is_nonlinear(skb)))
map_header = rmnet_map_add_map_header
(skb, additional_header_length, RMNET_MAP_NO_PAD_BYTES);
else
map_header = rmnet_map_add_map_header
(skb, additional_header_length, RMNET_MAP_ADD_PAD_BYTES);
if (!map_header) {
LOGD("%s", "Failed to add MAP header to egress packet");
return 1;
}
if (config->egress_data_format & RMNET_EGRESS_FORMAT_MUXING) {
if (ep->mux_id == 0xff)
map_header->mux_id = 0;
else
map_header->mux_id = ep->mux_id;
}
skb->protocol = htons(ETH_P_MAP);
if (config->egress_data_format & RMNET_EGRESS_FORMAT_AGGREGATION) {
rmnet_map_aggregate(skb, config);
return RMNET_MAP_CONSUMED;
}
return RMNET_MAP_SUCCESS;
}
/* Ingress / Egress Entry Points */
/* rmnet_ingress_handler() - Ingress handler entry point
* @skb: Packet being received
*
* Processes packet as per ingress data format for receiving device. Logical
* endpoint is determined from packet inspection. Packet is then sent to the
* egress device listed in the logical endpoint configuration.
*
* Return:
* - RX_HANDLER_PASS if packet is not processed by handler (caller must
* deal with the packet)
* - RX_HANDLER_CONSUMED if packet is forwarded or processed by MAP
*/
rx_handler_result_t rmnet_ingress_handler(struct sk_buff *skb)
{
struct rmnet_phys_ep_config *config;
struct net_device *dev;
int rc;
if (!skb)
return RX_HANDLER_CONSUMED;
dev = skb->dev;
trace_rmnet_ingress_handler(skb);
rmnet_print_packet(skb, dev->name, 'r');
config = _rmnet_get_phys_ep_config(skb->dev);
if (!config) {
LOGD("%s is not associated with rmnet_data", skb->dev->name);
kfree_skb(skb);
return RX_HANDLER_CONSUMED;
}
/* Sometimes devices operate in ethernet mode even thouth there is no
* ethernet header. This causes the skb->protocol to contain a bogus
* value and the skb->data pointer to be off by 14 bytes. Fix it if
* configured to do so
*/
if (config->ingress_data_format & RMNET_INGRESS_FIX_ETHERNET) {
skb_push(skb, RMNET_ETHERNET_HEADER_LENGTH);
__rmnet_data_set_skb_proto(skb);
}
if (config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP) {
rc = rmnet_map_ingress_handler(skb, config);
} else {
switch (ntohs(skb->protocol)) {
case ETH_P_MAP:
if (config->local_ep.rmnet_mode ==
RMNET_EPMODE_BRIDGE) {
rc = rmnet_ingress_deliver_packet(skb, config);
} else {
LOGD("MAP packet on %s; MAP not set",
dev->name);
rmnet_kfree_skb
(skb,
RMNET_STATS_SKBFREE_INGRESS_NOT_EXPECT_MAPD);
rc = RX_HANDLER_CONSUMED;
}
break;
case ETH_P_ARP:
case ETH_P_IP:
case ETH_P_IPV6:
rc = rmnet_ingress_deliver_packet(skb, config);
break;
default:
LOGD("Unknown skb->proto 0x%04X\n",
ntohs(skb->protocol) & 0xFFFF);
rc = RX_HANDLER_PASS;
}
}
return rc;
}
/* rmnet_rx_handler() - Rx handler callback registered with kernel
* @pskb: Packet to be processed by rx handler
*
* Standard kernel-expected footprint for rx handlers. Calls
* rmnet_ingress_handler with correctly formatted arguments
*
* Return:
* - Whatever rmnet_ingress_handler() returns
*/
rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb)
{
return rmnet_ingress_handler(*pskb);
}
/* rmnet_egress_handler() - Egress handler entry point
* @skb: packet to transmit
* @ep: logical endpoint configuration of the packet originator
* (e.g.. RmNet virtual network device)
*
* Modifies packet as per logical endpoint configuration and egress data format
* for egress device configured in logical endpoint. Packet is then transmitted
* on the egress device.
*/
void rmnet_egress_handler(struct sk_buff *skb,
struct rmnet_logical_ep_conf_s *ep)
{
struct rmnet_phys_ep_config *config;
struct net_device *orig_dev;
int rc;
orig_dev = skb->dev;
skb->dev = ep->egress_dev;
config = _rmnet_get_phys_ep_config(skb->dev);
if (!config) {
LOGD("%s is not associated with rmnet_data", skb->dev->name);
kfree_skb(skb);
return;
}
LOGD("Packet going out on %s with egress format 0x%08X",
skb->dev->name, config->egress_data_format);
if (config->egress_data_format & RMNET_EGRESS_FORMAT_MAP) {
switch (rmnet_map_egress_handler(skb, config, ep, orig_dev)) {
case RMNET_MAP_CONSUMED:
LOGD("%s", "MAP process consumed packet");
return;
case RMNET_MAP_SUCCESS:
break;
default:
LOGD("MAP egress failed on packet on %s",
skb->dev->name);
rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_EGR_MAPFAIL);
return;
}
}
if (ep->rmnet_mode == RMNET_EPMODE_VND)
rmnet_vnd_tx_fixup(skb, orig_dev);
rmnet_print_packet(skb, skb->dev->name, 't');
trace_rmnet_egress_handler(skb);
rc = dev_queue_xmit(skb);
if (rc != 0) {
LOGD("Failed to queue packet for transmission on [%s]",
skb->dev->name);
}
rmnet_stats_queue_xmit(rc, RMNET_STATS_QUEUE_XMIT_EGRESS);
}

View file

@ -0,0 +1,23 @@
/* Copyright (c) 2013, 2016 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
*/
#ifndef _RMNET_DATA_HANDLERS_H_
#define _RMNET_DATA_HANDLERS_H_
void rmnet_egress_handler(struct sk_buff *skb,
struct rmnet_logical_ep_conf_s *ep);
rx_handler_result_t rmnet_rx_handler(struct sk_buff **pskb);
#endif /* _RMNET_DATA_HANDLERS_H_ */

View file

@ -0,0 +1,59 @@
/* Copyright (c) 2013-2014, 2016 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 generic framework
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include "rmnet_data_private.h"
#include "rmnet_data_config.h"
#include "rmnet_data_vnd.h"
/* Trace Points */
#define CREATE_TRACE_POINTS
#include "rmnet_data_trace.h"
/* Module Parameters */
unsigned int rmnet_data_log_level = RMNET_LOG_LVL_ERR | RMNET_LOG_LVL_HI;
module_param(rmnet_data_log_level, uint, 0644);
MODULE_PARM_DESC(log_level, "Logging level");
unsigned int rmnet_data_log_module_mask;
module_param(rmnet_data_log_module_mask, uint, 0644);
MODULE_PARM_DESC(rmnet_data_log_module_mask, "Logging module mask");
/* Startup/Shutdown */
/* rmnet_init() - Module initialization
*
* todo: check for (and init) startup errors
*/
static int __init rmnet_init(void)
{
rmnet_config_init();
rmnet_vnd_init();
LOGL("%s", "RMNET Data driver loaded successfully");
return 0;
}
static void __exit rmnet_exit(void)
{
rmnet_config_exit();
rmnet_vnd_exit();
}
module_init(rmnet_init)
module_exit(rmnet_exit)
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,76 @@
/* Copyright (c) 2013-2014, 2016 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.
*/
#ifndef _RMNET_DATA_PRIVATE_H_
#define _RMNET_DATA_PRIVATE_H_
#define RMNET_DATA_MAX_VND 32
#define RMNET_DATA_MAX_PACKET_SIZE 16384
#define RMNET_DATA_DFLT_PACKET_SIZE 1500
#define RMNET_DATA_DEV_NAME_STR "rmnet_data"
#define RMNET_DATA_NEEDED_HEADROOM 16
#define RMNET_DATA_TX_QUEUE_LEN 1000
#define RMNET_ETHERNET_HEADER_LENGTH 14
extern unsigned int rmnet_data_log_level;
extern unsigned int rmnet_data_log_module_mask;
#define RMNET_INIT_OK 0
#define RMNET_INIT_ERROR 1
#define RMNET_LOG_LVL_DBG BIT(4)
#define RMNET_LOG_LVL_LOW BIT(3)
#define RMNET_LOG_LVL_MED BIT(2)
#define RMNET_LOG_LVL_HI BIT(1)
#define RMNET_LOG_LVL_ERR BIT(0)
#define RMNET_LOG_MODULE(X) \
static u32 rmnet_mod_mask = X
#define RMNET_DATA_LOGMASK_CONFIG BIT(0)
#define RMNET_DATA_LOGMASK_HANDLER BIT(1)
#define RMNET_DATA_LOGMASK_VND BIT(2)
#define RMNET_DATA_LOGMASK_MAPD BIT(3)
#define RMNET_DATA_LOGMASK_MAPC BIT(4)
#define LOGE(fmt, ...) do { if (rmnet_data_log_level & RMNET_LOG_LVL_ERR) \
pr_err("[RMNET:ERR] %s(): " fmt "\n", __func__, \
##__VA_ARGS__); \
} while (0)
#define LOGH(fmt, ...) do { if (rmnet_data_log_level & RMNET_LOG_LVL_HI) \
pr_err("[RMNET:HI] %s(): " fmt "\n", __func__, \
##__VA_ARGS__); \
} while (0)
#define LOGM(fmt, ...) do { if (rmnet_data_log_level & RMNET_LOG_LVL_MED) \
pr_warn("[RMNET:MED] %s(): " fmt "\n", __func__, \
##__VA_ARGS__); \
} while (0)
#define LOGL(fmt, ...) do { if (unlikely \
(rmnet_data_log_level & RMNET_LOG_LVL_LOW)) \
pr_notice("[RMNET:LOW] %s(): " fmt "\n", __func__, \
##__VA_ARGS__); \
} while (0)
/* Don't use pr_debug as it is compiled out of the kernel. We can be sure of
* minimal impact as LOGD is not enabled by default.
*/
#define LOGD(fmt, ...) do { if (unlikely( \
(rmnet_data_log_level & RMNET_LOG_LVL_DBG) && \
(rmnet_data_log_module_mask & rmnet_mod_mask))) \
pr_notice("[RMNET:DBG] %s(): " fmt "\n", __func__, \
##__VA_ARGS__); \
} while (0)
#endif /* _RMNET_DATA_PRIVATE_H_ */

View file

@ -0,0 +1,143 @@
/* Copyright (c) 2014, 2016 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 statistics
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <net/rmnet_config.h>
#include "rmnet_data_private.h"
#include "rmnet_data_stats.h"
#include "rmnet_data_config.h"
#include "rmnet_map.h"
enum rmnet_deagg_e {
RMNET_STATS_AGG_BUFF,
RMNET_STATS_AGG_PKT,
RMNET_STATS_AGG_MAX
};
static DEFINE_SPINLOCK(rmnet_skb_free_lock);
unsigned long int skb_free[RMNET_STATS_SKBFREE_MAX];
module_param_array(skb_free, ulong, 0, 0444);
MODULE_PARM_DESC(skb_free, "SKBs dropped or freed");
static DEFINE_SPINLOCK(rmnet_queue_xmit_lock);
unsigned long int queue_xmit[RMNET_STATS_QUEUE_XMIT_MAX * 2];
module_param_array(queue_xmit, ulong, 0, 0444);
MODULE_PARM_DESC(queue_xmit, "SKBs queued for transmit");
static DEFINE_SPINLOCK(rmnet_deagg_count);
unsigned long int deagg_count[RMNET_STATS_AGG_MAX];
module_param_array(deagg_count, ulong, 0, 0444);
MODULE_PARM_DESC(deagg_count, "SKBs De-aggregated");
static DEFINE_SPINLOCK(rmnet_agg_count);
unsigned long int agg_count[RMNET_STATS_AGG_MAX];
module_param_array(agg_count, ulong, 0, 0444);
MODULE_PARM_DESC(agg_count, "SKBs Aggregated");
static DEFINE_SPINLOCK(rmnet_checksum_dl_stats);
unsigned long int checksum_dl_stats[RMNET_MAP_CHECKSUM_ENUM_LENGTH];
module_param_array(checksum_dl_stats, ulong, 0, 0444);
MODULE_PARM_DESC(checksum_dl_stats, "Downlink Checksum Statistics");
static DEFINE_SPINLOCK(rmnet_checksum_ul_stats);
unsigned long int checksum_ul_stats[RMNET_MAP_CHECKSUM_ENUM_LENGTH];
module_param_array(checksum_ul_stats, ulong, 0, 0444);
MODULE_PARM_DESC(checksum_ul_stats, "Uplink Checksum Statistics");
void rmnet_kfree_skb(struct sk_buff *skb, unsigned int reason)
{
unsigned long flags;
if (reason >= RMNET_STATS_SKBFREE_MAX)
reason = RMNET_STATS_SKBFREE_UNKNOWN;
spin_lock_irqsave(&rmnet_skb_free_lock, flags);
skb_free[reason]++;
spin_unlock_irqrestore(&rmnet_skb_free_lock, flags);
if (likely(skb)) {
struct rmnet_phys_ep_conf_s *config;
config = (struct rmnet_phys_ep_conf_s *)rcu_dereference
(skb->dev->rx_handler_data);
if (likely(config))
config->recycle(skb);
else
kfree_skb(skb);
}
}
void rmnet_stats_queue_xmit(int rc, unsigned int reason)
{
unsigned long flags;
if (rc != 0)
reason += RMNET_STATS_QUEUE_XMIT_MAX;
if (reason >= RMNET_STATS_QUEUE_XMIT_MAX * 2)
reason = RMNET_STATS_SKBFREE_UNKNOWN;
spin_lock_irqsave(&rmnet_queue_xmit_lock, flags);
queue_xmit[reason]++;
spin_unlock_irqrestore(&rmnet_queue_xmit_lock, flags);
}
void rmnet_stats_agg_pkts(int aggcount)
{
unsigned long flags;
spin_lock_irqsave(&rmnet_agg_count, flags);
agg_count[RMNET_STATS_AGG_BUFF]++;
agg_count[RMNET_STATS_AGG_PKT] += aggcount;
spin_unlock_irqrestore(&rmnet_agg_count, flags);
}
void rmnet_stats_deagg_pkts(int aggcount)
{
unsigned long flags;
spin_lock_irqsave(&rmnet_deagg_count, flags);
deagg_count[RMNET_STATS_AGG_BUFF]++;
deagg_count[RMNET_STATS_AGG_PKT] += aggcount;
spin_unlock_irqrestore(&rmnet_deagg_count, flags);
}
void rmnet_stats_dl_checksum(unsigned int rc)
{
unsigned long flags;
if (rc >= RMNET_MAP_CHECKSUM_ENUM_LENGTH)
rc = RMNET_MAP_CHECKSUM_ERR_UNKNOWN;
spin_lock_irqsave(&rmnet_checksum_dl_stats, flags);
checksum_dl_stats[rc]++;
spin_unlock_irqrestore(&rmnet_checksum_dl_stats, flags);
}
void rmnet_stats_ul_checksum(unsigned int rc)
{
unsigned long flags;
if (rc >= RMNET_MAP_CHECKSUM_ENUM_LENGTH)
rc = RMNET_MAP_CHECKSUM_ERR_UNKNOWN;
spin_lock_irqsave(&rmnet_checksum_ul_stats, flags);
checksum_ul_stats[rc]++;
spin_unlock_irqrestore(&rmnet_checksum_ul_stats, flags);
}

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2014, 2016 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 statistics
*
*/
#ifndef _RMNET_DATA_STATS_H_
#define _RMNET_DATA_STATS_H_
enum rmnet_skb_free_e {
RMNET_STATS_SKBFREE_UNKNOWN,
RMNET_STATS_SKBFREE_BRDG_NO_EGRESS,
RMNET_STATS_SKBFREE_DELIVER_NO_EP,
RMNET_STATS_SKBFREE_IPINGRESS_NO_EP,
RMNET_STATS_SKBFREE_MAPINGRESS_BAD_MUX,
RMNET_STATS_SKBFREE_MAPINGRESS_MUX_NO_EP,
RMNET_STATS_SKBFREE_MAPINGRESS_AGGBUF,
RMNET_STATS_SKBFREE_INGRESS_NOT_EXPECT_MAPD,
RMNET_STATS_SKBFREE_INGRESS_NOT_EXPECT_MAPC,
RMNET_STATS_SKBFREE_EGR_MAPFAIL,
RMNET_STATS_SKBFREE_VND_NO_EGRESS,
RMNET_STATS_SKBFREE_MAPC_BAD_MUX,
RMNET_STATS_SKBFREE_MAPC_MUX_NO_EP,
RMNET_STATS_SKBFREE_AGG_CPY_EXPAND,
RMNET_STATS_SKBFREE_AGG_INTO_BUFF,
RMNET_STATS_SKBFREE_DEAGG_MALFORMED,
RMNET_STATS_SKBFREE_DEAGG_CLONE_FAIL,
RMNET_STATS_SKBFREE_DEAGG_UNKNOWN_IP_TYPE,
RMNET_STATS_SKBFREE_DEAGG_DATA_LEN_0,
RMNET_STATS_SKBFREE_INGRESS_BAD_MAP_CKSUM,
RMNET_STATS_SKBFREE_MAPC_UNSUPPORTED,
RMNET_STATS_SKBFREE_MAX
};
enum rmnet_queue_xmit_e {
RMNET_STATS_QUEUE_XMIT_UNKNOWN,
RMNET_STATS_QUEUE_XMIT_EGRESS,
RMNET_STATS_QUEUE_XMIT_AGG_FILL_BUFFER,
RMNET_STATS_QUEUE_XMIT_AGG_TIMEOUT,
RMNET_STATS_QUEUE_XMIT_AGG_CPY_EXP_FAIL,
RMNET_STATS_QUEUE_XMIT_AGG_SKIP,
RMNET_STATS_QUEUE_XMIT_MAX
};
void rmnet_kfree_skb(struct sk_buff *skb, unsigned int reason);
void rmnet_stats_queue_xmit(int rc, unsigned int reason);
void rmnet_stats_deagg_pkts(int aggcount);
void rmnet_stats_agg_pkts(int aggcount);
void rmnet_stats_dl_checksum(unsigned int rc);
void rmnet_stats_ul_checksum(unsigned int rc);
#endif /* _RMNET_DATA_STATS_H_ */

View file

@ -0,0 +1,358 @@
/* Copyright (c) 2014-2016, 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.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM rmnet_data
#define TRACE_INCLUDE_FILE rmnet_data_trace
#if !defined(_TRACE_MSM_LOW_POWER_H_) || defined(TRACE_HEADER_MULTI_READ)
#define _RMNET_DATA_TRACE_H_
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/tracepoint.h>
DECLARE_EVENT_CLASS
(rmnet_handler_template,
TP_PROTO(struct sk_buff *skb),
TP_ARGS(skb),
TP_STRUCT__entry(
__field(void *, skbaddr)
__field(unsigned int, len)
__string(name, skb->dev->name)
),
TP_fast_assign(
__entry->skbaddr = skb;
__entry->len = skb->len;
__assign_str(name, skb->dev->name);
),
TP_printk("dev=%s skbaddr=%pK len=%u",
__get_str(name), __entry->skbaddr, __entry->len)
)
DEFINE_EVENT
(rmnet_handler_template, rmnet_egress_handler,
TP_PROTO(struct sk_buff *skb),
TP_ARGS(skb)
);
DEFINE_EVENT
(rmnet_handler_template, rmnet_ingress_handler,
TP_PROTO(struct sk_buff *skb),
TP_ARGS(skb)
);
DEFINE_EVENT
(rmnet_handler_template, rmnet_vnd_start_xmit,
TP_PROTO(struct sk_buff *skb),
TP_ARGS(skb)
);
DEFINE_EVENT
(rmnet_handler_template, __rmnet_deliver_skb,
TP_PROTO(struct sk_buff *skb),
TP_ARGS(skb)
);
DECLARE_EVENT_CLASS
(rmnet_tc_fc_template,
TP_PROTO(u32 tcm_handle, int qdisc_len, int is_enable),
TP_ARGS(tcm_handle, qdisc_len, is_enable),
TP_STRUCT__entry(
__field(u32, handle)
__field(int, qlen)
__field(int, enable)
),
TP_fast_assign(
__entry->handle = tcm_handle;
__entry->qlen = qdisc_len;
__entry->enable = is_enable;
),
TP_printk("tcm_handle=%d qdisc length=%d flow %s",
__entry->handle, __entry->qlen,
__entry->enable ? "enable" : "disable")
)
DEFINE_EVENT
(rmnet_tc_fc_template, rmnet_fc_qmi,
TP_PROTO(u32 tcm_handle, int qdisc_len, int is_enable),
TP_ARGS(tcm_handle, qdisc_len, is_enable)
);
DEFINE_EVENT
(rmnet_tc_fc_template, rmnet_fc_map,
TP_PROTO(u32 tcm_handle, int qdisc_len, int is_enable),
TP_ARGS(tcm_handle, qdisc_len, is_enable)
);
DECLARE_EVENT_CLASS
(rmnet_aggregation_template,
TP_PROTO(struct sk_buff *skb, int num_agg_pakcets),
TP_ARGS(skb, num_agg_pakcets),
TP_STRUCT__entry(
__field(void *, skbaddr)
__field(unsigned int, len)
__string(name, skb->dev->name)
__field(int, num)
),
TP_fast_assign(
__entry->skbaddr = skb;
__entry->len = skb->len;
__assign_str(name, skb->dev->name);
__entry->num = num_agg_pakcets;
),
TP_printk("dev=%s skbaddr=%pK len=%u agg_count: %d",
__get_str(name), __entry->skbaddr, __entry->len,
__entry->num)
)
DEFINE_EVENT
(rmnet_aggregation_template, rmnet_map_aggregate,
TP_PROTO(struct sk_buff *skb, int num_agg_pakcets),
TP_ARGS(skb, num_agg_pakcets)
);
DEFINE_EVENT
(rmnet_aggregation_template, rmnet_map_flush_packet_queue,
TP_PROTO(struct sk_buff *skb, int num_agg_pakcets),
TP_ARGS(skb, num_agg_pakcets)
);
TRACE_EVENT
(rmnet_start_aggregation,
TP_PROTO(struct sk_buff *skb),
TP_ARGS(skb),
TP_STRUCT__entry(
__string(name, skb->dev->name)
),
TP_fast_assign(
__assign_str(name, skb->dev->name);
),
TP_printk("dev: %s, aggregated first packet", __get_str(name))
)
TRACE_EVENT
(rmnet_start_deaggregation,
TP_PROTO(struct sk_buff *skb),
TP_ARGS(skb),
TP_STRUCT__entry(
__string(name, skb->dev->name)
),
TP_fast_assign(
__assign_str(name, skb->dev->name);
),
TP_printk("dev: %s, deaggregated first packet", __get_str(name))
)
TRACE_EVENT
(rmnet_end_deaggregation,
TP_PROTO(struct sk_buff *skb, int num_deagg_packets),
TP_ARGS(skb, num_deagg_packets),
TP_STRUCT__entry(
__string(name, skb->dev->name)
__field(int, num)
),
TP_fast_assign(
__assign_str(name, skb->dev->name);
__entry->num = num_deagg_packets;
),
TP_printk("dev: %s, deaggregate end count: %d",
__get_str(name), __entry->num)
)
TRACE_EVENT
(rmnet_map_checksum_downlink_packet,
TP_PROTO(struct sk_buff *skb, int ckresult),
TP_ARGS(skb, ckresult),
TP_STRUCT__entry(
__string(name, skb->dev->name)
__field(int, res)
),
TP_fast_assign(
__assign_str(name, skb->dev->name);
__entry->res = ckresult;
),
TP_printk("DL checksum on dev=%s, res: %d",
__get_str(name), __entry->res)
)
TRACE_EVENT
(rmnet_map_checksum_uplink_packet,
TP_PROTO(struct net_device *dev, int ckresult),
TP_ARGS(dev, ckresult),
TP_STRUCT__entry(
__string(name, dev->name)
__field(int, res)
),
TP_fast_assign(
__assign_str(name, dev->name);
__entry->res = ckresult;
),
TP_printk("UL checksum on dev=%s, res: %d",
__get_str(name), __entry->res)
)
DECLARE_EVENT_CLASS
(rmnet_physdev_action_template,
TP_PROTO(struct net_device *dev),
TP_ARGS(dev),
TP_STRUCT__entry(
__string(name, dev->name)
),
TP_fast_assign(
__assign_str(name, dev->name);
),
TP_printk("Physical dev=%s", __get_str(name))
)
DEFINE_EVENT
(rmnet_physdev_action_template, rmnet_unregister_cb_unhandled,
TP_PROTO(struct net_device *dev),
TP_ARGS(dev)
);
DEFINE_EVENT
(rmnet_physdev_action_template, rmnet_unregister_cb_entry,
TP_PROTO(struct net_device *dev),
TP_ARGS(dev)
);
DEFINE_EVENT
(rmnet_physdev_action_template, rmnet_unregister_cb_exit,
TP_PROTO(struct net_device *dev),
TP_ARGS(dev)
);
DEFINE_EVENT
(rmnet_physdev_action_template, rmnet_unregister_cb_clear_vnds,
TP_PROTO(struct net_device *dev),
TP_ARGS(dev)
);
DEFINE_EVENT
(rmnet_physdev_action_template, rmnet_unregister_cb_clear_lepcs,
TP_PROTO(struct net_device *dev),
TP_ARGS(dev)
);
DEFINE_EVENT
(rmnet_physdev_action_template, rmnet_associate,
TP_PROTO(struct net_device *dev),
TP_ARGS(dev)
);
DEFINE_EVENT
(rmnet_physdev_action_template, rmnet_unassociate,
TP_PROTO(struct net_device *dev),
TP_ARGS(dev)
);
TRACE_EVENT
(rmnet_gro_downlink,
TP_PROTO(gro_result_t gro_res),
TP_ARGS(gro_res),
TP_STRUCT__entry(
__field(gro_result_t, res)
),
TP_fast_assign(
__entry->res = gro_res;
),
TP_printk("GRO res: %d", __entry->res)
)
#endif /* _RMNET_DATA_TRACE_H_ */
/* This part must be outside protection */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#include <trace/define_trace.h>

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more