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

wwan_hwsim.c (14233B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * WWAN device simulator for WWAN framework testing.
      4 *
      5 * Copyright (c) 2021, Sergey Ryazanov <ryazanov.s.a@gmail.com>
      6 */
      7
      8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      9
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/slab.h>
     13#include <linux/device.h>
     14#include <linux/spinlock.h>
     15#include <linux/list.h>
     16#include <linux/skbuff.h>
     17#include <linux/netdevice.h>
     18#include <linux/wwan.h>
     19#include <linux/debugfs.h>
     20#include <linux/workqueue.h>
     21
     22#include <net/arp.h>
     23
     24static int wwan_hwsim_devsnum = 2;
     25module_param_named(devices, wwan_hwsim_devsnum, int, 0444);
     26MODULE_PARM_DESC(devices, "Number of simulated devices");
     27
     28static struct class *wwan_hwsim_class;
     29
     30static struct dentry *wwan_hwsim_debugfs_topdir;
     31static struct dentry *wwan_hwsim_debugfs_devcreate;
     32
     33static DEFINE_SPINLOCK(wwan_hwsim_devs_lock);
     34static LIST_HEAD(wwan_hwsim_devs);
     35static unsigned int wwan_hwsim_dev_idx;
     36static struct workqueue_struct *wwan_wq;
     37
     38struct wwan_hwsim_dev {
     39	struct list_head list;
     40	unsigned int id;
     41	struct device dev;
     42	struct work_struct del_work;
     43	struct dentry *debugfs_topdir;
     44	struct dentry *debugfs_portcreate;
     45	spinlock_t ports_lock;	/* Serialize ports creation/deletion */
     46	unsigned int port_idx;
     47	struct list_head ports;
     48};
     49
     50struct wwan_hwsim_port {
     51	struct list_head list;
     52	unsigned int id;
     53	struct wwan_hwsim_dev *dev;
     54	struct wwan_port *wwan;
     55	struct work_struct del_work;
     56	struct dentry *debugfs_topdir;
     57	enum {			/* AT command parser state */
     58		AT_PARSER_WAIT_A,
     59		AT_PARSER_WAIT_T,
     60		AT_PARSER_WAIT_TERM,
     61		AT_PARSER_SKIP_LINE,
     62	} pstate;
     63};
     64
     65static const struct file_operations wwan_hwsim_debugfs_portdestroy_fops;
     66static const struct file_operations wwan_hwsim_debugfs_portcreate_fops;
     67static const struct file_operations wwan_hwsim_debugfs_devdestroy_fops;
     68static void wwan_hwsim_port_del_work(struct work_struct *work);
     69static void wwan_hwsim_dev_del_work(struct work_struct *work);
     70
     71static netdev_tx_t wwan_hwsim_netdev_xmit(struct sk_buff *skb,
     72					  struct net_device *ndev)
     73{
     74	ndev->stats.tx_packets++;
     75	ndev->stats.tx_bytes += skb->len;
     76	consume_skb(skb);
     77	return NETDEV_TX_OK;
     78}
     79
     80static const struct net_device_ops wwan_hwsim_netdev_ops = {
     81	.ndo_start_xmit = wwan_hwsim_netdev_xmit,
     82};
     83
     84static void wwan_hwsim_netdev_setup(struct net_device *ndev)
     85{
     86	ndev->netdev_ops = &wwan_hwsim_netdev_ops;
     87	ndev->needs_free_netdev = true;
     88
     89	ndev->mtu = ETH_DATA_LEN;
     90	ndev->min_mtu = ETH_MIN_MTU;
     91	ndev->max_mtu = ETH_MAX_MTU;
     92
     93	ndev->type = ARPHRD_NONE;
     94	ndev->flags = IFF_POINTOPOINT | IFF_NOARP;
     95}
     96
     97static const struct wwan_ops wwan_hwsim_wwan_rtnl_ops = {
     98	.priv_size = 0,			/* No private data */
     99	.setup = wwan_hwsim_netdev_setup,
    100};
    101
    102static int wwan_hwsim_port_start(struct wwan_port *wport)
    103{
    104	struct wwan_hwsim_port *port = wwan_port_get_drvdata(wport);
    105
    106	port->pstate = AT_PARSER_WAIT_A;
    107
    108	return 0;
    109}
    110
    111static void wwan_hwsim_port_stop(struct wwan_port *wport)
    112{
    113}
    114
    115/* Implements a minimalistic AT commands parser that echo input back and
    116 * reply with 'OK' to each input command. See AT command protocol details in the
    117 * ITU-T V.250 recomendations document.
    118 *
    119 * Be aware that this processor is not fully V.250 compliant.
    120 */
    121static int wwan_hwsim_port_tx(struct wwan_port *wport, struct sk_buff *in)
    122{
    123	struct wwan_hwsim_port *port = wwan_port_get_drvdata(wport);
    124	struct sk_buff *out;
    125	int i, n, s;
    126
    127	/* Estimate a max possible number of commands by counting the number of
    128	 * termination chars (S3 param, CR by default). And then allocate the
    129	 * output buffer that will be enough to fit the echo and result codes of
    130	 * all commands.
    131	 */
    132	for (i = 0, n = 0; i < in->len; ++i)
    133		if (in->data[i] == '\r')
    134			n++;
    135	n = in->len + n * (2 + 2 + 2);	/* Output buffer size */
    136	out = alloc_skb(n, GFP_KERNEL);
    137	if (!out)
    138		return -ENOMEM;
    139
    140	for (i = 0, s = 0; i < in->len; ++i) {
    141		char c = in->data[i];
    142
    143		if (port->pstate == AT_PARSER_WAIT_A) {
    144			if (c == 'A' || c == 'a')
    145				port->pstate = AT_PARSER_WAIT_T;
    146			else if (c != '\n')	/* Ignore formating char */
    147				port->pstate = AT_PARSER_SKIP_LINE;
    148		} else if (port->pstate == AT_PARSER_WAIT_T) {
    149			if (c == 'T' || c == 't')
    150				port->pstate = AT_PARSER_WAIT_TERM;
    151			else
    152				port->pstate = AT_PARSER_SKIP_LINE;
    153		} else if (port->pstate == AT_PARSER_WAIT_TERM) {
    154			if (c != '\r')
    155				continue;
    156			/* Consume the trailing formatting char as well */
    157			if ((i + 1) < in->len && in->data[i + 1] == '\n')
    158				i++;
    159			n = i - s + 1;
    160			memcpy(skb_put(out, n), &in->data[s], n);/* Echo */
    161			memcpy(skb_put(out, 6), "\r\nOK\r\n", 6);
    162			s = i + 1;
    163			port->pstate = AT_PARSER_WAIT_A;
    164		} else if (port->pstate == AT_PARSER_SKIP_LINE) {
    165			if (c != '\r')
    166				continue;
    167			port->pstate = AT_PARSER_WAIT_A;
    168		}
    169	}
    170
    171	if (i > s) {
    172		/* Echo the processed portion of a not yet completed command */
    173		n = i - s;
    174		memcpy(skb_put(out, n), &in->data[s], n);
    175	}
    176
    177	consume_skb(in);
    178
    179	wwan_port_rx(wport, out);
    180
    181	return 0;
    182}
    183
    184static const struct wwan_port_ops wwan_hwsim_port_ops = {
    185	.start = wwan_hwsim_port_start,
    186	.stop = wwan_hwsim_port_stop,
    187	.tx = wwan_hwsim_port_tx,
    188};
    189
    190static struct wwan_hwsim_port *wwan_hwsim_port_new(struct wwan_hwsim_dev *dev)
    191{
    192	struct wwan_hwsim_port *port;
    193	char name[0x10];
    194	int err;
    195
    196	port = kzalloc(sizeof(*port), GFP_KERNEL);
    197	if (!port)
    198		return ERR_PTR(-ENOMEM);
    199
    200	port->dev = dev;
    201
    202	spin_lock(&dev->ports_lock);
    203	port->id = dev->port_idx++;
    204	spin_unlock(&dev->ports_lock);
    205
    206	port->wwan = wwan_create_port(&dev->dev, WWAN_PORT_AT,
    207				      &wwan_hwsim_port_ops,
    208				      port);
    209	if (IS_ERR(port->wwan)) {
    210		err = PTR_ERR(port->wwan);
    211		goto err_free_port;
    212	}
    213
    214	INIT_WORK(&port->del_work, wwan_hwsim_port_del_work);
    215
    216	snprintf(name, sizeof(name), "port%u", port->id);
    217	port->debugfs_topdir = debugfs_create_dir(name, dev->debugfs_topdir);
    218	debugfs_create_file("destroy", 0200, port->debugfs_topdir, port,
    219			    &wwan_hwsim_debugfs_portdestroy_fops);
    220
    221	return port;
    222
    223err_free_port:
    224	kfree(port);
    225
    226	return ERR_PTR(err);
    227}
    228
    229static void wwan_hwsim_port_del(struct wwan_hwsim_port *port)
    230{
    231	debugfs_remove(port->debugfs_topdir);
    232
    233	/* Make sure that there is no pending deletion work */
    234	if (current_work() != &port->del_work)
    235		cancel_work_sync(&port->del_work);
    236
    237	wwan_remove_port(port->wwan);
    238	kfree(port);
    239}
    240
    241static void wwan_hwsim_port_del_work(struct work_struct *work)
    242{
    243	struct wwan_hwsim_port *port =
    244				container_of(work, typeof(*port), del_work);
    245	struct wwan_hwsim_dev *dev = port->dev;
    246
    247	spin_lock(&dev->ports_lock);
    248	if (list_empty(&port->list)) {
    249		/* Someone else deleting port at the moment */
    250		spin_unlock(&dev->ports_lock);
    251		return;
    252	}
    253	list_del_init(&port->list);
    254	spin_unlock(&dev->ports_lock);
    255
    256	wwan_hwsim_port_del(port);
    257}
    258
    259static void wwan_hwsim_dev_release(struct device *sysdev)
    260{
    261	struct wwan_hwsim_dev *dev = container_of(sysdev, typeof(*dev), dev);
    262
    263	kfree(dev);
    264}
    265
    266static struct wwan_hwsim_dev *wwan_hwsim_dev_new(void)
    267{
    268	struct wwan_hwsim_dev *dev;
    269	int err;
    270
    271	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    272	if (!dev)
    273		return ERR_PTR(-ENOMEM);
    274
    275	spin_lock(&wwan_hwsim_devs_lock);
    276	dev->id = wwan_hwsim_dev_idx++;
    277	spin_unlock(&wwan_hwsim_devs_lock);
    278
    279	dev->dev.release = wwan_hwsim_dev_release;
    280	dev->dev.class = wwan_hwsim_class;
    281	dev_set_name(&dev->dev, "hwsim%u", dev->id);
    282
    283	spin_lock_init(&dev->ports_lock);
    284	INIT_LIST_HEAD(&dev->ports);
    285
    286	err = device_register(&dev->dev);
    287	if (err)
    288		goto err_free_dev;
    289
    290	INIT_WORK(&dev->del_work, wwan_hwsim_dev_del_work);
    291
    292	err = wwan_register_ops(&dev->dev, &wwan_hwsim_wwan_rtnl_ops, dev, 1);
    293	if (err)
    294		goto err_unreg_dev;
    295
    296	dev->debugfs_topdir = debugfs_create_dir(dev_name(&dev->dev),
    297						 wwan_hwsim_debugfs_topdir);
    298	debugfs_create_file("destroy", 0200, dev->debugfs_topdir, dev,
    299			    &wwan_hwsim_debugfs_devdestroy_fops);
    300	dev->debugfs_portcreate =
    301		debugfs_create_file("portcreate", 0200,
    302				    dev->debugfs_topdir, dev,
    303				    &wwan_hwsim_debugfs_portcreate_fops);
    304
    305	return dev;
    306
    307err_unreg_dev:
    308	device_unregister(&dev->dev);
    309	/* Memory will be freed in the device release callback */
    310
    311	return ERR_PTR(err);
    312
    313err_free_dev:
    314	kfree(dev);
    315
    316	return ERR_PTR(err);
    317}
    318
    319static void wwan_hwsim_dev_del(struct wwan_hwsim_dev *dev)
    320{
    321	debugfs_remove(dev->debugfs_portcreate);	/* Avoid new ports */
    322
    323	spin_lock(&dev->ports_lock);
    324	while (!list_empty(&dev->ports)) {
    325		struct wwan_hwsim_port *port;
    326
    327		port = list_first_entry(&dev->ports, struct wwan_hwsim_port,
    328					list);
    329		list_del_init(&port->list);
    330		spin_unlock(&dev->ports_lock);
    331		wwan_hwsim_port_del(port);
    332		spin_lock(&dev->ports_lock);
    333	}
    334	spin_unlock(&dev->ports_lock);
    335
    336	debugfs_remove(dev->debugfs_topdir);
    337
    338	/* This will remove all child netdev(s) */
    339	wwan_unregister_ops(&dev->dev);
    340
    341	/* Make sure that there is no pending deletion work */
    342	if (current_work() != &dev->del_work)
    343		cancel_work_sync(&dev->del_work);
    344
    345	device_unregister(&dev->dev);
    346	/* Memory will be freed in the device release callback */
    347}
    348
    349static void wwan_hwsim_dev_del_work(struct work_struct *work)
    350{
    351	struct wwan_hwsim_dev *dev = container_of(work, typeof(*dev), del_work);
    352
    353	spin_lock(&wwan_hwsim_devs_lock);
    354	if (list_empty(&dev->list)) {
    355		/* Someone else deleting device at the moment */
    356		spin_unlock(&wwan_hwsim_devs_lock);
    357		return;
    358	}
    359	list_del_init(&dev->list);
    360	spin_unlock(&wwan_hwsim_devs_lock);
    361
    362	wwan_hwsim_dev_del(dev);
    363}
    364
    365static ssize_t wwan_hwsim_debugfs_portdestroy_write(struct file *file,
    366						    const char __user *usrbuf,
    367						    size_t count, loff_t *ppos)
    368{
    369	struct wwan_hwsim_port *port = file->private_data;
    370
    371	/* We can not delete port here since it will cause a deadlock due to
    372	 * waiting this callback to finish in the debugfs_remove() call. So,
    373	 * use workqueue.
    374	 */
    375	queue_work(wwan_wq, &port->del_work);
    376
    377	return count;
    378}
    379
    380static const struct file_operations wwan_hwsim_debugfs_portdestroy_fops = {
    381	.write = wwan_hwsim_debugfs_portdestroy_write,
    382	.open = simple_open,
    383	.llseek = noop_llseek,
    384};
    385
    386static ssize_t wwan_hwsim_debugfs_portcreate_write(struct file *file,
    387						   const char __user *usrbuf,
    388						   size_t count, loff_t *ppos)
    389{
    390	struct wwan_hwsim_dev *dev = file->private_data;
    391	struct wwan_hwsim_port *port;
    392
    393	port = wwan_hwsim_port_new(dev);
    394	if (IS_ERR(port))
    395		return PTR_ERR(port);
    396
    397	spin_lock(&dev->ports_lock);
    398	list_add_tail(&port->list, &dev->ports);
    399	spin_unlock(&dev->ports_lock);
    400
    401	return count;
    402}
    403
    404static const struct file_operations wwan_hwsim_debugfs_portcreate_fops = {
    405	.write = wwan_hwsim_debugfs_portcreate_write,
    406	.open = simple_open,
    407	.llseek = noop_llseek,
    408};
    409
    410static ssize_t wwan_hwsim_debugfs_devdestroy_write(struct file *file,
    411						   const char __user *usrbuf,
    412						   size_t count, loff_t *ppos)
    413{
    414	struct wwan_hwsim_dev *dev = file->private_data;
    415
    416	/* We can not delete device here since it will cause a deadlock due to
    417	 * waiting this callback to finish in the debugfs_remove() call. So,
    418	 * use workqueue.
    419	 */
    420	queue_work(wwan_wq, &dev->del_work);
    421
    422	return count;
    423}
    424
    425static const struct file_operations wwan_hwsim_debugfs_devdestroy_fops = {
    426	.write = wwan_hwsim_debugfs_devdestroy_write,
    427	.open = simple_open,
    428	.llseek = noop_llseek,
    429};
    430
    431static ssize_t wwan_hwsim_debugfs_devcreate_write(struct file *file,
    432						  const char __user *usrbuf,
    433						  size_t count, loff_t *ppos)
    434{
    435	struct wwan_hwsim_dev *dev;
    436
    437	dev = wwan_hwsim_dev_new();
    438	if (IS_ERR(dev))
    439		return PTR_ERR(dev);
    440
    441	spin_lock(&wwan_hwsim_devs_lock);
    442	list_add_tail(&dev->list, &wwan_hwsim_devs);
    443	spin_unlock(&wwan_hwsim_devs_lock);
    444
    445	return count;
    446}
    447
    448static const struct file_operations wwan_hwsim_debugfs_devcreate_fops = {
    449	.write = wwan_hwsim_debugfs_devcreate_write,
    450	.open = simple_open,
    451	.llseek = noop_llseek,
    452};
    453
    454static int __init wwan_hwsim_init_devs(void)
    455{
    456	struct wwan_hwsim_dev *dev;
    457	int i, j;
    458
    459	for (i = 0; i < wwan_hwsim_devsnum; ++i) {
    460		dev = wwan_hwsim_dev_new();
    461		if (IS_ERR(dev))
    462			return PTR_ERR(dev);
    463
    464		spin_lock(&wwan_hwsim_devs_lock);
    465		list_add_tail(&dev->list, &wwan_hwsim_devs);
    466		spin_unlock(&wwan_hwsim_devs_lock);
    467
    468		/* Create a couple of ports per each device to accelerate
    469		 * the simulator readiness time.
    470		 */
    471		for (j = 0; j < 2; ++j) {
    472			struct wwan_hwsim_port *port;
    473
    474			port = wwan_hwsim_port_new(dev);
    475			if (IS_ERR(port))
    476				return PTR_ERR(port);
    477
    478			spin_lock(&dev->ports_lock);
    479			list_add_tail(&port->list, &dev->ports);
    480			spin_unlock(&dev->ports_lock);
    481		}
    482	}
    483
    484	return 0;
    485}
    486
    487static void wwan_hwsim_free_devs(void)
    488{
    489	struct wwan_hwsim_dev *dev;
    490
    491	spin_lock(&wwan_hwsim_devs_lock);
    492	while (!list_empty(&wwan_hwsim_devs)) {
    493		dev = list_first_entry(&wwan_hwsim_devs, struct wwan_hwsim_dev,
    494				       list);
    495		list_del_init(&dev->list);
    496		spin_unlock(&wwan_hwsim_devs_lock);
    497		wwan_hwsim_dev_del(dev);
    498		spin_lock(&wwan_hwsim_devs_lock);
    499	}
    500	spin_unlock(&wwan_hwsim_devs_lock);
    501}
    502
    503static int __init wwan_hwsim_init(void)
    504{
    505	int err;
    506
    507	if (wwan_hwsim_devsnum < 0 || wwan_hwsim_devsnum > 128)
    508		return -EINVAL;
    509
    510	wwan_wq = alloc_workqueue("wwan_wq", 0, 0);
    511	if (!wwan_wq)
    512		return -ENOMEM;
    513
    514	wwan_hwsim_class = class_create(THIS_MODULE, "wwan_hwsim");
    515	if (IS_ERR(wwan_hwsim_class)) {
    516		err = PTR_ERR(wwan_hwsim_class);
    517		goto err_wq_destroy;
    518	}
    519
    520	wwan_hwsim_debugfs_topdir = debugfs_create_dir("wwan_hwsim", NULL);
    521	wwan_hwsim_debugfs_devcreate =
    522			debugfs_create_file("devcreate", 0200,
    523					    wwan_hwsim_debugfs_topdir, NULL,
    524					    &wwan_hwsim_debugfs_devcreate_fops);
    525
    526	err = wwan_hwsim_init_devs();
    527	if (err)
    528		goto err_clean_devs;
    529
    530	return 0;
    531
    532err_clean_devs:
    533	debugfs_remove(wwan_hwsim_debugfs_devcreate);	/* Avoid new devs */
    534	wwan_hwsim_free_devs();
    535	flush_workqueue(wwan_wq);	/* Wait deletion works completion */
    536	debugfs_remove(wwan_hwsim_debugfs_topdir);
    537	class_destroy(wwan_hwsim_class);
    538err_wq_destroy:
    539	destroy_workqueue(wwan_wq);
    540
    541	return err;
    542}
    543
    544static void __exit wwan_hwsim_exit(void)
    545{
    546	debugfs_remove(wwan_hwsim_debugfs_devcreate);	/* Avoid new devs */
    547	wwan_hwsim_free_devs();
    548	flush_workqueue(wwan_wq);	/* Wait deletion works completion */
    549	debugfs_remove(wwan_hwsim_debugfs_topdir);
    550	class_destroy(wwan_hwsim_class);
    551	destroy_workqueue(wwan_wq);
    552}
    553
    554module_init(wwan_hwsim_init);
    555module_exit(wwan_hwsim_exit);
    556
    557MODULE_AUTHOR("Sergey Ryazanov");
    558MODULE_DESCRIPTION("Device simulator for WWAN framework");
    559MODULE_LICENSE("GPL");