Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * WWAN device simulator for WWAN framework testing.
0004  *
0005  * Copyright (c) 2021, Sergey Ryazanov <ryazanov.s.a@gmail.com>
0006  */
0007 
0008 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/slab.h>
0013 #include <linux/device.h>
0014 #include <linux/spinlock.h>
0015 #include <linux/list.h>
0016 #include <linux/skbuff.h>
0017 #include <linux/netdevice.h>
0018 #include <linux/wwan.h>
0019 #include <linux/debugfs.h>
0020 #include <linux/workqueue.h>
0021 
0022 #include <net/arp.h>
0023 
0024 static int wwan_hwsim_devsnum = 2;
0025 module_param_named(devices, wwan_hwsim_devsnum, int, 0444);
0026 MODULE_PARM_DESC(devices, "Number of simulated devices");
0027 
0028 static struct class *wwan_hwsim_class;
0029 
0030 static struct dentry *wwan_hwsim_debugfs_topdir;
0031 static struct dentry *wwan_hwsim_debugfs_devcreate;
0032 
0033 static DEFINE_SPINLOCK(wwan_hwsim_devs_lock);
0034 static LIST_HEAD(wwan_hwsim_devs);
0035 static unsigned int wwan_hwsim_dev_idx;
0036 static struct workqueue_struct *wwan_wq;
0037 
0038 struct wwan_hwsim_dev {
0039     struct list_head list;
0040     unsigned int id;
0041     struct device dev;
0042     struct work_struct del_work;
0043     struct dentry *debugfs_topdir;
0044     struct dentry *debugfs_portcreate;
0045     spinlock_t ports_lock;  /* Serialize ports creation/deletion */
0046     unsigned int port_idx;
0047     struct list_head ports;
0048 };
0049 
0050 struct wwan_hwsim_port {
0051     struct list_head list;
0052     unsigned int id;
0053     struct wwan_hwsim_dev *dev;
0054     struct wwan_port *wwan;
0055     struct work_struct del_work;
0056     struct dentry *debugfs_topdir;
0057     enum {          /* AT command parser state */
0058         AT_PARSER_WAIT_A,
0059         AT_PARSER_WAIT_T,
0060         AT_PARSER_WAIT_TERM,
0061         AT_PARSER_SKIP_LINE,
0062     } pstate;
0063 };
0064 
0065 static const struct file_operations wwan_hwsim_debugfs_portdestroy_fops;
0066 static const struct file_operations wwan_hwsim_debugfs_portcreate_fops;
0067 static const struct file_operations wwan_hwsim_debugfs_devdestroy_fops;
0068 static void wwan_hwsim_port_del_work(struct work_struct *work);
0069 static void wwan_hwsim_dev_del_work(struct work_struct *work);
0070 
0071 static netdev_tx_t wwan_hwsim_netdev_xmit(struct sk_buff *skb,
0072                       struct net_device *ndev)
0073 {
0074     ndev->stats.tx_packets++;
0075     ndev->stats.tx_bytes += skb->len;
0076     consume_skb(skb);
0077     return NETDEV_TX_OK;
0078 }
0079 
0080 static const struct net_device_ops wwan_hwsim_netdev_ops = {
0081     .ndo_start_xmit = wwan_hwsim_netdev_xmit,
0082 };
0083 
0084 static void wwan_hwsim_netdev_setup(struct net_device *ndev)
0085 {
0086     ndev->netdev_ops = &wwan_hwsim_netdev_ops;
0087     ndev->needs_free_netdev = true;
0088 
0089     ndev->mtu = ETH_DATA_LEN;
0090     ndev->min_mtu = ETH_MIN_MTU;
0091     ndev->max_mtu = ETH_MAX_MTU;
0092 
0093     ndev->type = ARPHRD_NONE;
0094     ndev->flags = IFF_POINTOPOINT | IFF_NOARP;
0095 }
0096 
0097 static const struct wwan_ops wwan_hwsim_wwan_rtnl_ops = {
0098     .priv_size = 0,         /* No private data */
0099     .setup = wwan_hwsim_netdev_setup,
0100 };
0101 
0102 static int wwan_hwsim_port_start(struct wwan_port *wport)
0103 {
0104     struct wwan_hwsim_port *port = wwan_port_get_drvdata(wport);
0105 
0106     port->pstate = AT_PARSER_WAIT_A;
0107 
0108     return 0;
0109 }
0110 
0111 static void wwan_hwsim_port_stop(struct wwan_port *wport)
0112 {
0113 }
0114 
0115 /* Implements a minimalistic AT commands parser that echo input back and
0116  * reply with 'OK' to each input command. See AT command protocol details in the
0117  * ITU-T V.250 recomendations document.
0118  *
0119  * Be aware that this processor is not fully V.250 compliant.
0120  */
0121 static int wwan_hwsim_port_tx(struct wwan_port *wport, struct sk_buff *in)
0122 {
0123     struct wwan_hwsim_port *port = wwan_port_get_drvdata(wport);
0124     struct sk_buff *out;
0125     int i, n, s;
0126 
0127     /* Estimate a max possible number of commands by counting the number of
0128      * termination chars (S3 param, CR by default). And then allocate the
0129      * output buffer that will be enough to fit the echo and result codes of
0130      * all commands.
0131      */
0132     for (i = 0, n = 0; i < in->len; ++i)
0133         if (in->data[i] == '\r')
0134             n++;
0135     n = in->len + n * (2 + 2 + 2);  /* Output buffer size */
0136     out = alloc_skb(n, GFP_KERNEL);
0137     if (!out)
0138         return -ENOMEM;
0139 
0140     for (i = 0, s = 0; i < in->len; ++i) {
0141         char c = in->data[i];
0142 
0143         if (port->pstate == AT_PARSER_WAIT_A) {
0144             if (c == 'A' || c == 'a')
0145                 port->pstate = AT_PARSER_WAIT_T;
0146             else if (c != '\n') /* Ignore formating char */
0147                 port->pstate = AT_PARSER_SKIP_LINE;
0148         } else if (port->pstate == AT_PARSER_WAIT_T) {
0149             if (c == 'T' || c == 't')
0150                 port->pstate = AT_PARSER_WAIT_TERM;
0151             else
0152                 port->pstate = AT_PARSER_SKIP_LINE;
0153         } else if (port->pstate == AT_PARSER_WAIT_TERM) {
0154             if (c != '\r')
0155                 continue;
0156             /* Consume the trailing formatting char as well */
0157             if ((i + 1) < in->len && in->data[i + 1] == '\n')
0158                 i++;
0159             n = i - s + 1;
0160             memcpy(skb_put(out, n), &in->data[s], n);/* Echo */
0161             memcpy(skb_put(out, 6), "\r\nOK\r\n", 6);
0162             s = i + 1;
0163             port->pstate = AT_PARSER_WAIT_A;
0164         } else if (port->pstate == AT_PARSER_SKIP_LINE) {
0165             if (c != '\r')
0166                 continue;
0167             port->pstate = AT_PARSER_WAIT_A;
0168         }
0169     }
0170 
0171     if (i > s) {
0172         /* Echo the processed portion of a not yet completed command */
0173         n = i - s;
0174         memcpy(skb_put(out, n), &in->data[s], n);
0175     }
0176 
0177     consume_skb(in);
0178 
0179     wwan_port_rx(wport, out);
0180 
0181     return 0;
0182 }
0183 
0184 static const struct wwan_port_ops wwan_hwsim_port_ops = {
0185     .start = wwan_hwsim_port_start,
0186     .stop = wwan_hwsim_port_stop,
0187     .tx = wwan_hwsim_port_tx,
0188 };
0189 
0190 static struct wwan_hwsim_port *wwan_hwsim_port_new(struct wwan_hwsim_dev *dev)
0191 {
0192     struct wwan_hwsim_port *port;
0193     char name[0x10];
0194     int err;
0195 
0196     port = kzalloc(sizeof(*port), GFP_KERNEL);
0197     if (!port)
0198         return ERR_PTR(-ENOMEM);
0199 
0200     port->dev = dev;
0201 
0202     spin_lock(&dev->ports_lock);
0203     port->id = dev->port_idx++;
0204     spin_unlock(&dev->ports_lock);
0205 
0206     port->wwan = wwan_create_port(&dev->dev, WWAN_PORT_AT,
0207                       &wwan_hwsim_port_ops,
0208                       port);
0209     if (IS_ERR(port->wwan)) {
0210         err = PTR_ERR(port->wwan);
0211         goto err_free_port;
0212     }
0213 
0214     INIT_WORK(&port->del_work, wwan_hwsim_port_del_work);
0215 
0216     snprintf(name, sizeof(name), "port%u", port->id);
0217     port->debugfs_topdir = debugfs_create_dir(name, dev->debugfs_topdir);
0218     debugfs_create_file("destroy", 0200, port->debugfs_topdir, port,
0219                 &wwan_hwsim_debugfs_portdestroy_fops);
0220 
0221     return port;
0222 
0223 err_free_port:
0224     kfree(port);
0225 
0226     return ERR_PTR(err);
0227 }
0228 
0229 static void wwan_hwsim_port_del(struct wwan_hwsim_port *port)
0230 {
0231     debugfs_remove(port->debugfs_topdir);
0232 
0233     /* Make sure that there is no pending deletion work */
0234     if (current_work() != &port->del_work)
0235         cancel_work_sync(&port->del_work);
0236 
0237     wwan_remove_port(port->wwan);
0238     kfree(port);
0239 }
0240 
0241 static void wwan_hwsim_port_del_work(struct work_struct *work)
0242 {
0243     struct wwan_hwsim_port *port =
0244                 container_of(work, typeof(*port), del_work);
0245     struct wwan_hwsim_dev *dev = port->dev;
0246 
0247     spin_lock(&dev->ports_lock);
0248     if (list_empty(&port->list)) {
0249         /* Someone else deleting port at the moment */
0250         spin_unlock(&dev->ports_lock);
0251         return;
0252     }
0253     list_del_init(&port->list);
0254     spin_unlock(&dev->ports_lock);
0255 
0256     wwan_hwsim_port_del(port);
0257 }
0258 
0259 static void wwan_hwsim_dev_release(struct device *sysdev)
0260 {
0261     struct wwan_hwsim_dev *dev = container_of(sysdev, typeof(*dev), dev);
0262 
0263     kfree(dev);
0264 }
0265 
0266 static struct wwan_hwsim_dev *wwan_hwsim_dev_new(void)
0267 {
0268     struct wwan_hwsim_dev *dev;
0269     int err;
0270 
0271     dev = kzalloc(sizeof(*dev), GFP_KERNEL);
0272     if (!dev)
0273         return ERR_PTR(-ENOMEM);
0274 
0275     spin_lock(&wwan_hwsim_devs_lock);
0276     dev->id = wwan_hwsim_dev_idx++;
0277     spin_unlock(&wwan_hwsim_devs_lock);
0278 
0279     dev->dev.release = wwan_hwsim_dev_release;
0280     dev->dev.class = wwan_hwsim_class;
0281     dev_set_name(&dev->dev, "hwsim%u", dev->id);
0282 
0283     spin_lock_init(&dev->ports_lock);
0284     INIT_LIST_HEAD(&dev->ports);
0285 
0286     err = device_register(&dev->dev);
0287     if (err)
0288         goto err_free_dev;
0289 
0290     INIT_WORK(&dev->del_work, wwan_hwsim_dev_del_work);
0291 
0292     err = wwan_register_ops(&dev->dev, &wwan_hwsim_wwan_rtnl_ops, dev, 1);
0293     if (err)
0294         goto err_unreg_dev;
0295 
0296     dev->debugfs_topdir = debugfs_create_dir(dev_name(&dev->dev),
0297                          wwan_hwsim_debugfs_topdir);
0298     debugfs_create_file("destroy", 0200, dev->debugfs_topdir, dev,
0299                 &wwan_hwsim_debugfs_devdestroy_fops);
0300     dev->debugfs_portcreate =
0301         debugfs_create_file("portcreate", 0200,
0302                     dev->debugfs_topdir, dev,
0303                     &wwan_hwsim_debugfs_portcreate_fops);
0304 
0305     return dev;
0306 
0307 err_unreg_dev:
0308     device_unregister(&dev->dev);
0309     /* Memory will be freed in the device release callback */
0310 
0311     return ERR_PTR(err);
0312 
0313 err_free_dev:
0314     kfree(dev);
0315 
0316     return ERR_PTR(err);
0317 }
0318 
0319 static void wwan_hwsim_dev_del(struct wwan_hwsim_dev *dev)
0320 {
0321     debugfs_remove(dev->debugfs_portcreate);    /* Avoid new ports */
0322 
0323     spin_lock(&dev->ports_lock);
0324     while (!list_empty(&dev->ports)) {
0325         struct wwan_hwsim_port *port;
0326 
0327         port = list_first_entry(&dev->ports, struct wwan_hwsim_port,
0328                     list);
0329         list_del_init(&port->list);
0330         spin_unlock(&dev->ports_lock);
0331         wwan_hwsim_port_del(port);
0332         spin_lock(&dev->ports_lock);
0333     }
0334     spin_unlock(&dev->ports_lock);
0335 
0336     debugfs_remove(dev->debugfs_topdir);
0337 
0338     /* This will remove all child netdev(s) */
0339     wwan_unregister_ops(&dev->dev);
0340 
0341     /* Make sure that there is no pending deletion work */
0342     if (current_work() != &dev->del_work)
0343         cancel_work_sync(&dev->del_work);
0344 
0345     device_unregister(&dev->dev);
0346     /* Memory will be freed in the device release callback */
0347 }
0348 
0349 static void wwan_hwsim_dev_del_work(struct work_struct *work)
0350 {
0351     struct wwan_hwsim_dev *dev = container_of(work, typeof(*dev), del_work);
0352 
0353     spin_lock(&wwan_hwsim_devs_lock);
0354     if (list_empty(&dev->list)) {
0355         /* Someone else deleting device at the moment */
0356         spin_unlock(&wwan_hwsim_devs_lock);
0357         return;
0358     }
0359     list_del_init(&dev->list);
0360     spin_unlock(&wwan_hwsim_devs_lock);
0361 
0362     wwan_hwsim_dev_del(dev);
0363 }
0364 
0365 static ssize_t wwan_hwsim_debugfs_portdestroy_write(struct file *file,
0366                             const char __user *usrbuf,
0367                             size_t count, loff_t *ppos)
0368 {
0369     struct wwan_hwsim_port *port = file->private_data;
0370 
0371     /* We can not delete port here since it will cause a deadlock due to
0372      * waiting this callback to finish in the debugfs_remove() call. So,
0373      * use workqueue.
0374      */
0375     queue_work(wwan_wq, &port->del_work);
0376 
0377     return count;
0378 }
0379 
0380 static const struct file_operations wwan_hwsim_debugfs_portdestroy_fops = {
0381     .write = wwan_hwsim_debugfs_portdestroy_write,
0382     .open = simple_open,
0383     .llseek = noop_llseek,
0384 };
0385 
0386 static ssize_t wwan_hwsim_debugfs_portcreate_write(struct file *file,
0387                            const char __user *usrbuf,
0388                            size_t count, loff_t *ppos)
0389 {
0390     struct wwan_hwsim_dev *dev = file->private_data;
0391     struct wwan_hwsim_port *port;
0392 
0393     port = wwan_hwsim_port_new(dev);
0394     if (IS_ERR(port))
0395         return PTR_ERR(port);
0396 
0397     spin_lock(&dev->ports_lock);
0398     list_add_tail(&port->list, &dev->ports);
0399     spin_unlock(&dev->ports_lock);
0400 
0401     return count;
0402 }
0403 
0404 static const struct file_operations wwan_hwsim_debugfs_portcreate_fops = {
0405     .write = wwan_hwsim_debugfs_portcreate_write,
0406     .open = simple_open,
0407     .llseek = noop_llseek,
0408 };
0409 
0410 static ssize_t wwan_hwsim_debugfs_devdestroy_write(struct file *file,
0411                            const char __user *usrbuf,
0412                            size_t count, loff_t *ppos)
0413 {
0414     struct wwan_hwsim_dev *dev = file->private_data;
0415 
0416     /* We can not delete device here since it will cause a deadlock due to
0417      * waiting this callback to finish in the debugfs_remove() call. So,
0418      * use workqueue.
0419      */
0420     queue_work(wwan_wq, &dev->del_work);
0421 
0422     return count;
0423 }
0424 
0425 static const struct file_operations wwan_hwsim_debugfs_devdestroy_fops = {
0426     .write = wwan_hwsim_debugfs_devdestroy_write,
0427     .open = simple_open,
0428     .llseek = noop_llseek,
0429 };
0430 
0431 static ssize_t wwan_hwsim_debugfs_devcreate_write(struct file *file,
0432                           const char __user *usrbuf,
0433                           size_t count, loff_t *ppos)
0434 {
0435     struct wwan_hwsim_dev *dev;
0436 
0437     dev = wwan_hwsim_dev_new();
0438     if (IS_ERR(dev))
0439         return PTR_ERR(dev);
0440 
0441     spin_lock(&wwan_hwsim_devs_lock);
0442     list_add_tail(&dev->list, &wwan_hwsim_devs);
0443     spin_unlock(&wwan_hwsim_devs_lock);
0444 
0445     return count;
0446 }
0447 
0448 static const struct file_operations wwan_hwsim_debugfs_devcreate_fops = {
0449     .write = wwan_hwsim_debugfs_devcreate_write,
0450     .open = simple_open,
0451     .llseek = noop_llseek,
0452 };
0453 
0454 static int __init wwan_hwsim_init_devs(void)
0455 {
0456     struct wwan_hwsim_dev *dev;
0457     int i, j;
0458 
0459     for (i = 0; i < wwan_hwsim_devsnum; ++i) {
0460         dev = wwan_hwsim_dev_new();
0461         if (IS_ERR(dev))
0462             return PTR_ERR(dev);
0463 
0464         spin_lock(&wwan_hwsim_devs_lock);
0465         list_add_tail(&dev->list, &wwan_hwsim_devs);
0466         spin_unlock(&wwan_hwsim_devs_lock);
0467 
0468         /* Create a couple of ports per each device to accelerate
0469          * the simulator readiness time.
0470          */
0471         for (j = 0; j < 2; ++j) {
0472             struct wwan_hwsim_port *port;
0473 
0474             port = wwan_hwsim_port_new(dev);
0475             if (IS_ERR(port))
0476                 return PTR_ERR(port);
0477 
0478             spin_lock(&dev->ports_lock);
0479             list_add_tail(&port->list, &dev->ports);
0480             spin_unlock(&dev->ports_lock);
0481         }
0482     }
0483 
0484     return 0;
0485 }
0486 
0487 static void wwan_hwsim_free_devs(void)
0488 {
0489     struct wwan_hwsim_dev *dev;
0490 
0491     spin_lock(&wwan_hwsim_devs_lock);
0492     while (!list_empty(&wwan_hwsim_devs)) {
0493         dev = list_first_entry(&wwan_hwsim_devs, struct wwan_hwsim_dev,
0494                        list);
0495         list_del_init(&dev->list);
0496         spin_unlock(&wwan_hwsim_devs_lock);
0497         wwan_hwsim_dev_del(dev);
0498         spin_lock(&wwan_hwsim_devs_lock);
0499     }
0500     spin_unlock(&wwan_hwsim_devs_lock);
0501 }
0502 
0503 static int __init wwan_hwsim_init(void)
0504 {
0505     int err;
0506 
0507     if (wwan_hwsim_devsnum < 0 || wwan_hwsim_devsnum > 128)
0508         return -EINVAL;
0509 
0510     wwan_wq = alloc_workqueue("wwan_wq", 0, 0);
0511     if (!wwan_wq)
0512         return -ENOMEM;
0513 
0514     wwan_hwsim_class = class_create(THIS_MODULE, "wwan_hwsim");
0515     if (IS_ERR(wwan_hwsim_class)) {
0516         err = PTR_ERR(wwan_hwsim_class);
0517         goto err_wq_destroy;
0518     }
0519 
0520     wwan_hwsim_debugfs_topdir = debugfs_create_dir("wwan_hwsim", NULL);
0521     wwan_hwsim_debugfs_devcreate =
0522             debugfs_create_file("devcreate", 0200,
0523                         wwan_hwsim_debugfs_topdir, NULL,
0524                         &wwan_hwsim_debugfs_devcreate_fops);
0525 
0526     err = wwan_hwsim_init_devs();
0527     if (err)
0528         goto err_clean_devs;
0529 
0530     return 0;
0531 
0532 err_clean_devs:
0533     debugfs_remove(wwan_hwsim_debugfs_devcreate);   /* Avoid new devs */
0534     wwan_hwsim_free_devs();
0535     flush_workqueue(wwan_wq);   /* Wait deletion works completion */
0536     debugfs_remove(wwan_hwsim_debugfs_topdir);
0537     class_destroy(wwan_hwsim_class);
0538 err_wq_destroy:
0539     destroy_workqueue(wwan_wq);
0540 
0541     return err;
0542 }
0543 
0544 static void __exit wwan_hwsim_exit(void)
0545 {
0546     debugfs_remove(wwan_hwsim_debugfs_devcreate);   /* Avoid new devs */
0547     wwan_hwsim_free_devs();
0548     flush_workqueue(wwan_wq);   /* Wait deletion works completion */
0549     debugfs_remove(wwan_hwsim_debugfs_topdir);
0550     class_destroy(wwan_hwsim_class);
0551     destroy_workqueue(wwan_wq);
0552 }
0553 
0554 module_init(wwan_hwsim_init);
0555 module_exit(wwan_hwsim_exit);
0556 
0557 MODULE_AUTHOR("Sergey Ryazanov");
0558 MODULE_DESCRIPTION("Device simulator for WWAN framework");
0559 MODULE_LICENSE("GPL");