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