aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/usbip/stub_tx.c74
-rw-r--r--drivers/staging/usbip/usbip_common.c57
-rw-r--r--drivers/staging/usbip/usbip_common.h2
-rw-r--r--drivers/staging/usbip/vhci_rx.c3
4 files changed, 122 insertions, 14 deletions
diff --git a/drivers/staging/usbip/stub_tx.c b/drivers/staging/usbip/stub_tx.c
index 5523f25998e6..64a52b26dcf6 100644
--- a/drivers/staging/usbip/stub_tx.c
+++ b/drivers/staging/usbip/stub_tx.c
@@ -170,7 +170,6 @@ static int stub_send_ret_submit(struct stub_device *sdev)
170 struct stub_priv *priv, *tmp; 170 struct stub_priv *priv, *tmp;
171 171
172 struct msghdr msg; 172 struct msghdr msg;
173 struct kvec iov[3];
174 size_t txsize; 173 size_t txsize;
175 174
176 size_t total_size = 0; 175 size_t total_size = 0;
@@ -180,28 +179,73 @@ static int stub_send_ret_submit(struct stub_device *sdev)
180 struct urb *urb = priv->urb; 179 struct urb *urb = priv->urb;
181 struct usbip_header pdu_header; 180 struct usbip_header pdu_header;
182 void *iso_buffer = NULL; 181 void *iso_buffer = NULL;
182 struct kvec *iov = NULL;
183 int iovnum = 0;
183 184
184 txsize = 0; 185 txsize = 0;
185 memset(&pdu_header, 0, sizeof(pdu_header)); 186 memset(&pdu_header, 0, sizeof(pdu_header));
186 memset(&msg, 0, sizeof(msg)); 187 memset(&msg, 0, sizeof(msg));
187 memset(&iov, 0, sizeof(iov));
188 188
189 usbip_dbg_stub_tx("setup txdata urb %p\n", urb); 189 if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
190 iovnum = 2 + urb->number_of_packets;
191 else
192 iovnum = 2;
193
194 iov = kzalloc(iovnum * sizeof(struct kvec), GFP_KERNEL);
190 195
196 if (!iov) {
197 usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_MALLOC);
198 return -1;
199 }
200
201 iovnum = 0;
191 202
192 /* 1. setup usbip_header */ 203 /* 1. setup usbip_header */
193 setup_ret_submit_pdu(&pdu_header, urb); 204 setup_ret_submit_pdu(&pdu_header, urb);
205 usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n",
206 pdu_header.base.seqnum, urb);
207 /*usbip_dump_header(pdu_header);*/
194 usbip_header_correct_endian(&pdu_header, 1); 208 usbip_header_correct_endian(&pdu_header, 1);
195 209
196 iov[0].iov_base = &pdu_header; 210 iov[iovnum].iov_base = &pdu_header;
197 iov[0].iov_len = sizeof(pdu_header); 211 iov[iovnum].iov_len = sizeof(pdu_header);
212 iovnum++;
198 txsize += sizeof(pdu_header); 213 txsize += sizeof(pdu_header);
199 214
200 /* 2. setup transfer buffer */ 215 /* 2. setup transfer buffer */
201 if (usb_pipein(urb->pipe) && urb->actual_length > 0) { 216 if (usb_pipein(urb->pipe) &&
202 iov[1].iov_base = urb->transfer_buffer; 217 usb_pipetype(urb->pipe) != PIPE_ISOCHRONOUS &&
203 iov[1].iov_len = urb->actual_length; 218 urb->actual_length > 0) {
219 iov[iovnum].iov_base = urb->transfer_buffer;
220 iov[iovnum].iov_len = urb->actual_length;
221 iovnum++;
204 txsize += urb->actual_length; 222 txsize += urb->actual_length;
223 } else if (usb_pipein(urb->pipe) &&
224 usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
225 /*
226 * For isochronous packets: actual length is the sum of
227 * the actual length of the individual, packets, but as
228 * the packet offsets are not changed there will be
229 * padding between the packets. To optimally use the
230 * bandwidth the padding is not transmitted.
231 */
232
233 int i;
234 for (i = 0; i < urb->number_of_packets; i++) {
235 iov[iovnum].iov_base = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
236 iov[iovnum].iov_len = urb->iso_frame_desc[i].actual_length;
237 iovnum++;
238 txsize += urb->iso_frame_desc[i].actual_length;
239 }
240
241 if (txsize != sizeof(pdu_header) + urb->actual_length) {
242 dev_err(&sdev->interface->dev,
243 "actual length of urb (%d) does not match iso packet sizes (%d)\n",
244 urb->actual_length, txsize-sizeof(pdu_header));
245 kfree(iov);
246 usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
247 return -1;
248 }
205 } 249 }
206 250
207 /* 3. setup iso_packet_descriptor */ 251 /* 3. setup iso_packet_descriptor */
@@ -212,32 +256,34 @@ static int stub_send_ret_submit(struct stub_device *sdev)
212 if (!iso_buffer) { 256 if (!iso_buffer) {
213 usbip_event_add(&sdev->ud, 257 usbip_event_add(&sdev->ud,
214 SDEV_EVENT_ERROR_MALLOC); 258 SDEV_EVENT_ERROR_MALLOC);
259 kfree(iov);
215 return -1; 260 return -1;
216 } 261 }
217 262
218 iov[2].iov_base = iso_buffer; 263 iov[iovnum].iov_base = iso_buffer;
219 iov[2].iov_len = len; 264 iov[iovnum].iov_len = len;
220 txsize += len; 265 txsize += len;
266 iovnum++;
221 } 267 }
222 268
223 ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg, iov, 269 ret = kernel_sendmsg(sdev->ud.tcp_socket, &msg,
224 3, txsize); 270 iov, iovnum, txsize);
225 if (ret != txsize) { 271 if (ret != txsize) {
226 dev_err(&sdev->interface->dev, 272 dev_err(&sdev->interface->dev,
227 "sendmsg failed!, retval %d for %zd\n", 273 "sendmsg failed!, retval %d for %zd\n",
228 ret, txsize); 274 ret, txsize);
275 kfree(iov);
229 kfree(iso_buffer); 276 kfree(iso_buffer);
230 usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); 277 usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP);
231 return -1; 278 return -1;
232 } 279 }
233 280
281 kfree(iov);
234 kfree(iso_buffer); 282 kfree(iso_buffer);
235 usbip_dbg_stub_tx("send txdata\n");
236 283
237 total_size += txsize; 284 total_size += txsize;
238 } 285 }
239 286
240
241 spin_lock_irqsave(&sdev->priv_lock, flags); 287 spin_lock_irqsave(&sdev->priv_lock, flags);
242 288
243 list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) { 289 list_for_each_entry_safe(priv, tmp, &sdev->priv_free, list) {
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index 85622153ea7c..7b1fe45bf7dd 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -730,6 +730,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb)
730 int size = np * sizeof(*iso); 730 int size = np * sizeof(*iso);
731 int i; 731 int i;
732 int ret; 732 int ret;
733 int total_length = 0;
733 734
734 if (!usb_pipeisoc(urb->pipe)) 735 if (!usb_pipeisoc(urb->pipe))
735 return 0; 736 return 0;
@@ -759,19 +760,75 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb)
759 return -EPIPE; 760 return -EPIPE;
760 } 761 }
761 762
763
762 for (i = 0; i < np; i++) { 764 for (i = 0; i < np; i++) {
763 iso = buff + (i * sizeof(*iso)); 765 iso = buff + (i * sizeof(*iso));
764 766
765 usbip_iso_pakcet_correct_endian(iso, 0); 767 usbip_iso_pakcet_correct_endian(iso, 0);
766 usbip_pack_iso(iso, &urb->iso_frame_desc[i], 0); 768 usbip_pack_iso(iso, &urb->iso_frame_desc[i], 0);
769 total_length += urb->iso_frame_desc[i].actual_length;
767 } 770 }
768 771
769 kfree(buff); 772 kfree(buff);
770 773
774 if (total_length != urb->actual_length) {
775 dev_err(&urb->dev->dev,
776 "total length of iso packets (%d) not equal to actual length of buffer (%d)\n",
777 total_length, urb->actual_length);
778
779 if (ud->side == USBIP_STUB)
780 usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
781 else
782 usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
783
784 return -EPIPE;
785 }
786
771 return ret; 787 return ret;
772} 788}
773EXPORT_SYMBOL_GPL(usbip_recv_iso); 789EXPORT_SYMBOL_GPL(usbip_recv_iso);
774 790
791/*
792 * This functions restores the padding which was removed for optimizing
793 * the bandwidth during transfer over tcp/ip
794 *
795 * buffer and iso packets need to be stored and be in propeper endian in urb
796 * before calling this function
797 */
798int usbip_pad_iso(struct usbip_device *ud, struct urb *urb)
799{
800 int np = urb->number_of_packets;
801 int i;
802 int ret;
803 int actualoffset = urb->actual_length;
804
805 if (!usb_pipeisoc(urb->pipe))
806 return 0;
807
808 /* if no packets or length of data is 0, then nothing to unpack */
809 if (np == 0 || urb->actual_length == 0)
810 return 0;
811
812 /*
813 * if actual_length is transfer_buffer_length then no padding is
814 * present.
815 */
816 if (urb->actual_length == urb->transfer_buffer_length)
817 return 0;
818
819 /*
820 * loop over all packets from last to first (to prevent overwritting
821 * memory when padding) and move them into the proper place
822 */
823 for (i = np-1; i > 0; i--) {
824 actualoffset -= urb->iso_frame_desc[i].actual_length;
825 memmove(urb->transfer_buffer + urb->iso_frame_desc[i].offset,
826 urb->transfer_buffer + actualoffset,
827 urb->iso_frame_desc[i].actual_length);
828 }
829 return ret;
830}
831EXPORT_SYMBOL_GPL(usbip_pad_iso);
775 832
776/* some members of urb must be substituted before. */ 833/* some members of urb must be substituted before. */
777int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) 834int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h
index 9f809c315d92..c767f52be5fb 100644
--- a/drivers/staging/usbip/usbip_common.h
+++ b/drivers/staging/usbip/usbip_common.h
@@ -379,6 +379,8 @@ void usbip_header_correct_endian(struct usbip_header *pdu, int send);
379int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb); 379int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb);
380/* some members of urb must be substituted before. */ 380/* some members of urb must be substituted before. */
381int usbip_recv_iso(struct usbip_device *ud, struct urb *urb); 381int usbip_recv_iso(struct usbip_device *ud, struct urb *urb);
382/* some members of urb must be substituted before. */
383int usbip_pad_iso(struct usbip_device *ud, struct urb *urb);
382void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen); 384void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen);
383 385
384 386
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c
index 09bf2355934b..2ffc96a4c0d4 100644
--- a/drivers/staging/usbip/vhci_rx.c
+++ b/drivers/staging/usbip/vhci_rx.c
@@ -100,6 +100,9 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev,
100 if (usbip_recv_iso(ud, urb) < 0) 100 if (usbip_recv_iso(ud, urb) < 0)
101 return; 101 return;
102 102
103 /* restore the padding in iso packets */
104 if (usbip_pad_iso(ud, urb) < 0)
105 return;
103 106
104 if (usbip_dbg_flag_vhci_rx) 107 if (usbip_dbg_flag_vhci_rx)
105 usbip_dump_urb(urb); 108 usbip_dump_urb(urb);