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

vudc_sysfs.c (6124B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright (C) 2015 Karol Kosik <karo9@interia.eu>
      4 * Copyright (C) 2015-2016 Samsung Electronics
      5 *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
      6 *               Krzysztof Opasiak <k.opasiak@samsung.com>
      7 */
      8
      9#include <linux/device.h>
     10#include <linux/list.h>
     11#include <linux/usb/gadget.h>
     12#include <linux/usb/ch9.h>
     13#include <linux/sysfs.h>
     14#include <linux/kthread.h>
     15#include <linux/byteorder/generic.h>
     16
     17#include "usbip_common.h"
     18#include "vudc.h"
     19
     20#include <net/sock.h>
     21
     22/* called with udc->lock held */
     23int get_gadget_descs(struct vudc *udc)
     24{
     25	struct vrequest *usb_req;
     26	struct vep *ep0 = to_vep(udc->gadget.ep0);
     27	struct usb_device_descriptor *ddesc = &udc->dev_desc;
     28	struct usb_ctrlrequest req;
     29	int ret;
     30
     31	if (!udc->driver || !udc->pullup)
     32		return -EINVAL;
     33
     34	req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
     35	req.bRequest = USB_REQ_GET_DESCRIPTOR;
     36	req.wValue = cpu_to_le16(USB_DT_DEVICE << 8);
     37	req.wIndex = cpu_to_le16(0);
     38	req.wLength = cpu_to_le16(sizeof(*ddesc));
     39
     40	spin_unlock(&udc->lock);
     41	ret = udc->driver->setup(&(udc->gadget), &req);
     42	spin_lock(&udc->lock);
     43	if (ret < 0)
     44		goto out;
     45
     46	/* assuming request queue is empty; request is now on top */
     47	usb_req = list_last_entry(&ep0->req_queue, struct vrequest, req_entry);
     48	list_del(&usb_req->req_entry);
     49
     50	if (usb_req->req.length > sizeof(*ddesc)) {
     51		ret = -EOVERFLOW;
     52		goto giveback_req;
     53	}
     54
     55	memcpy(ddesc, usb_req->req.buf, sizeof(*ddesc));
     56	udc->desc_cached = 1;
     57	ret = 0;
     58giveback_req:
     59	usb_req->req.status = 0;
     60	usb_req->req.actual = usb_req->req.length;
     61	usb_gadget_giveback_request(&(ep0->ep), &(usb_req->req));
     62out:
     63	return ret;
     64}
     65
     66/*
     67 * Exposes device descriptor from the gadget driver.
     68 */
     69static ssize_t dev_desc_read(struct file *file, struct kobject *kobj,
     70			     struct bin_attribute *attr, char *out,
     71			     loff_t off, size_t count)
     72{
     73	struct device *dev = kobj_to_dev(kobj);
     74	struct vudc *udc = (struct vudc *)dev_get_drvdata(dev);
     75	char *desc_ptr = (char *) &udc->dev_desc;
     76	unsigned long flags;
     77	int ret;
     78
     79	spin_lock_irqsave(&udc->lock, flags);
     80	if (!udc->desc_cached) {
     81		ret = -ENODEV;
     82		goto unlock;
     83	}
     84
     85	memcpy(out, desc_ptr + off, count);
     86	ret = count;
     87unlock:
     88	spin_unlock_irqrestore(&udc->lock, flags);
     89	return ret;
     90}
     91static BIN_ATTR_RO(dev_desc, sizeof(struct usb_device_descriptor));
     92
     93static ssize_t usbip_sockfd_store(struct device *dev,
     94				  struct device_attribute *attr,
     95				  const char *in, size_t count)
     96{
     97	struct vudc *udc = (struct vudc *) dev_get_drvdata(dev);
     98	int rv;
     99	int sockfd = 0;
    100	int err;
    101	struct socket *socket;
    102	unsigned long flags;
    103	int ret;
    104	struct task_struct *tcp_rx = NULL;
    105	struct task_struct *tcp_tx = NULL;
    106
    107	rv = kstrtoint(in, 0, &sockfd);
    108	if (rv != 0)
    109		return -EINVAL;
    110
    111	if (!udc) {
    112		dev_err(dev, "no device");
    113		return -ENODEV;
    114	}
    115	mutex_lock(&udc->ud.sysfs_lock);
    116	spin_lock_irqsave(&udc->lock, flags);
    117	/* Don't export what we don't have */
    118	if (!udc->driver || !udc->pullup) {
    119		dev_err(dev, "gadget not bound");
    120		ret = -ENODEV;
    121		goto unlock;
    122	}
    123
    124	if (sockfd != -1) {
    125		if (udc->connected) {
    126			dev_err(dev, "Device already connected");
    127			ret = -EBUSY;
    128			goto unlock;
    129		}
    130
    131		spin_lock_irq(&udc->ud.lock);
    132
    133		if (udc->ud.status != SDEV_ST_AVAILABLE) {
    134			ret = -EINVAL;
    135			goto unlock_ud;
    136		}
    137
    138		socket = sockfd_lookup(sockfd, &err);
    139		if (!socket) {
    140			dev_err(dev, "failed to lookup sock");
    141			ret = -EINVAL;
    142			goto unlock_ud;
    143		}
    144
    145		if (socket->type != SOCK_STREAM) {
    146			dev_err(dev, "Expecting SOCK_STREAM - found %d",
    147				socket->type);
    148			ret = -EINVAL;
    149			goto sock_err;
    150		}
    151
    152		/* unlock and create threads and get tasks */
    153		spin_unlock_irq(&udc->ud.lock);
    154		spin_unlock_irqrestore(&udc->lock, flags);
    155
    156		tcp_rx = kthread_create(&v_rx_loop, &udc->ud, "vudc_rx");
    157		if (IS_ERR(tcp_rx)) {
    158			sockfd_put(socket);
    159			mutex_unlock(&udc->ud.sysfs_lock);
    160			return -EINVAL;
    161		}
    162		tcp_tx = kthread_create(&v_tx_loop, &udc->ud, "vudc_tx");
    163		if (IS_ERR(tcp_tx)) {
    164			kthread_stop(tcp_rx);
    165			sockfd_put(socket);
    166			mutex_unlock(&udc->ud.sysfs_lock);
    167			return -EINVAL;
    168		}
    169
    170		/* get task structs now */
    171		get_task_struct(tcp_rx);
    172		get_task_struct(tcp_tx);
    173
    174		/* lock and update udc->ud state */
    175		spin_lock_irqsave(&udc->lock, flags);
    176		spin_lock_irq(&udc->ud.lock);
    177
    178		udc->ud.tcp_socket = socket;
    179		udc->ud.tcp_rx = tcp_rx;
    180		udc->ud.tcp_tx = tcp_tx;
    181		udc->ud.status = SDEV_ST_USED;
    182
    183		spin_unlock_irq(&udc->ud.lock);
    184
    185		ktime_get_ts64(&udc->start_time);
    186		v_start_timer(udc);
    187		udc->connected = 1;
    188
    189		spin_unlock_irqrestore(&udc->lock, flags);
    190
    191		wake_up_process(udc->ud.tcp_rx);
    192		wake_up_process(udc->ud.tcp_tx);
    193
    194		mutex_unlock(&udc->ud.sysfs_lock);
    195		return count;
    196
    197	} else {
    198		if (!udc->connected) {
    199			dev_err(dev, "Device not connected");
    200			ret = -EINVAL;
    201			goto unlock;
    202		}
    203
    204		spin_lock_irq(&udc->ud.lock);
    205		if (udc->ud.status != SDEV_ST_USED) {
    206			ret = -EINVAL;
    207			goto unlock_ud;
    208		}
    209		spin_unlock_irq(&udc->ud.lock);
    210
    211		usbip_event_add(&udc->ud, VUDC_EVENT_DOWN);
    212	}
    213
    214	spin_unlock_irqrestore(&udc->lock, flags);
    215	mutex_unlock(&udc->ud.sysfs_lock);
    216
    217	return count;
    218
    219sock_err:
    220	sockfd_put(socket);
    221unlock_ud:
    222	spin_unlock_irq(&udc->ud.lock);
    223unlock:
    224	spin_unlock_irqrestore(&udc->lock, flags);
    225	mutex_unlock(&udc->ud.sysfs_lock);
    226
    227	return ret;
    228}
    229static DEVICE_ATTR_WO(usbip_sockfd);
    230
    231static ssize_t usbip_status_show(struct device *dev,
    232			       struct device_attribute *attr, char *out)
    233{
    234	struct vudc *udc = (struct vudc *) dev_get_drvdata(dev);
    235	int status;
    236
    237	if (!udc) {
    238		dev_err(dev, "no device");
    239		return -ENODEV;
    240	}
    241	spin_lock_irq(&udc->ud.lock);
    242	status = udc->ud.status;
    243	spin_unlock_irq(&udc->ud.lock);
    244
    245	return snprintf(out, PAGE_SIZE, "%d\n", status);
    246}
    247static DEVICE_ATTR_RO(usbip_status);
    248
    249static struct attribute *dev_attrs[] = {
    250	&dev_attr_usbip_sockfd.attr,
    251	&dev_attr_usbip_status.attr,
    252	NULL,
    253};
    254
    255static struct bin_attribute *dev_bin_attrs[] = {
    256	&bin_attr_dev_desc,
    257	NULL,
    258};
    259
    260static const struct attribute_group vudc_attr_group = {
    261	.attrs = dev_attrs,
    262	.bin_attrs = dev_bin_attrs,
    263};
    264
    265const struct attribute_group *vudc_groups[] = {
    266	&vudc_attr_group,
    267	NULL,
    268};