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 129 nci_recv_frame(vdev->ndev, skb); 130 return count; 131 } 132 133 static int virtual_ncidev_open(struct inode *inode, struct file *file) 134 { 135 int ret = 0; 136 struct virtual_nci_dev *vdev; 137 138 vdev = kzalloc(sizeof(*vdev), GFP_KERNEL); 139 if (!vdev) 140 return -ENOMEM; 141 vdev->ndev = nci_allocate_device(&virtual_nci_ops, 142 VIRTUAL_NFC_PROTOCOLS, 0, 0); 143 if (!vdev->ndev) { 144 kfree(vdev); 145 return -ENOMEM; 146 } 147 148 mutex_init(&vdev->mtx); 149 init_waitqueue_head(&vdev->wq); 150 file->private_data = vdev; 151 nci_set_drvdata(vdev->ndev, vdev); 152 153 ret = nci_register_device(vdev->ndev); 154 if (ret < 0) { 155 nci_free_device(vdev->ndev); 156 mutex_destroy(&vdev->mtx); 157 kfree(vdev); 158 return ret; 159 } 160 161 return 0; 162 } 163 164 static int virtual_ncidev_close(struct inode *inode, struct file *file) 165 { 166 struct virtual_nci_dev *vdev = file->private_data; 167 168 nci_unregister_device(vdev->ndev); 169 nci_free_device(vdev->ndev); 170 mutex_destroy(&vdev->mtx); 171 kfree(vdev); 172 173 return 0; 174 } 175 176 static long virtual_ncidev_ioctl(struct file *file, unsigned int cmd, 177 unsigned long arg) 178 { 179 struct virtual_nci_dev *vdev = file->private_data; 180 const struct nfc_dev *nfc_dev = vdev->ndev->nfc_dev; 181 void __user *p = (void __user *)arg; 182 183 if (cmd != IOCTL_GET_NCIDEV_IDX) 184 return -ENOTTY; 185 186 if (copy_to_user(p, &nfc_dev->idx, sizeof(nfc_dev->idx))) 187 return -EFAULT; 188 189 return 0; 190 } 191 192 static const struct file_operations virtual_ncidev_fops = { 193 .owner = THIS_MODULE, 194 .read = virtual_ncidev_read, 195 .write = virtual_ncidev_write, 196 .open = virtual_ncidev_open, 197 .release = virtual_ncidev_close, 198 .unlocked_ioctl = virtual_ncidev_ioctl 199 }; 200 201 static struct miscdevice miscdev = { 202 .minor = MISC_DYNAMIC_MINOR, 203 .name = "virtual_nci", 204 .fops = &virtual_ncidev_fops, 205 .mode = 0600, 206 }; 207 208 module_misc_device(miscdev); 209 210 MODULE_LICENSE("GPL"); 211 MODULE_DESCRIPTION("Virtual NCI device simulation driver"); 212 MODULE_AUTHOR("Bongsu Jeon <bongsu.jeon@samsung.com>"); 213