linux/drivers/usb/usbip/vudc_rx.c
<<
>>
Prefs
   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 */
   7
   8#include <net/sock.h>
   9#include <linux/list.h>
  10#include <linux/kthread.h>
  11
  12#include "usbip_common.h"
  13#include "vudc.h"
  14
  15static int alloc_urb_from_cmd(struct urb **urbp,
  16                              struct usbip_header *pdu, u8 type)
  17{
  18        struct urb *urb;
  19
  20        if (type == USB_ENDPOINT_XFER_ISOC)
  21                urb = usb_alloc_urb(pdu->u.cmd_submit.number_of_packets,
  22                                          GFP_KERNEL);
  23        else
  24                urb = usb_alloc_urb(0, GFP_KERNEL);
  25
  26        if (!urb)
  27                goto err;
  28
  29        usbip_pack_pdu(pdu, urb, USBIP_CMD_SUBMIT, 0);
  30
  31        if (urb->transfer_buffer_length > 0) {
  32                urb->transfer_buffer = kzalloc(urb->transfer_buffer_length,
  33                        GFP_KERNEL);
  34                if (!urb->transfer_buffer)
  35                        goto free_urb;
  36        }
  37
  38        urb->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, 8,
  39                            GFP_KERNEL);
  40        if (!urb->setup_packet)
  41                goto free_buffer;
  42
  43        /*
  44         * FIXME - we only setup pipe enough for usbip functions
  45         * to behave nicely
  46         */
  47        urb->pipe |= pdu->base.direction == USBIP_DIR_IN ?
  48                        USB_DIR_IN : USB_DIR_OUT;
  49
  50        *urbp = urb;
  51        return 0;
  52
  53free_buffer:
  54        kfree(urb->transfer_buffer);
  55        urb->transfer_buffer = NULL;
  56free_urb:
  57        usb_free_urb(urb);
  58err:
  59        return -ENOMEM;
  60}
  61
  62static int v_recv_cmd_unlink(struct vudc *udc,
  63                                struct usbip_header *pdu)
  64{
  65        unsigned long flags;
  66        struct urbp *urb_p;
  67
  68        spin_lock_irqsave(&udc->lock, flags);
  69        list_for_each_entry(urb_p, &udc->urb_queue, urb_entry) {
  70                if (urb_p->seqnum != pdu->u.cmd_unlink.seqnum)
  71                        continue;
  72                urb_p->urb->unlinked = -ECONNRESET;
  73                urb_p->seqnum = pdu->base.seqnum;
  74                v_kick_timer(udc, jiffies);
  75                spin_unlock_irqrestore(&udc->lock, flags);
  76                return 0;
  77        }
  78        /* Not found, completed / not queued */
  79        spin_lock(&udc->lock_tx);
  80        v_enqueue_ret_unlink(udc, pdu->base.seqnum, 0);
  81        wake_up(&udc->tx_waitq);
  82        spin_unlock(&udc->lock_tx);
  83        spin_unlock_irqrestore(&udc->lock, flags);
  84
  85        return 0;
  86}
  87
  88static int v_recv_cmd_submit(struct vudc *udc,
  89                                 struct usbip_header *pdu)
  90{
  91        int ret = 0;
  92        struct urbp *urb_p;
  93        u8 address;
  94        unsigned long flags;
  95
  96        urb_p = alloc_urbp();
  97        if (!urb_p) {
  98                usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_MALLOC);
  99                return -ENOMEM;
 100        }
 101
 102        /* base.ep is pipeendpoint(pipe) */
 103        address = pdu->base.ep;
 104        if (pdu->base.direction == USBIP_DIR_IN)
 105                address |= USB_DIR_IN;
 106
 107        spin_lock_irq(&udc->lock);
 108        urb_p->ep = vudc_find_endpoint(udc, address);
 109        if (!urb_p->ep) {
 110                /* we don't know the type, there may be isoc data! */
 111                dev_err(&udc->pdev->dev, "request to nonexistent endpoint");
 112                spin_unlock_irq(&udc->lock);
 113                usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP);
 114                ret = -EPIPE;
 115                goto free_urbp;
 116        }
 117        urb_p->type = urb_p->ep->type;
 118        spin_unlock_irq(&udc->lock);
 119
 120        urb_p->new = 1;
 121        urb_p->seqnum = pdu->base.seqnum;
 122
 123        if (urb_p->ep->type == USB_ENDPOINT_XFER_ISOC) {
 124                /* validate packet size and number of packets */
 125                unsigned int maxp, packets, bytes;
 126
 127                maxp = usb_endpoint_maxp(urb_p->ep->desc);
 128                maxp *= usb_endpoint_maxp_mult(urb_p->ep->desc);
 129                bytes = pdu->u.cmd_submit.transfer_buffer_length;
 130                packets = DIV_ROUND_UP(bytes, maxp);
 131
 132                if (pdu->u.cmd_submit.number_of_packets < 0 ||
 133                    pdu->u.cmd_submit.number_of_packets > packets) {
 134                        dev_err(&udc->gadget.dev,
 135                                "CMD_SUBMIT: isoc invalid num packets %d\n",
 136                                pdu->u.cmd_submit.number_of_packets);
 137                        ret = -EMSGSIZE;
 138                        goto free_urbp;
 139                }
 140        }
 141
 142        ret = alloc_urb_from_cmd(&urb_p->urb, pdu, urb_p->ep->type);
 143        if (ret) {
 144                usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_MALLOC);
 145                ret = -ENOMEM;
 146                goto free_urbp;
 147        }
 148
 149        urb_p->urb->status = -EINPROGRESS;
 150
 151        /* FIXME: more pipe setup to please usbip_common */
 152        urb_p->urb->pipe &= ~(3 << 30);
 153        switch (urb_p->ep->type) {
 154        case USB_ENDPOINT_XFER_BULK:
 155                urb_p->urb->pipe |= (PIPE_BULK << 30);
 156                break;
 157        case USB_ENDPOINT_XFER_INT:
 158                urb_p->urb->pipe |= (PIPE_INTERRUPT << 30);
 159                break;
 160        case USB_ENDPOINT_XFER_CONTROL:
 161                urb_p->urb->pipe |= (PIPE_CONTROL << 30);
 162                break;
 163        case USB_ENDPOINT_XFER_ISOC:
 164                urb_p->urb->pipe |= (PIPE_ISOCHRONOUS << 30);
 165                break;
 166        }
 167        ret = usbip_recv_xbuff(&udc->ud, urb_p->urb);
 168        if (ret < 0)
 169                goto free_urbp;
 170
 171        ret = usbip_recv_iso(&udc->ud, urb_p->urb);
 172        if (ret < 0)
 173                goto free_urbp;
 174
 175        spin_lock_irqsave(&udc->lock, flags);
 176        v_kick_timer(udc, jiffies);
 177        list_add_tail(&urb_p->urb_entry, &udc->urb_queue);
 178        spin_unlock_irqrestore(&udc->lock, flags);
 179
 180        return 0;
 181
 182free_urbp:
 183        free_urbp_and_urb(urb_p);
 184        return ret;
 185}
 186
 187static int v_rx_pdu(struct usbip_device *ud)
 188{
 189        int ret;
 190        struct usbip_header pdu;
 191        struct vudc *udc = container_of(ud, struct vudc, ud);
 192
 193        memset(&pdu, 0, sizeof(pdu));
 194        ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu));
 195        if (ret != sizeof(pdu)) {
 196                usbip_event_add(ud, VUDC_EVENT_ERROR_TCP);
 197                if (ret >= 0)
 198                        return -EPIPE;
 199                return ret;
 200        }
 201        usbip_header_correct_endian(&pdu, 0);
 202
 203        spin_lock_irq(&ud->lock);
 204        ret = (ud->status == SDEV_ST_USED);
 205        spin_unlock_irq(&ud->lock);
 206        if (!ret) {
 207                usbip_event_add(ud, VUDC_EVENT_ERROR_TCP);
 208                return -EBUSY;
 209        }
 210
 211        switch (pdu.base.command) {
 212        case USBIP_CMD_UNLINK:
 213                ret = v_recv_cmd_unlink(udc, &pdu);
 214                break;
 215        case USBIP_CMD_SUBMIT:
 216                ret = v_recv_cmd_submit(udc, &pdu);
 217                break;
 218        default:
 219                ret = -EPIPE;
 220                pr_err("rx: unknown command");
 221                break;
 222        }
 223        return ret;
 224}
 225
 226int v_rx_loop(void *data)
 227{
 228        struct usbip_device *ud = data;
 229        int ret = 0;
 230
 231        while (!kthread_should_stop()) {
 232                if (usbip_event_happened(ud))
 233                        break;
 234                ret = v_rx_pdu(ud);
 235                if (ret < 0) {
 236                        pr_warn("v_rx exit with error %d", ret);
 237                        break;
 238                }
 239        }
 240        return ret;
 241}
 242