1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Virtual NCI device simulation driver 4 * 5 * Copyright (C) 2020 Samsung Electrnoics 6 * Bongsu Jeon <bongsu.jeon@samsung.com> 7 */ 8 9 #include <linux/kernel.h> 10 #include <linux/module.h> 11 #include <linux/miscdevice.h> 12 #include <linux/mutex.h> 13 #include <linux/wait.h> 14 #include <net/nfc/nci_core.h> 15 16 #define IOCTL_GET_NCIDEV_IDX 0 17 #define VIRTUAL_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \ 18 NFC_PROTO_MIFARE_MASK | \ 19 NFC_PROTO_FELICA_MASK | \ 20 NFC_PROTO_ISO14443_MASK | \ 21 NFC_PROTO_ISO14443_B_MASK | \ 22 NFC_PROTO_ISO15693_MASK) 23 24 struct virtual_nci_dev { 25 struct nci_dev *ndev; 26 struct mutex mtx; 27 struct sk_buff *send_buff; 28 struct wait_queue_head wq; 29 bool running; 30 }; 31 32 static int virtual_nci_open(struct nci_dev *ndev) 33 { 34 struct virtual_nci_dev *vdev = nci_get_drvdata(ndev); 35 36 vdev->running = true; 37 return 0; 38 } 39 40 static int virtual_nci_close(struct nci_dev *ndev) 41 { 42 struct virtual_nci_dev *vdev = nci_get_drvdata(ndev); 43 44 mutex_lock(&vdev->mtx); 45 kfree_skb(vdev->send_buff); 46 vdev->send_buff = NULL; 47 vdev->running = false; 48 mutex_unlock(&vdev->mtx); 49 50 return 0; 51 } 52 53 static int virtual_nci_send(struct nci_dev *ndev, struct sk_buff *skb) 54 { 55 struct virtual_nci_dev *vdev = nci_get_drvdata(ndev); 56 57 mutex_lock(&vdev->mtx); 58 if (vdev->send_buff || !vdev->running) { 59 mutex_unlock(&vdev->mtx); 60 kfree_skb(skb); 61 return -1; 62 } 63 vdev->send_buff = skb_copy(skb, GFP_KERNEL); 64 if (!vdev->send_buff) { 65 mutex_unlock(&vdev->mtx); 66 kfree_skb(skb); 67 return -1; 68 } 69 mutex_unlock(&vdev->mtx); 70 wake_up_interruptible(&vdev->wq); 71 consume_skb(skb); 72 73 return 0; 74 } 75 76 static const struct nci_ops virtual_nci_ops = { 77 .open = virtual_nci_open, 78 .close = virtual_nci_close, 79 .send = virtual_nci_send 80 }; 81 82 static ssize_t virtual_ncidev_read(struct file *file, char __user *buf, 83 size_t count, loff_t *ppos) 84 { 85 struct virtual_nci_dev *vdev = file->private_data; 86 size_t actual_len; 87 88 mutex_lock(&vdev->mtx); 89 while (!vdev->send_buff) { 90 mutex_unlock(&vdev->mtx); 91 if (wait_event_interruptible(vdev->wq, vdev->send_buff)) 92 return -EFAULT; 93 mutex_lock(&vdev->mtx); 94 } 95 96 actual_len = min_t(size_t, count, vdev->send_buff->len); 97 98 if (copy_to_user(buf, vdev->send_buff->data, actual_len)) { 99 mutex_unlock(&vdev->mtx); 100 return -EFAULT; 101 } 102 103 skb_pull(vdev->send_buff, actual_len); 104 if (vdev->send_buff->len == 0) { 105 consume_skb(vdev->send_buff); 106 vdev->send_buff = NULL; 107 } 108 mutex_unlock(&vdev->mtx); 109 110 return actual_len; 111 } 112 113 static ssize_t virtual_ncidev_write(struct file *file, 114 const char __user *buf, 115 size_t count, loff_t *ppos) 116 { 117 struct virtual_nci_dev *vdev = file->private_data; 118 struct sk_buff *skb; 119 120 skb = alloc_skb(count, GFP_KERNEL); 121 if (!skb) 122 return -ENOMEM; 123 124 if (copy_from_user(skb_put(skb, count), buf, count)) { 125 kfree_skb(skb); 126 return -EFAULT; 127 } 128 if (strnlen(skb->data, count) != count) { 129 kfree_skb(skb); 130 return -EINVAL; 131 } 132 133 nci_recv_frame(vdev->ndev, skb); 134 return count; 135 } 136 137 static int virtual_ncidev_open(struct inode *inode, struct file *file) 138 { 139 int ret = 0; 140 struct virtual_nci_dev *vdev; 141 142 vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); 143 if (!vdev) 144 return -ENOMEM; 145 vdev->ndev = nci_allocate_device(&virtual_nci_ops, 146 VIRTUAL_NFC_PROTOCOLS, 0, 0); 147 if (!vdev->ndev) { 148 kfree(vdev); 149 return -ENOMEM; 150 } 151 152 mutex_init(&vdev->mtx); 153 init_waitqueue_head(&vdev->wq); 154 file->private_data = vdev; 155 nci_set_drvdata(vdev->ndev, vdev); 156 157 ret = nci_register_device(vdev->ndev); 158 if (ret < 0) { 159 nci_free_device(vdev->ndev); 160 mutex_destroy(&vdev->mtx); 161 kfree(vdev); 162 return ret; 163 } 164 165 return 0; 166 } 167 168 static int virtual_ncidev_close(struct inode *inode, struct file *file) 169 { 170 struct virtual_nci_dev *vdev = file->private_data; 171 172 nci_unregister_device(vdev->ndev); 173 nci_free_device(vdev->ndev); 174 mutex_destroy(&vdev->mtx); 175 kfree(vdev); 176 177 return 0; 178 } 179 180 static long virtual_ncidev_ioctl(struct file *file, unsigned int cmd, 181 unsigned long arg) 182 { 183 struct virtual_nci_dev *vdev = file->private_data; 184 const struct nfc_dev *nfc_dev = vdev->ndev->nfc_dev; 185 void __user *p = (void __user *)arg; 186 187 if (cmd != IOCTL_GET_NCIDEV_IDX) 188 return -ENOTTY; 189 190 if (copy_to_user(p, &nfc_dev->idx, sizeof(nfc_dev->idx))) 191 return -EFAULT; 192 193 return 0; 194 } 195 196 static const struct file_operations virtual_ncidev_fops = { 197 .owner = THIS_MODULE, 198 .read = virtual_ncidev_read, 199 .write = virtual_ncidev_write, 200 .open = virtual_ncidev_open, 201 .release = virtual_ncidev_close, 202 .unlocked_ioctl = virtual_ncidev_ioctl 203 }; 204 205 static struct miscdevice miscdev = { 206 .minor = MISC_DYNAMIC_MINOR, 207 .name = "virtual_nci", 208 .fops = &virtual_ncidev_fops, 209 .mode = 0600, 210 }; 211 212 module_misc_device(miscdev); 213 214 MODULE_LICENSE("GPL"); 215 MODULE_DESCRIPTION("Virtual NCI device simulation driver"); 216 MODULE_AUTHOR("Bongsu Jeon <bongsu.jeon@samsung.com>"); 217