18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Karol Kosik <karo9@interia.eu> 48c2ecf20Sopenharmony_ci * Copyright (C) 2015-2016 Samsung Electronics 58c2ecf20Sopenharmony_ci * Igor Kotrasinski <i.kotrasinsk@samsung.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <net/sock.h> 98c2ecf20Sopenharmony_ci#include <linux/list.h> 108c2ecf20Sopenharmony_ci#include <linux/kthread.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "usbip_common.h" 138c2ecf20Sopenharmony_ci#include "vudc.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic int alloc_urb_from_cmd(struct urb **urbp, 168c2ecf20Sopenharmony_ci struct usbip_header *pdu, u8 type) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci struct urb *urb; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci if (type == USB_ENDPOINT_XFER_ISOC) 218c2ecf20Sopenharmony_ci urb = usb_alloc_urb(pdu->u.cmd_submit.number_of_packets, 228c2ecf20Sopenharmony_ci GFP_KERNEL); 238c2ecf20Sopenharmony_ci else 248c2ecf20Sopenharmony_ci urb = usb_alloc_urb(0, GFP_KERNEL); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci if (!urb) 278c2ecf20Sopenharmony_ci goto err; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci usbip_pack_pdu(pdu, urb, USBIP_CMD_SUBMIT, 0); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (urb->transfer_buffer_length > 0) { 328c2ecf20Sopenharmony_ci urb->transfer_buffer = kzalloc(urb->transfer_buffer_length, 338c2ecf20Sopenharmony_ci GFP_KERNEL); 348c2ecf20Sopenharmony_ci if (!urb->transfer_buffer) 358c2ecf20Sopenharmony_ci goto free_urb; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci urb->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, 8, 398c2ecf20Sopenharmony_ci GFP_KERNEL); 408c2ecf20Sopenharmony_ci if (!urb->setup_packet) 418c2ecf20Sopenharmony_ci goto free_buffer; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* 448c2ecf20Sopenharmony_ci * FIXME - we only setup pipe enough for usbip functions 458c2ecf20Sopenharmony_ci * to behave nicely 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci urb->pipe |= pdu->base.direction == USBIP_DIR_IN ? 488c2ecf20Sopenharmony_ci USB_DIR_IN : USB_DIR_OUT; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci *urbp = urb; 518c2ecf20Sopenharmony_ci return 0; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cifree_buffer: 548c2ecf20Sopenharmony_ci kfree(urb->transfer_buffer); 558c2ecf20Sopenharmony_ci urb->transfer_buffer = NULL; 568c2ecf20Sopenharmony_cifree_urb: 578c2ecf20Sopenharmony_ci usb_free_urb(urb); 588c2ecf20Sopenharmony_cierr: 598c2ecf20Sopenharmony_ci return -ENOMEM; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int v_recv_cmd_unlink(struct vudc *udc, 638c2ecf20Sopenharmony_ci struct usbip_header *pdu) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci unsigned long flags; 668c2ecf20Sopenharmony_ci struct urbp *urb_p; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 698c2ecf20Sopenharmony_ci list_for_each_entry(urb_p, &udc->urb_queue, urb_entry) { 708c2ecf20Sopenharmony_ci if (urb_p->seqnum != pdu->u.cmd_unlink.seqnum) 718c2ecf20Sopenharmony_ci continue; 728c2ecf20Sopenharmony_ci urb_p->urb->unlinked = -ECONNRESET; 738c2ecf20Sopenharmony_ci urb_p->seqnum = pdu->base.seqnum; 748c2ecf20Sopenharmony_ci v_kick_timer(udc, jiffies); 758c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 768c2ecf20Sopenharmony_ci return 0; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci /* Not found, completed / not queued */ 798c2ecf20Sopenharmony_ci spin_lock(&udc->lock_tx); 808c2ecf20Sopenharmony_ci v_enqueue_ret_unlink(udc, pdu->base.seqnum, 0); 818c2ecf20Sopenharmony_ci wake_up(&udc->tx_waitq); 828c2ecf20Sopenharmony_ci spin_unlock(&udc->lock_tx); 838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int v_recv_cmd_submit(struct vudc *udc, 898c2ecf20Sopenharmony_ci struct usbip_header *pdu) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci int ret = 0; 928c2ecf20Sopenharmony_ci struct urbp *urb_p; 938c2ecf20Sopenharmony_ci u8 address; 948c2ecf20Sopenharmony_ci unsigned long flags; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci urb_p = alloc_urbp(); 978c2ecf20Sopenharmony_ci if (!urb_p) { 988c2ecf20Sopenharmony_ci usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_MALLOC); 998c2ecf20Sopenharmony_ci return -ENOMEM; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* base.ep is pipeendpoint(pipe) */ 1038c2ecf20Sopenharmony_ci address = pdu->base.ep; 1048c2ecf20Sopenharmony_ci if (pdu->base.direction == USBIP_DIR_IN) 1058c2ecf20Sopenharmony_ci address |= USB_DIR_IN; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci spin_lock_irq(&udc->lock); 1088c2ecf20Sopenharmony_ci urb_p->ep = vudc_find_endpoint(udc, address); 1098c2ecf20Sopenharmony_ci if (!urb_p->ep) { 1108c2ecf20Sopenharmony_ci /* we don't know the type, there may be isoc data! */ 1118c2ecf20Sopenharmony_ci dev_err(&udc->pdev->dev, "request to nonexistent endpoint"); 1128c2ecf20Sopenharmony_ci spin_unlock_irq(&udc->lock); 1138c2ecf20Sopenharmony_ci usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP); 1148c2ecf20Sopenharmony_ci ret = -EPIPE; 1158c2ecf20Sopenharmony_ci goto free_urbp; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci urb_p->type = urb_p->ep->type; 1188c2ecf20Sopenharmony_ci spin_unlock_irq(&udc->lock); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci urb_p->new = 1; 1218c2ecf20Sopenharmony_ci urb_p->seqnum = pdu->base.seqnum; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (urb_p->ep->type == USB_ENDPOINT_XFER_ISOC) { 1248c2ecf20Sopenharmony_ci /* validate packet size and number of packets */ 1258c2ecf20Sopenharmony_ci unsigned int maxp, packets, bytes; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci maxp = usb_endpoint_maxp(urb_p->ep->desc); 1288c2ecf20Sopenharmony_ci maxp *= usb_endpoint_maxp_mult(urb_p->ep->desc); 1298c2ecf20Sopenharmony_ci bytes = pdu->u.cmd_submit.transfer_buffer_length; 1308c2ecf20Sopenharmony_ci packets = DIV_ROUND_UP(bytes, maxp); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (pdu->u.cmd_submit.number_of_packets < 0 || 1338c2ecf20Sopenharmony_ci pdu->u.cmd_submit.number_of_packets > packets) { 1348c2ecf20Sopenharmony_ci dev_err(&udc->gadget.dev, 1358c2ecf20Sopenharmony_ci "CMD_SUBMIT: isoc invalid num packets %d\n", 1368c2ecf20Sopenharmony_ci pdu->u.cmd_submit.number_of_packets); 1378c2ecf20Sopenharmony_ci ret = -EMSGSIZE; 1388c2ecf20Sopenharmony_ci goto free_urbp; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci ret = alloc_urb_from_cmd(&urb_p->urb, pdu, urb_p->ep->type); 1438c2ecf20Sopenharmony_ci if (ret) { 1448c2ecf20Sopenharmony_ci usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_MALLOC); 1458c2ecf20Sopenharmony_ci ret = -ENOMEM; 1468c2ecf20Sopenharmony_ci goto free_urbp; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci urb_p->urb->status = -EINPROGRESS; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* FIXME: more pipe setup to please usbip_common */ 1528c2ecf20Sopenharmony_ci urb_p->urb->pipe &= ~(3 << 30); 1538c2ecf20Sopenharmony_ci switch (urb_p->ep->type) { 1548c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 1558c2ecf20Sopenharmony_ci urb_p->urb->pipe |= (PIPE_BULK << 30); 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 1588c2ecf20Sopenharmony_ci urb_p->urb->pipe |= (PIPE_INTERRUPT << 30); 1598c2ecf20Sopenharmony_ci break; 1608c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_CONTROL: 1618c2ecf20Sopenharmony_ci urb_p->urb->pipe |= (PIPE_CONTROL << 30); 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 1648c2ecf20Sopenharmony_ci urb_p->urb->pipe |= (PIPE_ISOCHRONOUS << 30); 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci ret = usbip_recv_xbuff(&udc->ud, urb_p->urb); 1688c2ecf20Sopenharmony_ci if (ret < 0) 1698c2ecf20Sopenharmony_ci goto free_urbp; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci ret = usbip_recv_iso(&udc->ud, urb_p->urb); 1728c2ecf20Sopenharmony_ci if (ret < 0) 1738c2ecf20Sopenharmony_ci goto free_urbp; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci spin_lock_irqsave(&udc->lock, flags); 1768c2ecf20Sopenharmony_ci v_kick_timer(udc, jiffies); 1778c2ecf20Sopenharmony_ci list_add_tail(&urb_p->urb_entry, &udc->urb_queue); 1788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&udc->lock, flags); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_cifree_urbp: 1838c2ecf20Sopenharmony_ci free_urbp_and_urb(urb_p); 1848c2ecf20Sopenharmony_ci return ret; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic int v_rx_pdu(struct usbip_device *ud) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci int ret; 1908c2ecf20Sopenharmony_ci struct usbip_header pdu; 1918c2ecf20Sopenharmony_ci struct vudc *udc = container_of(ud, struct vudc, ud); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci memset(&pdu, 0, sizeof(pdu)); 1948c2ecf20Sopenharmony_ci ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu)); 1958c2ecf20Sopenharmony_ci if (ret != sizeof(pdu)) { 1968c2ecf20Sopenharmony_ci usbip_event_add(ud, VUDC_EVENT_ERROR_TCP); 1978c2ecf20Sopenharmony_ci if (ret >= 0) 1988c2ecf20Sopenharmony_ci return -EPIPE; 1998c2ecf20Sopenharmony_ci return ret; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci usbip_header_correct_endian(&pdu, 0); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci spin_lock_irq(&ud->lock); 2048c2ecf20Sopenharmony_ci ret = (ud->status == SDEV_ST_USED); 2058c2ecf20Sopenharmony_ci spin_unlock_irq(&ud->lock); 2068c2ecf20Sopenharmony_ci if (!ret) { 2078c2ecf20Sopenharmony_ci usbip_event_add(ud, VUDC_EVENT_ERROR_TCP); 2088c2ecf20Sopenharmony_ci return -EBUSY; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci switch (pdu.base.command) { 2128c2ecf20Sopenharmony_ci case USBIP_CMD_UNLINK: 2138c2ecf20Sopenharmony_ci ret = v_recv_cmd_unlink(udc, &pdu); 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci case USBIP_CMD_SUBMIT: 2168c2ecf20Sopenharmony_ci ret = v_recv_cmd_submit(udc, &pdu); 2178c2ecf20Sopenharmony_ci break; 2188c2ecf20Sopenharmony_ci default: 2198c2ecf20Sopenharmony_ci ret = -EPIPE; 2208c2ecf20Sopenharmony_ci pr_err("rx: unknown command"); 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci return ret; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ciint v_rx_loop(void *data) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct usbip_device *ud = data; 2298c2ecf20Sopenharmony_ci int ret = 0; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci while (!kthread_should_stop()) { 2328c2ecf20Sopenharmony_ci if (usbip_event_happened(ud)) 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci ret = v_rx_pdu(ud); 2358c2ecf20Sopenharmony_ci if (ret < 0) { 2368c2ecf20Sopenharmony_ci pr_warn("v_rx exit with error %d", ret); 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci return ret; 2418c2ecf20Sopenharmony_ci} 242