cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

lapbether.c (12262B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *	"LAPB via ethernet" driver release 001
      4 *
      5 *	This code REQUIRES 2.1.15 or higher/ NET3.038
      6 *
      7 *	This is a "pseudo" network driver to allow LAPB over Ethernet.
      8 *
      9 *	This driver can use any ethernet destination address, and can be
     10 *	limited to accept frames from one dedicated ethernet card only.
     11 *
     12 *	History
     13 *	LAPBETH 001	Jonathan Naylor		Cloned from bpqether.c
     14 *	2000-10-29	Henner Eisen	lapb_data_indication() return status.
     15 *	2000-11-14	Henner Eisen	dev_hold/put, NETDEV_GOING_DOWN support
     16 */
     17
     18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     19
     20#include <linux/errno.h>
     21#include <linux/types.h>
     22#include <linux/socket.h>
     23#include <linux/in.h>
     24#include <linux/slab.h>
     25#include <linux/kernel.h>
     26#include <linux/string.h>
     27#include <linux/net.h>
     28#include <linux/inet.h>
     29#include <linux/netdevice.h>
     30#include <linux/if_arp.h>
     31#include <linux/skbuff.h>
     32#include <net/sock.h>
     33#include <linux/uaccess.h>
     34#include <linux/mm.h>
     35#include <linux/interrupt.h>
     36#include <linux/notifier.h>
     37#include <linux/stat.h>
     38#include <linux/module.h>
     39#include <linux/lapb.h>
     40#include <linux/init.h>
     41
     42#include <net/x25device.h>
     43
     44static const u8 bcast_addr[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
     45
     46/* If this number is made larger, check that the temporary string buffer
     47 * in lapbeth_new_device is large enough to store the probe device name.
     48 */
     49#define MAXLAPBDEV 100
     50
     51struct lapbethdev {
     52	struct list_head	node;
     53	struct net_device	*ethdev;	/* link to ethernet device */
     54	struct net_device	*axdev;		/* lapbeth device (lapb#) */
     55	bool			up;
     56	spinlock_t		up_lock;	/* Protects "up" */
     57	struct sk_buff_head	rx_queue;
     58	struct napi_struct	napi;
     59};
     60
     61static LIST_HEAD(lapbeth_devices);
     62
     63static void lapbeth_connected(struct net_device *dev, int reason);
     64static void lapbeth_disconnected(struct net_device *dev, int reason);
     65
     66/* ------------------------------------------------------------------------ */
     67
     68/*	Get the LAPB device for the ethernet device
     69 */
     70static struct lapbethdev *lapbeth_get_x25_dev(struct net_device *dev)
     71{
     72	struct lapbethdev *lapbeth;
     73
     74	list_for_each_entry_rcu(lapbeth, &lapbeth_devices, node, lockdep_rtnl_is_held()) {
     75		if (lapbeth->ethdev == dev)
     76			return lapbeth;
     77	}
     78	return NULL;
     79}
     80
     81static __inline__ int dev_is_ethdev(struct net_device *dev)
     82{
     83	return dev->type == ARPHRD_ETHER && strncmp(dev->name, "dummy", 5);
     84}
     85
     86/* ------------------------------------------------------------------------ */
     87
     88static int lapbeth_napi_poll(struct napi_struct *napi, int budget)
     89{
     90	struct lapbethdev *lapbeth = container_of(napi, struct lapbethdev,
     91						  napi);
     92	struct sk_buff *skb;
     93	int processed = 0;
     94
     95	for (; processed < budget; ++processed) {
     96		skb = skb_dequeue(&lapbeth->rx_queue);
     97		if (!skb)
     98			break;
     99		netif_receive_skb_core(skb);
    100	}
    101
    102	if (processed < budget)
    103		napi_complete(napi);
    104
    105	return processed;
    106}
    107
    108/*	Receive a LAPB frame via an ethernet interface.
    109 */
    110static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev,
    111		       struct packet_type *ptype, struct net_device *orig_dev)
    112{
    113	int len, err;
    114	struct lapbethdev *lapbeth;
    115
    116	if (dev_net(dev) != &init_net)
    117		goto drop;
    118
    119	skb = skb_share_check(skb, GFP_ATOMIC);
    120	if (!skb)
    121		return NET_RX_DROP;
    122
    123	if (!pskb_may_pull(skb, 2))
    124		goto drop;
    125
    126	rcu_read_lock();
    127	lapbeth = lapbeth_get_x25_dev(dev);
    128	if (!lapbeth)
    129		goto drop_unlock_rcu;
    130	spin_lock_bh(&lapbeth->up_lock);
    131	if (!lapbeth->up)
    132		goto drop_unlock;
    133
    134	len = skb->data[0] + skb->data[1] * 256;
    135	dev->stats.rx_packets++;
    136	dev->stats.rx_bytes += len;
    137
    138	skb_pull(skb, 2);	/* Remove the length bytes */
    139	skb_trim(skb, len);	/* Set the length of the data */
    140
    141	err = lapb_data_received(lapbeth->axdev, skb);
    142	if (err != LAPB_OK) {
    143		printk(KERN_DEBUG "lapbether: lapb_data_received err - %d\n", err);
    144		goto drop_unlock;
    145	}
    146out:
    147	spin_unlock_bh(&lapbeth->up_lock);
    148	rcu_read_unlock();
    149	return 0;
    150drop_unlock:
    151	kfree_skb(skb);
    152	goto out;
    153drop_unlock_rcu:
    154	rcu_read_unlock();
    155drop:
    156	kfree_skb(skb);
    157	return 0;
    158}
    159
    160static int lapbeth_data_indication(struct net_device *dev, struct sk_buff *skb)
    161{
    162	struct lapbethdev *lapbeth = netdev_priv(dev);
    163	unsigned char *ptr;
    164
    165	if (skb_cow(skb, 1)) {
    166		kfree_skb(skb);
    167		return NET_RX_DROP;
    168	}
    169
    170	skb_push(skb, 1);
    171
    172	ptr  = skb->data;
    173	*ptr = X25_IFACE_DATA;
    174
    175	skb->protocol = x25_type_trans(skb, dev);
    176
    177	skb_queue_tail(&lapbeth->rx_queue, skb);
    178	napi_schedule(&lapbeth->napi);
    179	return NET_RX_SUCCESS;
    180}
    181
    182/*	Send a LAPB frame via an ethernet interface
    183 */
    184static netdev_tx_t lapbeth_xmit(struct sk_buff *skb,
    185				struct net_device *dev)
    186{
    187	struct lapbethdev *lapbeth = netdev_priv(dev);
    188	int err;
    189
    190	spin_lock_bh(&lapbeth->up_lock);
    191	if (!lapbeth->up)
    192		goto drop;
    193
    194	/* There should be a pseudo header of 1 byte added by upper layers.
    195	 * Check to make sure it is there before reading it.
    196	 */
    197	if (skb->len < 1)
    198		goto drop;
    199
    200	switch (skb->data[0]) {
    201	case X25_IFACE_DATA:
    202		break;
    203	case X25_IFACE_CONNECT:
    204		err = lapb_connect_request(dev);
    205		if (err == LAPB_CONNECTED)
    206			lapbeth_connected(dev, LAPB_OK);
    207		else if (err != LAPB_OK)
    208			pr_err("lapb_connect_request error: %d\n", err);
    209		goto drop;
    210	case X25_IFACE_DISCONNECT:
    211		err = lapb_disconnect_request(dev);
    212		if (err == LAPB_NOTCONNECTED)
    213			lapbeth_disconnected(dev, LAPB_OK);
    214		else if (err != LAPB_OK)
    215			pr_err("lapb_disconnect_request err: %d\n", err);
    216		fallthrough;
    217	default:
    218		goto drop;
    219	}
    220
    221	skb_pull(skb, 1);
    222
    223	err = lapb_data_request(dev, skb);
    224	if (err != LAPB_OK) {
    225		pr_err("lapb_data_request error - %d\n", err);
    226		goto drop;
    227	}
    228out:
    229	spin_unlock_bh(&lapbeth->up_lock);
    230	return NETDEV_TX_OK;
    231drop:
    232	kfree_skb(skb);
    233	goto out;
    234}
    235
    236static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb)
    237{
    238	struct lapbethdev *lapbeth = netdev_priv(ndev);
    239	unsigned char *ptr;
    240	struct net_device *dev;
    241	int size = skb->len;
    242
    243	ptr = skb_push(skb, 2);
    244
    245	*ptr++ = size % 256;
    246	*ptr++ = size / 256;
    247
    248	ndev->stats.tx_packets++;
    249	ndev->stats.tx_bytes += size;
    250
    251	skb->dev = dev = lapbeth->ethdev;
    252
    253	skb->protocol = htons(ETH_P_DEC);
    254
    255	skb_reset_network_header(skb);
    256
    257	dev_hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
    258
    259	dev_queue_xmit(skb);
    260}
    261
    262static void lapbeth_connected(struct net_device *dev, int reason)
    263{
    264	struct lapbethdev *lapbeth = netdev_priv(dev);
    265	unsigned char *ptr;
    266	struct sk_buff *skb = __dev_alloc_skb(1, GFP_ATOMIC | __GFP_NOMEMALLOC);
    267
    268	if (!skb)
    269		return;
    270
    271	ptr  = skb_put(skb, 1);
    272	*ptr = X25_IFACE_CONNECT;
    273
    274	skb->protocol = x25_type_trans(skb, dev);
    275
    276	skb_queue_tail(&lapbeth->rx_queue, skb);
    277	napi_schedule(&lapbeth->napi);
    278}
    279
    280static void lapbeth_disconnected(struct net_device *dev, int reason)
    281{
    282	struct lapbethdev *lapbeth = netdev_priv(dev);
    283	unsigned char *ptr;
    284	struct sk_buff *skb = __dev_alloc_skb(1, GFP_ATOMIC | __GFP_NOMEMALLOC);
    285
    286	if (!skb)
    287		return;
    288
    289	ptr  = skb_put(skb, 1);
    290	*ptr = X25_IFACE_DISCONNECT;
    291
    292	skb->protocol = x25_type_trans(skb, dev);
    293
    294	skb_queue_tail(&lapbeth->rx_queue, skb);
    295	napi_schedule(&lapbeth->napi);
    296}
    297
    298/*	Set AX.25 callsign
    299 */
    300static int lapbeth_set_mac_address(struct net_device *dev, void *addr)
    301{
    302	struct sockaddr *sa = addr;
    303
    304	dev_addr_set(dev, sa->sa_data);
    305	return 0;
    306}
    307
    308static const struct lapb_register_struct lapbeth_callbacks = {
    309	.connect_confirmation    = lapbeth_connected,
    310	.connect_indication      = lapbeth_connected,
    311	.disconnect_confirmation = lapbeth_disconnected,
    312	.disconnect_indication   = lapbeth_disconnected,
    313	.data_indication         = lapbeth_data_indication,
    314	.data_transmit           = lapbeth_data_transmit,
    315};
    316
    317/* open/close a device
    318 */
    319static int lapbeth_open(struct net_device *dev)
    320{
    321	struct lapbethdev *lapbeth = netdev_priv(dev);
    322	int err;
    323
    324	napi_enable(&lapbeth->napi);
    325
    326	err = lapb_register(dev, &lapbeth_callbacks);
    327	if (err != LAPB_OK) {
    328		pr_err("lapb_register error: %d\n", err);
    329		return -ENODEV;
    330	}
    331
    332	spin_lock_bh(&lapbeth->up_lock);
    333	lapbeth->up = true;
    334	spin_unlock_bh(&lapbeth->up_lock);
    335
    336	return 0;
    337}
    338
    339static int lapbeth_close(struct net_device *dev)
    340{
    341	struct lapbethdev *lapbeth = netdev_priv(dev);
    342	int err;
    343
    344	spin_lock_bh(&lapbeth->up_lock);
    345	lapbeth->up = false;
    346	spin_unlock_bh(&lapbeth->up_lock);
    347
    348	err = lapb_unregister(dev);
    349	if (err != LAPB_OK)
    350		pr_err("lapb_unregister error: %d\n", err);
    351
    352	napi_disable(&lapbeth->napi);
    353
    354	return 0;
    355}
    356
    357/* ------------------------------------------------------------------------ */
    358
    359static const struct net_device_ops lapbeth_netdev_ops = {
    360	.ndo_open	     = lapbeth_open,
    361	.ndo_stop	     = lapbeth_close,
    362	.ndo_start_xmit	     = lapbeth_xmit,
    363	.ndo_set_mac_address = lapbeth_set_mac_address,
    364};
    365
    366static void lapbeth_setup(struct net_device *dev)
    367{
    368	dev->netdev_ops	     = &lapbeth_netdev_ops;
    369	dev->needs_free_netdev = true;
    370	dev->type            = ARPHRD_X25;
    371	dev->hard_header_len = 0;
    372	dev->mtu             = 1000;
    373	dev->addr_len        = 0;
    374}
    375
    376/*	Setup a new device.
    377 */
    378static int lapbeth_new_device(struct net_device *dev)
    379{
    380	struct net_device *ndev;
    381	struct lapbethdev *lapbeth;
    382	int rc = -ENOMEM;
    383
    384	ASSERT_RTNL();
    385
    386	ndev = alloc_netdev(sizeof(*lapbeth), "lapb%d", NET_NAME_UNKNOWN,
    387			    lapbeth_setup);
    388	if (!ndev)
    389		goto out;
    390
    391	/* When transmitting data:
    392	 * first this driver removes a pseudo header of 1 byte,
    393	 * then the lapb module prepends an LAPB header of at most 3 bytes,
    394	 * then this driver prepends a length field of 2 bytes,
    395	 * then the underlying Ethernet device prepends its own header.
    396	 */
    397	ndev->needed_headroom = -1 + 3 + 2 + dev->hard_header_len
    398					   + dev->needed_headroom;
    399	ndev->needed_tailroom = dev->needed_tailroom;
    400
    401	lapbeth = netdev_priv(ndev);
    402	lapbeth->axdev = ndev;
    403
    404	dev_hold(dev);
    405	lapbeth->ethdev = dev;
    406
    407	lapbeth->up = false;
    408	spin_lock_init(&lapbeth->up_lock);
    409
    410	skb_queue_head_init(&lapbeth->rx_queue);
    411	netif_napi_add_weight(ndev, &lapbeth->napi, lapbeth_napi_poll, 16);
    412
    413	rc = -EIO;
    414	if (register_netdevice(ndev))
    415		goto fail;
    416
    417	list_add_rcu(&lapbeth->node, &lapbeth_devices);
    418	rc = 0;
    419out:
    420	return rc;
    421fail:
    422	dev_put(dev);
    423	free_netdev(ndev);
    424	goto out;
    425}
    426
    427/*	Free a lapb network device.
    428 */
    429static void lapbeth_free_device(struct lapbethdev *lapbeth)
    430{
    431	dev_put(lapbeth->ethdev);
    432	list_del_rcu(&lapbeth->node);
    433	unregister_netdevice(lapbeth->axdev);
    434}
    435
    436/*	Handle device status changes.
    437 *
    438 * Called from notifier with RTNL held.
    439 */
    440static int lapbeth_device_event(struct notifier_block *this,
    441				unsigned long event, void *ptr)
    442{
    443	struct lapbethdev *lapbeth;
    444	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
    445
    446	if (dev_net(dev) != &init_net)
    447		return NOTIFY_DONE;
    448
    449	if (!dev_is_ethdev(dev))
    450		return NOTIFY_DONE;
    451
    452	switch (event) {
    453	case NETDEV_UP:
    454		/* New ethernet device -> new LAPB interface	 */
    455		if (!lapbeth_get_x25_dev(dev))
    456			lapbeth_new_device(dev);
    457		break;
    458	case NETDEV_GOING_DOWN:
    459		/* ethernet device closes -> close LAPB interface */
    460		lapbeth = lapbeth_get_x25_dev(dev);
    461		if (lapbeth)
    462			dev_close(lapbeth->axdev);
    463		break;
    464	case NETDEV_UNREGISTER:
    465		/* ethernet device disappears -> remove LAPB interface */
    466		lapbeth = lapbeth_get_x25_dev(dev);
    467		if (lapbeth)
    468			lapbeth_free_device(lapbeth);
    469		break;
    470	}
    471
    472	return NOTIFY_DONE;
    473}
    474
    475/* ------------------------------------------------------------------------ */
    476
    477static struct packet_type lapbeth_packet_type __read_mostly = {
    478	.type = cpu_to_be16(ETH_P_DEC),
    479	.func = lapbeth_rcv,
    480};
    481
    482static struct notifier_block lapbeth_dev_notifier = {
    483	.notifier_call = lapbeth_device_event,
    484};
    485
    486static const char banner[] __initconst =
    487	KERN_INFO "LAPB Ethernet driver version 0.02\n";
    488
    489static int __init lapbeth_init_driver(void)
    490{
    491	dev_add_pack(&lapbeth_packet_type);
    492
    493	register_netdevice_notifier(&lapbeth_dev_notifier);
    494
    495	printk(banner);
    496
    497	return 0;
    498}
    499module_init(lapbeth_init_driver);
    500
    501static void __exit lapbeth_cleanup_driver(void)
    502{
    503	struct lapbethdev *lapbeth;
    504	struct list_head *entry, *tmp;
    505
    506	dev_remove_pack(&lapbeth_packet_type);
    507	unregister_netdevice_notifier(&lapbeth_dev_notifier);
    508
    509	rtnl_lock();
    510	list_for_each_safe(entry, tmp, &lapbeth_devices) {
    511		lapbeth = list_entry(entry, struct lapbethdev, node);
    512
    513		dev_put(lapbeth->ethdev);
    514		unregister_netdevice(lapbeth->axdev);
    515	}
    516	rtnl_unlock();
    517}
    518module_exit(lapbeth_cleanup_driver);
    519
    520MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
    521MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver");
    522MODULE_LICENSE("GPL");