18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2003-2008 Takahiro Hirofuchi 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/kthread.h> 78c2ecf20Sopenharmony_ci#include <linux/slab.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "usbip_common.h" 108c2ecf20Sopenharmony_ci#include "vhci.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci/* get URB from transmitted urb queue. caller must hold vdev->priv_lock */ 138c2ecf20Sopenharmony_cistruct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci struct vhci_priv *priv, *tmp; 168c2ecf20Sopenharmony_ci struct urb *urb = NULL; 178c2ecf20Sopenharmony_ci int status; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) { 208c2ecf20Sopenharmony_ci if (priv->seqnum != seqnum) 218c2ecf20Sopenharmony_ci continue; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci urb = priv->urb; 248c2ecf20Sopenharmony_ci status = urb->status; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci usbip_dbg_vhci_rx("find urb seqnum %u\n", seqnum); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci switch (status) { 298c2ecf20Sopenharmony_ci case -ENOENT: 308c2ecf20Sopenharmony_ci fallthrough; 318c2ecf20Sopenharmony_ci case -ECONNRESET: 328c2ecf20Sopenharmony_ci dev_dbg(&urb->dev->dev, 338c2ecf20Sopenharmony_ci "urb seq# %u was unlinked %ssynchronously\n", 348c2ecf20Sopenharmony_ci seqnum, status == -ENOENT ? "" : "a"); 358c2ecf20Sopenharmony_ci break; 368c2ecf20Sopenharmony_ci case -EINPROGRESS: 378c2ecf20Sopenharmony_ci /* no info output */ 388c2ecf20Sopenharmony_ci break; 398c2ecf20Sopenharmony_ci default: 408c2ecf20Sopenharmony_ci dev_dbg(&urb->dev->dev, 418c2ecf20Sopenharmony_ci "urb seq# %u may be in a error, status %d\n", 428c2ecf20Sopenharmony_ci seqnum, status); 438c2ecf20Sopenharmony_ci } 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci list_del(&priv->list); 468c2ecf20Sopenharmony_ci kfree(priv); 478c2ecf20Sopenharmony_ci urb->hcpriv = NULL; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci break; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return urb; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic void vhci_recv_ret_submit(struct vhci_device *vdev, 568c2ecf20Sopenharmony_ci struct usbip_header *pdu) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct vhci_hcd *vhci_hcd = vdev_to_vhci_hcd(vdev); 598c2ecf20Sopenharmony_ci struct vhci *vhci = vhci_hcd->vhci; 608c2ecf20Sopenharmony_ci struct usbip_device *ud = &vdev->ud; 618c2ecf20Sopenharmony_ci struct urb *urb; 628c2ecf20Sopenharmony_ci unsigned long flags; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci spin_lock_irqsave(&vdev->priv_lock, flags); 658c2ecf20Sopenharmony_ci urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum); 668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vdev->priv_lock, flags); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (!urb) { 698c2ecf20Sopenharmony_ci pr_err("cannot find a urb of seqnum %u max seqnum %d\n", 708c2ecf20Sopenharmony_ci pdu->base.seqnum, 718c2ecf20Sopenharmony_ci atomic_read(&vhci_hcd->seqnum)); 728c2ecf20Sopenharmony_ci usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); 738c2ecf20Sopenharmony_ci return; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* unpack the pdu to a urb */ 778c2ecf20Sopenharmony_ci usbip_pack_pdu(pdu, urb, USBIP_RET_SUBMIT, 0); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* recv transfer buffer */ 808c2ecf20Sopenharmony_ci if (usbip_recv_xbuff(ud, urb) < 0) { 818c2ecf20Sopenharmony_ci urb->status = -EPROTO; 828c2ecf20Sopenharmony_ci goto error; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* recv iso_packet_descriptor */ 868c2ecf20Sopenharmony_ci if (usbip_recv_iso(ud, urb) < 0) { 878c2ecf20Sopenharmony_ci urb->status = -EPROTO; 888c2ecf20Sopenharmony_ci goto error; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* restore the padding in iso packets */ 928c2ecf20Sopenharmony_ci usbip_pad_iso(ud, urb); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cierror: 958c2ecf20Sopenharmony_ci if (usbip_dbg_flag_vhci_rx) 968c2ecf20Sopenharmony_ci usbip_dump_urb(urb); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (urb->num_sgs) 998c2ecf20Sopenharmony_ci urb->transfer_flags &= ~URB_DMA_MAP_SG; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci usbip_dbg_vhci_rx("now giveback urb %u\n", pdu->base.seqnum); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci spin_lock_irqsave(&vhci->lock, flags); 1048c2ecf20Sopenharmony_ci usb_hcd_unlink_urb_from_ep(vhci_hcd_to_hcd(vhci_hcd), urb); 1058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vhci->lock, flags); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci usb_hcd_giveback_urb(vhci_hcd_to_hcd(vhci_hcd), urb, urb->status); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci usbip_dbg_vhci_rx("Leave\n"); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic struct vhci_unlink *dequeue_pending_unlink(struct vhci_device *vdev, 1138c2ecf20Sopenharmony_ci struct usbip_header *pdu) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct vhci_unlink *unlink, *tmp; 1168c2ecf20Sopenharmony_ci unsigned long flags; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci spin_lock_irqsave(&vdev->priv_lock, flags); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) { 1218c2ecf20Sopenharmony_ci pr_info("unlink->seqnum %lu\n", unlink->seqnum); 1228c2ecf20Sopenharmony_ci if (unlink->seqnum == pdu->base.seqnum) { 1238c2ecf20Sopenharmony_ci usbip_dbg_vhci_rx("found pending unlink, %lu\n", 1248c2ecf20Sopenharmony_ci unlink->seqnum); 1258c2ecf20Sopenharmony_ci list_del(&unlink->list); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vdev->priv_lock, flags); 1288c2ecf20Sopenharmony_ci return unlink; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vdev->priv_lock, flags); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return NULL; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void vhci_recv_ret_unlink(struct vhci_device *vdev, 1388c2ecf20Sopenharmony_ci struct usbip_header *pdu) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct vhci_hcd *vhci_hcd = vdev_to_vhci_hcd(vdev); 1418c2ecf20Sopenharmony_ci struct vhci *vhci = vhci_hcd->vhci; 1428c2ecf20Sopenharmony_ci struct vhci_unlink *unlink; 1438c2ecf20Sopenharmony_ci struct urb *urb; 1448c2ecf20Sopenharmony_ci unsigned long flags; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci usbip_dump_header(pdu); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci unlink = dequeue_pending_unlink(vdev, pdu); 1498c2ecf20Sopenharmony_ci if (!unlink) { 1508c2ecf20Sopenharmony_ci pr_info("cannot find the pending unlink %u\n", 1518c2ecf20Sopenharmony_ci pdu->base.seqnum); 1528c2ecf20Sopenharmony_ci return; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci spin_lock_irqsave(&vdev->priv_lock, flags); 1568c2ecf20Sopenharmony_ci urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum); 1578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vdev->priv_lock, flags); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (!urb) { 1608c2ecf20Sopenharmony_ci /* 1618c2ecf20Sopenharmony_ci * I get the result of a unlink request. But, it seems that I 1628c2ecf20Sopenharmony_ci * already received the result of its submit result and gave 1638c2ecf20Sopenharmony_ci * back the URB. 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci pr_info("the urb (seqnum %d) was already given back\n", 1668c2ecf20Sopenharmony_ci pdu->base.seqnum); 1678c2ecf20Sopenharmony_ci } else { 1688c2ecf20Sopenharmony_ci usbip_dbg_vhci_rx("now giveback urb %d\n", pdu->base.seqnum); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* If unlink is successful, status is -ECONNRESET */ 1718c2ecf20Sopenharmony_ci urb->status = pdu->u.ret_unlink.status; 1728c2ecf20Sopenharmony_ci pr_info("urb->status %d\n", urb->status); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci spin_lock_irqsave(&vhci->lock, flags); 1758c2ecf20Sopenharmony_ci usb_hcd_unlink_urb_from_ep(vhci_hcd_to_hcd(vhci_hcd), urb); 1768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vhci->lock, flags); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci usb_hcd_giveback_urb(vhci_hcd_to_hcd(vhci_hcd), urb, urb->status); 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci kfree(unlink); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int vhci_priv_tx_empty(struct vhci_device *vdev) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci int empty = 0; 1878c2ecf20Sopenharmony_ci unsigned long flags; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci spin_lock_irqsave(&vdev->priv_lock, flags); 1908c2ecf20Sopenharmony_ci empty = list_empty(&vdev->priv_rx); 1918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vdev->priv_lock, flags); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci return empty; 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* recv a pdu */ 1978c2ecf20Sopenharmony_cistatic void vhci_rx_pdu(struct usbip_device *ud) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci int ret; 2008c2ecf20Sopenharmony_ci struct usbip_header pdu; 2018c2ecf20Sopenharmony_ci struct vhci_device *vdev = container_of(ud, struct vhci_device, ud); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci usbip_dbg_vhci_rx("Enter\n"); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci memset(&pdu, 0, sizeof(pdu)); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* receive a pdu header */ 2088c2ecf20Sopenharmony_ci ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu)); 2098c2ecf20Sopenharmony_ci if (ret < 0) { 2108c2ecf20Sopenharmony_ci if (ret == -ECONNRESET) 2118c2ecf20Sopenharmony_ci pr_info("connection reset by peer\n"); 2128c2ecf20Sopenharmony_ci else if (ret == -EAGAIN) { 2138c2ecf20Sopenharmony_ci /* ignore if connection was idle */ 2148c2ecf20Sopenharmony_ci if (vhci_priv_tx_empty(vdev)) 2158c2ecf20Sopenharmony_ci return; 2168c2ecf20Sopenharmony_ci pr_info("connection timed out with pending urbs\n"); 2178c2ecf20Sopenharmony_ci } else if (ret != -ERESTARTSYS) 2188c2ecf20Sopenharmony_ci pr_info("xmit failed %d\n", ret); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); 2218c2ecf20Sopenharmony_ci return; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci if (ret == 0) { 2248c2ecf20Sopenharmony_ci pr_info("connection closed"); 2258c2ecf20Sopenharmony_ci usbip_event_add(ud, VDEV_EVENT_DOWN); 2268c2ecf20Sopenharmony_ci return; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci if (ret != sizeof(pdu)) { 2298c2ecf20Sopenharmony_ci pr_err("received pdu size is %d, should be %d\n", ret, 2308c2ecf20Sopenharmony_ci (unsigned int)sizeof(pdu)); 2318c2ecf20Sopenharmony_ci usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); 2328c2ecf20Sopenharmony_ci return; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci usbip_header_correct_endian(&pdu, 0); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (usbip_dbg_flag_vhci_rx) 2388c2ecf20Sopenharmony_ci usbip_dump_header(&pdu); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci switch (pdu.base.command) { 2418c2ecf20Sopenharmony_ci case USBIP_RET_SUBMIT: 2428c2ecf20Sopenharmony_ci vhci_recv_ret_submit(vdev, &pdu); 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci case USBIP_RET_UNLINK: 2458c2ecf20Sopenharmony_ci vhci_recv_ret_unlink(vdev, &pdu); 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci default: 2488c2ecf20Sopenharmony_ci /* NOT REACHED */ 2498c2ecf20Sopenharmony_ci pr_err("unknown pdu %u\n", pdu.base.command); 2508c2ecf20Sopenharmony_ci usbip_dump_header(&pdu); 2518c2ecf20Sopenharmony_ci usbip_event_add(ud, VDEV_EVENT_ERROR_TCP); 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ciint vhci_rx_loop(void *data) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci struct usbip_device *ud = data; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci while (!kthread_should_stop()) { 2618c2ecf20Sopenharmony_ci if (usbip_event_happened(ud)) 2628c2ecf20Sopenharmony_ci break; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci vhci_rx_pdu(ud); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci} 269