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

Commit 236fb315 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge changes...

Merge changes Iedf9be1e,I89ad3c6f,If3e657cd,Ie586fa43,Id559d9ef,I007bdf8b,I0e9096e4,I7cf1c5e3 into msm-next

* changes:
  drivers: net: rmnet_iplo: Initial commit
  defconfig: sdm855: Enable rmnet_data
  net: rmnet_data: Remove redundant uapi installation
  net: rmnet_data: Add support for data path testing in UML
  Revert "genetlink: disallow subscribing to unknown mcast groups"
  ipv6: generate random IID only for temporary addresses on RAWIP devices
  net_sched: Add flow control support to prio qdisc
  net: Add the get current NAPI context API
parents be0fe526 72d5deb8
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -193,6 +193,9 @@ CONFIG_NET_ACT_MIRRED=y
CONFIG_NET_ACT_SKBEDIT=y
CONFIG_QRTR=y
CONFIG_QRTR_SMD=y
CONFIG_RMNET_DATA=y
CONFIG_RMNET_DATA_FC=y
CONFIG_RMNET_DATA_DEBUG_PKT=y
CONFIG_BT=y
CONFIG_CFG80211=y
CONFIG_CFG80211_INTERNAL_REGDB=y
+3 −0
Original line number Diff line number Diff line
@@ -200,6 +200,9 @@ CONFIG_NET_ACT_SKBEDIT=y
CONFIG_DNS_RESOLVER=y
CONFIG_QRTR=y
CONFIG_QRTR_SMD=y
CONFIG_RMNET_DATA=y
CONFIG_RMNET_DATA_FC=y
CONFIG_RMNET_DATA_DEBUG_PKT=y
CONFIG_BT=y
CONFIG_CFG80211=y
CONFIG_CFG80211_INTERNAL_REGDB=y
+10 −0
Original line number Diff line number Diff line
@@ -263,6 +263,16 @@ config NTB_NETDEV
	tristate "Virtual Ethernet over NTB Transport"
	depends on NTB_TRANSPORT

config RMNET_IPLO
	tristate "RMNET IPLO driver"
	---help---
	   This allows the creation of the rmnet ip loopback driver which is
	   used for testing rmnet_data control and data path.

	   rmnet_iplo supports most of the IOCTL's which will be defined by
	   a physical device which uses rmnet_data. rmnet_iplo will
	   loopback any data which is sent to it.

config RIONET
	tristate "RapidIO Ethernet over messaging driver support"
	depends on RAPIDIO
+1 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ obj-$(CONFIG_NET) += Space.o loopback.o
obj-$(CONFIG_NETCONSOLE) += netconsole.o
obj-y += phy/
obj-$(CONFIG_RIONET) += rionet.o
obj-$(CONFIG_RMNET_IPLO) += rmnet_iplo.o
obj-$(CONFIG_NET_TEAM) += team/
obj-$(CONFIG_TUN) += tun.o
obj-$(CONFIG_TAP) += tap.o
+232 −0
Original line number Diff line number Diff line
/* Copyright (c) 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.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <linux/msm_rmnet.h>

unsigned int multiplication_factor = 1;
module_param(multiplication_factor, uint, 0644);

struct net_device *mydevice;

static void iplo_do_ip_loopback(struct sk_buff *skb, int ip_offset)
{
	struct iphdr *hdr;
	struct icmphdr *icmp;
	__be32 ipaddr;
	int i;

	hdr = (struct iphdr *)(skb->data + ip_offset);
	ipaddr = hdr->saddr;
	hdr->saddr = hdr->daddr;
	hdr->daddr = ipaddr;
	switch (hdr->protocol) {
	case 1: /* ICMP */
		icmp = (struct icmphdr *)(skb->data + ip_offset + hdr->ihl * 4);
		if (icmp->type == ICMP_ECHO)
			icmp->type = ICMP_ECHOREPLY;
		break;
	case 11: /* UDP */
		break;
	case 6: /* TCP */
		break;
	default:
		break;
	}
	if (multiplication_factor < 2) {
		netif_rx(skb);
		skb->dev->stats.tx_packets++;
	} else {
		for (i = 0; i < (multiplication_factor - 1); i++) {
			netif_rx(skb_copy(skb, GFP_ATOMIC));
			skb->dev->stats.tx_packets++;
		}
		netif_rx(skb);
		skb->dev->stats.tx_packets++;
	}
}

static netdev_tx_t iplo_vnd_start_xmit(struct sk_buff *skb,
				       struct net_device *dev)
{
	int ip_offset = 0;

	switch (ntohs(skb->protocol)) {
	case ETH_P_MAP:
		ip_offset = 4;
	case ETH_P_IP:
		iplo_do_ip_loopback(skb, ip_offset);
		dev->stats.rx_packets++;
		break;
	default:
		dev->stats.tx_dropped++;
		kfree_skb(skb);
		break;
	}
	return NETDEV_TX_OK;
}

static int iplo_vnd_ioctl_extended(struct net_device *dev, struct ifreq *ifr)
{
	struct rmnet_ioctl_extended_s ext_cmd;
	int rc = 0;

	rc = copy_from_user(&ext_cmd, ifr->ifr_ifru.ifru_data,
			    sizeof(struct rmnet_ioctl_extended_s));

	if (rc) {
		pr_err("%s() copy_from_user failed, error %d\n", __func__, rc);
		return rc;
	}

	switch (ext_cmd.extended_ioctl) {
	case RMNET_IOCTL_SET_MRU:
		break;
	case RMNET_IOCTL_GET_EPID:
		ext_cmd.u.data = 100;
		break;
	case RMNET_IOCTL_GET_SUPPORTED_FEATURES:
		ext_cmd.u.data = 0;
		break;
	case RMNET_IOCTL_GET_DRIVER_NAME:
		strlcpy(ext_cmd.u.if_name, "rmnet_mhi",
			sizeof(ext_cmd.u.if_name));
		break;
	default:
		rc = -EINVAL;
		break;
	}

	rc = copy_to_user(ifr->ifr_ifru.ifru_data, &ext_cmd,
			  sizeof(struct rmnet_ioctl_extended_s));

	if (rc)
		pr_err("%s() copy_to_user failed, error %d\n", __func__, rc);

	return rc;
}

static int iplo_vnd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
	int rc = 0;

	struct rmnet_ioctl_data_s ioctl_data;

	switch (cmd) {
	case RMNET_IOCTL_SET_LLP_IP:        /* Set RAWIP protocol */
		break;
	case RMNET_IOCTL_GET_LLP:           /* Get link protocol state */
		ioctl_data.u.operation_mode = RMNET_MODE_LLP_IP;
		if (copy_to_user(ifr->ifr_ifru.ifru_data, &ioctl_data,
				 sizeof(struct rmnet_ioctl_data_s)))
			rc = -EFAULT;
		break;
	case RMNET_IOCTL_GET_OPMODE:        /* Get operation mode      */
		ioctl_data.u.operation_mode = RMNET_MODE_LLP_IP;
		if (copy_to_user(ifr->ifr_ifru.ifru_data, &ioctl_data,
				 sizeof(struct rmnet_ioctl_data_s)))
			rc = -EFAULT;
		break;
	case RMNET_IOCTL_SET_QOS_ENABLE:
		rc = -EINVAL;
		break;
	case RMNET_IOCTL_SET_QOS_DISABLE:
		rc = 0;
		break;
	case RMNET_IOCTL_OPEN:
	case RMNET_IOCTL_CLOSE:
		/* We just ignore them and return success */
		rc = 0;
		break;
	case RMNET_IOCTL_EXTENDED:
		rc = iplo_vnd_ioctl_extended(dev, ifr);
		break;
	default:
		/* Don't fail any IOCTL right now */
		rc = 0;
		break;
	}

	return rc;
}

static int iplo_vnd_change_mtu(struct net_device *dev, int new_mtu)
{
	if (0 > new_mtu || 16384 < new_mtu)
		return -EINVAL;

	dev->mtu = new_mtu;
	return 0;
}

static const struct net_device_ops iplo_device_ops = {
	.ndo_init = 0,
	.ndo_do_ioctl = iplo_vnd_ioctl,
	.ndo_start_xmit = iplo_vnd_start_xmit,
	.ndo_change_mtu = iplo_vnd_change_mtu,
};

static void iplo_device_setup(struct net_device *dev)
{
	dev->flags |= IFF_NOARP;
	dev->netdev_ops = &iplo_device_ops;
	dev->mtu = 1500;
	dev->needed_headroom = 0;
	dev->watchdog_timeo = 100;
	dev->header_ops = 0;
	dev->type = ARPHRD_RAWIP;
	dev->hard_header_len = 0;
	dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
	dev->tx_queue_len = 1000;
}

int __init rmnet_iplo_init(void)
{
	int rc;

	pr_err("iplo: Module is coming up\n");
	mydevice = alloc_netdev(100, "rmnet_mhi0", NET_NAME_ENUM,
				iplo_device_setup);
	if (!mydevice) {
		pr_err("iplo: Failed to to allocate netdev for iplo\n");
		return -EINVAL;
	}
	rtnl_lock();
	rc = register_netdevice(mydevice);
	rtnl_unlock();
	if (rc != 0) {
		pr_err("iplo: Failed to to register netdev [%s]\n",
		       mydevice->name);
		free_netdev(mydevice);
		return -EINVAL;
	}
	return 0;
}

void __exit rmnet_iplo_exit(void)
{
	unregister_netdev(mydevice);
	free_netdev(mydevice);
	pr_err("iplo: Module is going away\n");
}

module_init(rmnet_iplo_init)
module_exit(rmnet_iplo_exit)
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("RmNet IP Loop Back Driver");
Loading