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

tun.c (3468B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright (c) 2018, Linaro Ltd */
      3
      4#include <linux/miscdevice.h>
      5#include <linux/module.h>
      6#include <linux/poll.h>
      7#include <linux/skbuff.h>
      8#include <linux/uaccess.h>
      9
     10#include "qrtr.h"
     11
     12struct qrtr_tun {
     13	struct qrtr_endpoint ep;
     14
     15	struct sk_buff_head queue;
     16	wait_queue_head_t readq;
     17};
     18
     19static int qrtr_tun_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
     20{
     21	struct qrtr_tun *tun = container_of(ep, struct qrtr_tun, ep);
     22
     23	skb_queue_tail(&tun->queue, skb);
     24
     25	/* wake up any blocking processes, waiting for new data */
     26	wake_up_interruptible(&tun->readq);
     27
     28	return 0;
     29}
     30
     31static int qrtr_tun_open(struct inode *inode, struct file *filp)
     32{
     33	struct qrtr_tun *tun;
     34	int ret;
     35
     36	tun = kzalloc(sizeof(*tun), GFP_KERNEL);
     37	if (!tun)
     38		return -ENOMEM;
     39
     40	skb_queue_head_init(&tun->queue);
     41	init_waitqueue_head(&tun->readq);
     42
     43	tun->ep.xmit = qrtr_tun_send;
     44
     45	filp->private_data = tun;
     46
     47	ret = qrtr_endpoint_register(&tun->ep, QRTR_EP_NID_AUTO);
     48	if (ret)
     49		goto out;
     50
     51	return 0;
     52
     53out:
     54	filp->private_data = NULL;
     55	kfree(tun);
     56	return ret;
     57}
     58
     59static ssize_t qrtr_tun_read_iter(struct kiocb *iocb, struct iov_iter *to)
     60{
     61	struct file *filp = iocb->ki_filp;
     62	struct qrtr_tun *tun = filp->private_data;
     63	struct sk_buff *skb;
     64	int count;
     65
     66	while (!(skb = skb_dequeue(&tun->queue))) {
     67		if (filp->f_flags & O_NONBLOCK)
     68			return -EAGAIN;
     69
     70		/* Wait until we get data or the endpoint goes away */
     71		if (wait_event_interruptible(tun->readq,
     72					     !skb_queue_empty(&tun->queue)))
     73			return -ERESTARTSYS;
     74	}
     75
     76	count = min_t(size_t, iov_iter_count(to), skb->len);
     77	if (copy_to_iter(skb->data, count, to) != count)
     78		count = -EFAULT;
     79
     80	kfree_skb(skb);
     81
     82	return count;
     83}
     84
     85static ssize_t qrtr_tun_write_iter(struct kiocb *iocb, struct iov_iter *from)
     86{
     87	struct file *filp = iocb->ki_filp;
     88	struct qrtr_tun *tun = filp->private_data;
     89	size_t len = iov_iter_count(from);
     90	ssize_t ret;
     91	void *kbuf;
     92
     93	if (!len)
     94		return -EINVAL;
     95
     96	if (len > KMALLOC_MAX_SIZE)
     97		return -ENOMEM;
     98
     99	kbuf = kzalloc(len, GFP_KERNEL);
    100	if (!kbuf)
    101		return -ENOMEM;
    102
    103	if (!copy_from_iter_full(kbuf, len, from)) {
    104		kfree(kbuf);
    105		return -EFAULT;
    106	}
    107
    108	ret = qrtr_endpoint_post(&tun->ep, kbuf, len);
    109
    110	kfree(kbuf);
    111	return ret < 0 ? ret : len;
    112}
    113
    114static __poll_t qrtr_tun_poll(struct file *filp, poll_table *wait)
    115{
    116	struct qrtr_tun *tun = filp->private_data;
    117	__poll_t mask = 0;
    118
    119	poll_wait(filp, &tun->readq, wait);
    120
    121	if (!skb_queue_empty(&tun->queue))
    122		mask |= EPOLLIN | EPOLLRDNORM;
    123
    124	return mask;
    125}
    126
    127static int qrtr_tun_release(struct inode *inode, struct file *filp)
    128{
    129	struct qrtr_tun *tun = filp->private_data;
    130
    131	qrtr_endpoint_unregister(&tun->ep);
    132
    133	/* Discard all SKBs */
    134	skb_queue_purge(&tun->queue);
    135
    136	kfree(tun);
    137
    138	return 0;
    139}
    140
    141static const struct file_operations qrtr_tun_ops = {
    142	.owner = THIS_MODULE,
    143	.open = qrtr_tun_open,
    144	.poll = qrtr_tun_poll,
    145	.read_iter = qrtr_tun_read_iter,
    146	.write_iter = qrtr_tun_write_iter,
    147	.release = qrtr_tun_release,
    148};
    149
    150static struct miscdevice qrtr_tun_miscdev = {
    151	MISC_DYNAMIC_MINOR,
    152	"qrtr-tun",
    153	&qrtr_tun_ops,
    154};
    155
    156static int __init qrtr_tun_init(void)
    157{
    158	int ret;
    159
    160	ret = misc_register(&qrtr_tun_miscdev);
    161	if (ret)
    162		pr_err("failed to register Qualcomm IPC Router tun device\n");
    163
    164	return ret;
    165}
    166
    167static void __exit qrtr_tun_exit(void)
    168{
    169	misc_deregister(&qrtr_tun_miscdev);
    170}
    171
    172module_init(qrtr_tun_init);
    173module_exit(qrtr_tun_exit);
    174
    175MODULE_DESCRIPTION("Qualcomm IPC Router TUN device");
    176MODULE_LICENSE("GPL v2");