vudc_tx.c (6461B)
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 inline void setup_base_pdu(struct usbip_header_basic *base, 16 __u32 command, __u32 seqnum) 17{ 18 base->command = command; 19 base->seqnum = seqnum; 20 base->devid = 0; 21 base->ep = 0; 22 base->direction = 0; 23} 24 25static void setup_ret_submit_pdu(struct usbip_header *rpdu, struct urbp *urb_p) 26{ 27 setup_base_pdu(&rpdu->base, USBIP_RET_SUBMIT, urb_p->seqnum); 28 usbip_pack_pdu(rpdu, urb_p->urb, USBIP_RET_SUBMIT, 1); 29} 30 31static void setup_ret_unlink_pdu(struct usbip_header *rpdu, 32 struct v_unlink *unlink) 33{ 34 setup_base_pdu(&rpdu->base, USBIP_RET_UNLINK, unlink->seqnum); 35 rpdu->u.ret_unlink.status = unlink->status; 36} 37 38static int v_send_ret_unlink(struct vudc *udc, struct v_unlink *unlink) 39{ 40 struct msghdr msg; 41 struct kvec iov[1]; 42 size_t txsize; 43 44 int ret; 45 struct usbip_header pdu_header; 46 47 txsize = 0; 48 memset(&pdu_header, 0, sizeof(pdu_header)); 49 memset(&msg, 0, sizeof(msg)); 50 memset(&iov, 0, sizeof(iov)); 51 52 /* 1. setup usbip_header */ 53 setup_ret_unlink_pdu(&pdu_header, unlink); 54 usbip_header_correct_endian(&pdu_header, 1); 55 56 iov[0].iov_base = &pdu_header; 57 iov[0].iov_len = sizeof(pdu_header); 58 txsize += sizeof(pdu_header); 59 60 ret = kernel_sendmsg(udc->ud.tcp_socket, &msg, iov, 61 1, txsize); 62 if (ret != txsize) { 63 usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP); 64 if (ret >= 0) 65 return -EPIPE; 66 return ret; 67 } 68 kfree(unlink); 69 70 return txsize; 71} 72 73static int v_send_ret_submit(struct vudc *udc, struct urbp *urb_p) 74{ 75 struct urb *urb = urb_p->urb; 76 struct usbip_header pdu_header; 77 struct usbip_iso_packet_descriptor *iso_buffer = NULL; 78 struct kvec *iov = NULL; 79 int iovnum = 0; 80 int ret = 0; 81 size_t txsize; 82 struct msghdr msg; 83 84 txsize = 0; 85 memset(&pdu_header, 0, sizeof(pdu_header)); 86 memset(&msg, 0, sizeof(msg)); 87 88 if (urb->actual_length > 0 && !urb->transfer_buffer) { 89 dev_err(&udc->gadget.dev, 90 "urb: actual_length %d transfer_buffer null\n", 91 urb->actual_length); 92 return -1; 93 } 94 95 if (urb_p->type == USB_ENDPOINT_XFER_ISOC) 96 iovnum = 2 + urb->number_of_packets; 97 else 98 iovnum = 2; 99 100 iov = kcalloc(iovnum, sizeof(*iov), GFP_KERNEL); 101 if (!iov) { 102 usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_MALLOC); 103 ret = -ENOMEM; 104 goto out; 105 } 106 iovnum = 0; 107 108 /* 1. setup usbip_header */ 109 setup_ret_submit_pdu(&pdu_header, urb_p); 110 usbip_dbg_stub_tx("setup txdata seqnum: %d\n", 111 pdu_header.base.seqnum); 112 usbip_header_correct_endian(&pdu_header, 1); 113 114 iov[iovnum].iov_base = &pdu_header; 115 iov[iovnum].iov_len = sizeof(pdu_header); 116 iovnum++; 117 txsize += sizeof(pdu_header); 118 119 /* 2. setup transfer buffer */ 120 if (urb_p->type != USB_ENDPOINT_XFER_ISOC && 121 usb_pipein(urb->pipe) && urb->actual_length > 0) { 122 iov[iovnum].iov_base = urb->transfer_buffer; 123 iov[iovnum].iov_len = urb->actual_length; 124 iovnum++; 125 txsize += urb->actual_length; 126 } else if (urb_p->type == USB_ENDPOINT_XFER_ISOC && 127 usb_pipein(urb->pipe)) { 128 /* FIXME - copypasted from stub_tx, refactor */ 129 int i; 130 131 for (i = 0; i < urb->number_of_packets; i++) { 132 iov[iovnum].iov_base = urb->transfer_buffer + 133 urb->iso_frame_desc[i].offset; 134 iov[iovnum].iov_len = 135 urb->iso_frame_desc[i].actual_length; 136 iovnum++; 137 txsize += urb->iso_frame_desc[i].actual_length; 138 } 139 140 if (txsize != sizeof(pdu_header) + urb->actual_length) { 141 usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP); 142 ret = -EPIPE; 143 goto out; 144 } 145 } 146 /* else - no buffer to send */ 147 148 /* 3. setup iso_packet_descriptor */ 149 if (urb_p->type == USB_ENDPOINT_XFER_ISOC) { 150 ssize_t len = 0; 151 152 iso_buffer = usbip_alloc_iso_desc_pdu(urb, &len); 153 if (!iso_buffer) { 154 usbip_event_add(&udc->ud, 155 VUDC_EVENT_ERROR_MALLOC); 156 ret = -ENOMEM; 157 goto out; 158 } 159 160 iov[iovnum].iov_base = iso_buffer; 161 iov[iovnum].iov_len = len; 162 txsize += len; 163 iovnum++; 164 } 165 166 ret = kernel_sendmsg(udc->ud.tcp_socket, &msg, 167 iov, iovnum, txsize); 168 if (ret != txsize) { 169 usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP); 170 if (ret >= 0) 171 ret = -EPIPE; 172 goto out; 173 } 174 175out: 176 kfree(iov); 177 kfree(iso_buffer); 178 free_urbp_and_urb(urb_p); 179 if (ret < 0) 180 return ret; 181 return txsize; 182} 183 184static int v_send_ret(struct vudc *udc) 185{ 186 unsigned long flags; 187 struct tx_item *txi; 188 size_t total_size = 0; 189 int ret = 0; 190 191 spin_lock_irqsave(&udc->lock_tx, flags); 192 while (!list_empty(&udc->tx_queue)) { 193 txi = list_first_entry(&udc->tx_queue, struct tx_item, 194 tx_entry); 195 list_del(&txi->tx_entry); 196 spin_unlock_irqrestore(&udc->lock_tx, flags); 197 198 switch (txi->type) { 199 case TX_SUBMIT: 200 ret = v_send_ret_submit(udc, txi->s); 201 break; 202 case TX_UNLINK: 203 ret = v_send_ret_unlink(udc, txi->u); 204 break; 205 } 206 kfree(txi); 207 208 if (ret < 0) 209 return ret; 210 211 total_size += ret; 212 213 spin_lock_irqsave(&udc->lock_tx, flags); 214 } 215 216 spin_unlock_irqrestore(&udc->lock_tx, flags); 217 return total_size; 218} 219 220 221int v_tx_loop(void *data) 222{ 223 struct usbip_device *ud = (struct usbip_device *) data; 224 struct vudc *udc = container_of(ud, struct vudc, ud); 225 int ret; 226 227 while (!kthread_should_stop()) { 228 if (usbip_event_happened(&udc->ud)) 229 break; 230 ret = v_send_ret(udc); 231 if (ret < 0) { 232 pr_warn("v_tx exit with error %d", ret); 233 break; 234 } 235 wait_event_interruptible(udc->tx_waitq, 236 (!list_empty(&udc->tx_queue) || 237 kthread_should_stop())); 238 } 239 240 return 0; 241} 242 243/* called with spinlocks held */ 244void v_enqueue_ret_unlink(struct vudc *udc, __u32 seqnum, __u32 status) 245{ 246 struct tx_item *txi; 247 struct v_unlink *unlink; 248 249 txi = kzalloc(sizeof(*txi), GFP_ATOMIC); 250 if (!txi) { 251 usbip_event_add(&udc->ud, VDEV_EVENT_ERROR_MALLOC); 252 return; 253 } 254 unlink = kzalloc(sizeof(*unlink), GFP_ATOMIC); 255 if (!unlink) { 256 kfree(txi); 257 usbip_event_add(&udc->ud, VDEV_EVENT_ERROR_MALLOC); 258 return; 259 } 260 261 unlink->seqnum = seqnum; 262 unlink->status = status; 263 txi->type = TX_UNLINK; 264 txi->u = unlink; 265 266 list_add_tail(&txi->tx_entry, &udc->tx_queue); 267} 268 269/* called with spinlocks held */ 270void v_enqueue_ret_submit(struct vudc *udc, struct urbp *urb_p) 271{ 272 struct tx_item *txi; 273 274 txi = kzalloc(sizeof(*txi), GFP_ATOMIC); 275 if (!txi) { 276 usbip_event_add(&udc->ud, VDEV_EVENT_ERROR_MALLOC); 277 return; 278 } 279 280 txi->type = TX_SUBMIT; 281 txi->s = urb_p; 282 283 list_add_tail(&txi->tx_entry, &udc->tx_queue); 284}