aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/atm
diff options
context:
space:
mode:
authorDuncan Sands <baldrick@free.fr>2006-01-13 05:06:46 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-01-31 20:23:40 -0500
commite3fb2f641f421662ebda48763f2f03cb9bd29e82 (patch)
tree2511087a08a177c27bf28207f3ab05ac3093b85d /drivers/usb/atm
parent80aae7a17afd21f7ba900dd566fb23a2444021f8 (diff)
[PATCH] USBATM: handle urbs containing partial cells
The receive logic has always assumed that urbs contain an integral number of ATM cells, which is a bit naughty, though it never caused any problems with bulk transfers. Isochronous urbs spank us soundly for this. Fixed thanks to this patch, mostly by Stanislaw Gruszka. Signed-off-by: Duncan Sands <baldrick@free.fr> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/atm')
-rw-r--r--drivers/usb/atm/usbatm.c271
-rw-r--r--drivers/usb/atm/usbatm.h7
2 files changed, 182 insertions, 96 deletions
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 923f2d9269bc..341430fbaf9c 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -296,126 +296,159 @@ static inline struct usbatm_vcc_data *usbatm_find_vcc(struct usbatm_data *instan
296 return NULL; 296 return NULL;
297} 297}
298 298
299static void usbatm_extract_cells(struct usbatm_data *instance, 299static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char *source)
300 unsigned char *source, unsigned int avail_data)
301{ 300{
302 struct usbatm_vcc_data *cached_vcc = NULL;
303 struct atm_vcc *vcc; 301 struct atm_vcc *vcc;
304 struct sk_buff *sarb; 302 struct sk_buff *sarb;
305 unsigned int stride = instance->rx_channel.stride; 303 short vpi = ((source[0] & 0x0f) << 4) | (source[1] >> 4);
306 int vci, cached_vci = 0; 304 int vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
307 short vpi, cached_vpi = 0; 305 u8 pti = ((source[3] & 0xe) >> 1);
308 u8 pti;
309 306
310 for (; avail_data >= stride; avail_data -= stride, source += stride) { 307 vdbg("%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti);
311 vpi = ((source[0] & 0x0f) << 4) | (source[1] >> 4);
312 vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
313 pti = ((source[3] & 0xe) >> 1);
314 308
315 vdbg("%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti); 309 if ((vci != instance->cached_vci) || (vpi != instance->cached_vpi)) {
310 instance->cached_vpi = vpi;
311 instance->cached_vci = vci;
316 312
317 if ((vci != cached_vci) || (vpi != cached_vpi)) { 313 instance->cached_vcc = usbatm_find_vcc(instance, vpi, vci);
318 cached_vpi = vpi;
319 cached_vci = vci;
320 314
321 cached_vcc = usbatm_find_vcc(instance, vpi, vci); 315 if (!instance->cached_vcc)
316 atm_rldbg(instance, "%s: unknown vpi/vci (%hd/%d)!\n", __func__, vpi, vci);
317 }
322 318
323 if (!cached_vcc) 319 if (!instance->cached_vcc)
324 atm_rldbg(instance, "%s: unknown vpi/vci (%hd/%d)!\n", __func__, vpi, vci); 320 return;
325 }
326 321
327 if (!cached_vcc) 322 vcc = instance->cached_vcc->vcc;
328 continue;
329 323
330 vcc = cached_vcc->vcc; 324 /* OAM F5 end-to-end */
325 if (pti == ATM_PTI_E2EF5) {
326 if (printk_ratelimit())
327 atm_warn(instance, "%s: OAM not supported (vpi %d, vci %d)!\n",
328 __func__, vpi, vci);
329 atomic_inc(&vcc->stats->rx_err);
330 return;
331 }
331 332
332 /* OAM F5 end-to-end */ 333 sarb = instance->cached_vcc->sarb;
333 if (pti == ATM_PTI_E2EF5) {
334 if (printk_ratelimit())
335 atm_warn(instance, "%s: OAM not supported (vpi %d, vci %d)!\n",
336 __func__, vpi, vci);
337 atomic_inc(&vcc->stats->rx_err);
338 continue;
339 }
340 334
341 sarb = cached_vcc->sarb; 335 if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) {
336 atm_rldbg(instance, "%s: buffer overrun (sarb->len %u, vcc: 0x%p)!\n",
337 __func__, sarb->len, vcc);
338 /* discard cells already received */
339 skb_trim(sarb, 0);
340 UDSL_ASSERT(sarb->tail + ATM_CELL_PAYLOAD <= sarb->end);
341 }
342 342
343 if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) { 343 memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
344 atm_rldbg(instance, "%s: buffer overrun (sarb->len %u, vcc: 0x%p)!\n", 344 __skb_put(sarb, ATM_CELL_PAYLOAD);
345 __func__, sarb->len, vcc);
346 /* discard cells already received */
347 skb_trim(sarb, 0);
348 UDSL_ASSERT(sarb->tail + ATM_CELL_PAYLOAD <= sarb->end);
349 }
350 345
351 memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD); 346 if (pti & 1) {
352 __skb_put(sarb, ATM_CELL_PAYLOAD); 347 struct sk_buff *skb;
348 unsigned int length;
349 unsigned int pdu_length;
353 350
354 if (pti & 1) { 351 length = (source[ATM_CELL_SIZE - 6] << 8) + source[ATM_CELL_SIZE - 5];
355 struct sk_buff *skb;
356 unsigned int length;
357 unsigned int pdu_length;
358 352
359 length = (source[ATM_CELL_SIZE - 6] << 8) + source[ATM_CELL_SIZE - 5]; 353 /* guard against overflow */
354 if (length > ATM_MAX_AAL5_PDU) {
355 atm_rldbg(instance, "%s: bogus length %u (vcc: 0x%p)!\n",
356 __func__, length, vcc);
357 atomic_inc(&vcc->stats->rx_err);
358 goto out;
359 }
360 360
361 /* guard against overflow */ 361 pdu_length = usbatm_pdu_length(length);
362 if (length > ATM_MAX_AAL5_PDU) {
363 atm_rldbg(instance, "%s: bogus length %u (vcc: 0x%p)!\n",
364 __func__, length, vcc);
365 atomic_inc(&vcc->stats->rx_err);
366 goto out;
367 }
368 362
369 pdu_length = usbatm_pdu_length(length); 363 if (sarb->len < pdu_length) {
364 atm_rldbg(instance, "%s: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!\n",
365 __func__, pdu_length, sarb->len, vcc);
366 atomic_inc(&vcc->stats->rx_err);
367 goto out;
368 }
370 369
371 if (sarb->len < pdu_length) { 370 if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) {
372 atm_rldbg(instance, "%s: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!\n", 371 atm_rldbg(instance, "%s: packet failed crc check (vcc: 0x%p)!\n",
373 __func__, pdu_length, sarb->len, vcc); 372 __func__, vcc);
374 atomic_inc(&vcc->stats->rx_err); 373 atomic_inc(&vcc->stats->rx_err);
375 goto out; 374 goto out;
376 } 375 }
377 376
378 if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) { 377 vdbg("%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", __func__, length, pdu_length, vcc);
379 atm_rldbg(instance, "%s: packet failed crc check (vcc: 0x%p)!\n",
380 __func__, vcc);
381 atomic_inc(&vcc->stats->rx_err);
382 goto out;
383 }
384 378
385 vdbg("%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", __func__, length, pdu_length, vcc); 379 if (!(skb = dev_alloc_skb(length))) {
380 if (printk_ratelimit())
381 atm_err(instance, "%s: no memory for skb (length: %u)!\n",
382 __func__, length);
383 atomic_inc(&vcc->stats->rx_drop);
384 goto out;
385 }
386 386
387 if (!(skb = dev_alloc_skb(length))) { 387 vdbg("%s: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", __func__, skb, skb->truesize);
388 if (printk_ratelimit())
389 atm_err(instance, "%s: no memory for skb (length: %u)!\n",
390 __func__, length);
391 atomic_inc(&vcc->stats->rx_drop);
392 goto out;
393 }
394 388
395 vdbg("%s: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", __func__, skb, skb->truesize); 389 if (!atm_charge(vcc, skb->truesize)) {
390 atm_rldbg(instance, "%s: failed atm_charge (skb->truesize: %u)!\n",
391 __func__, skb->truesize);
392 dev_kfree_skb_any(skb);
393 goto out; /* atm_charge increments rx_drop */
394 }
396 395
397 if (!atm_charge(vcc, skb->truesize)) { 396 memcpy(skb->data, sarb->tail - pdu_length, length);
398 atm_rldbg(instance, "%s: failed atm_charge (skb->truesize: %u)!\n", 397 __skb_put(skb, length);
399 __func__, skb->truesize);
400 dev_kfree_skb_any(skb);
401 goto out; /* atm_charge increments rx_drop */
402 }
403 398
404 memcpy(skb->data, sarb->tail - pdu_length, length); 399 vdbg("%s: sending skb 0x%p, skb->len %u, skb->truesize %u",
405 __skb_put(skb, length); 400 __func__, skb, skb->len, skb->truesize);
406 401
407 vdbg("%s: sending skb 0x%p, skb->len %u, skb->truesize %u", 402 PACKETDEBUG(skb->data, skb->len);
408 __func__, skb, skb->len, skb->truesize);
409 403
410 PACKETDEBUG(skb->data, skb->len); 404 vcc->push(vcc, skb);
411 405
412 vcc->push(vcc, skb); 406 atomic_inc(&vcc->stats->rx);
407 out:
408 skb_trim(sarb, 0);
409 }
410}
413 411
414 atomic_inc(&vcc->stats->rx); 412static void usbatm_extract_cells(struct usbatm_data *instance,
415 out: 413 unsigned char *source, unsigned int avail_data)
416 skb_trim(sarb, 0); 414{
415 unsigned int stride = instance->rx_channel.stride;
416 unsigned int buf_usage = instance->buf_usage;
417
418 /* extract cells from incoming data, taking into account that
419 * the length of avail data may not be a multiple of stride */
420
421 if (buf_usage > 0) {
422 /* we have a partially received atm cell */
423 unsigned char *cell_buf = instance->cell_buf;
424 unsigned int space_left = stride - buf_usage;
425
426 UDSL_ASSERT(buf_usage <= stride);
427
428 if (avail_data >= space_left) {
429 /* add new data and process cell */
430 memcpy(cell_buf + buf_usage, source, space_left);
431 source += space_left;
432 avail_data -= space_left;
433 usbatm_extract_one_cell(instance, cell_buf);
434 instance->buf_usage = 0;
435 } else {
436 /* not enough data to fill the cell */
437 memcpy(cell_buf + buf_usage, source, avail_data);
438 instance->buf_usage = buf_usage + avail_data;
439 return;
417 } 440 }
418 } 441 }
442
443 for (; avail_data >= stride; avail_data -= stride, source += stride)
444 usbatm_extract_one_cell(instance, source);
445
446 if (avail_data > 0) {
447 /* length was not a multiple of stride -
448 * save remaining data for next call */
449 memcpy(instance->cell_buf, source, avail_data);
450 instance->buf_usage = avail_data;
451 }
419} 452}
420 453
421 454
@@ -496,16 +529,40 @@ static void usbatm_rx_process(unsigned long data)
496 vdbg("%s: processing urb 0x%p", __func__, urb); 529 vdbg("%s: processing urb 0x%p", __func__, urb);
497 530
498 if (usb_pipeisoc(urb->pipe)) { 531 if (usb_pipeisoc(urb->pipe)) {
532 unsigned char *merge_start = NULL;
533 unsigned int merge_length = 0;
534 const unsigned int packet_size = instance->rx_channel.packet_size;
499 int i; 535 int i;
500 for (i = 0; i < urb->number_of_packets; i++) 536
501 if (!urb->iso_frame_desc[i].status) 537 for (i = 0; i < urb->number_of_packets; i++) {
502 usbatm_extract_cells(instance, 538 if (!urb->iso_frame_desc[i].status) {
503 (u8 *)urb->transfer_buffer + urb->iso_frame_desc[i].offset, 539 unsigned int actual_length = urb->iso_frame_desc[i].actual_length;
504 urb->iso_frame_desc[i].actual_length); 540
505 } 541 UDSL_ASSERT(actual_length <= packet_size);
506 else 542
543 if (!merge_length)
544 merge_start = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
545 merge_length += actual_length;
546 if (merge_length && (actual_length < packet_size)) {
547 usbatm_extract_cells(instance, merge_start, merge_length);
548 merge_length = 0;
549 }
550 } else {
551 atm_rldbg(instance, "%s: status %d in frame %d!\n", __func__, urb->status, i);
552 if (merge_length)
553 usbatm_extract_cells(instance, merge_start, merge_length);
554 merge_length = 0;
555 instance->buf_usage = 0;
556 }
557 }
558
559 if (merge_length)
560 usbatm_extract_cells(instance, merge_start, merge_length);
561 } else
507 if (!urb->status) 562 if (!urb->status)
508 usbatm_extract_cells(instance, urb->transfer_buffer, urb->actual_length); 563 usbatm_extract_cells(instance, urb->transfer_buffer, urb->actual_length);
564 else
565 instance->buf_usage = 0;
509 566
510 if (usbatm_submit_urb(urb)) 567 if (usbatm_submit_urb(urb))
511 return; 568 return;
@@ -797,6 +854,9 @@ static int usbatm_atm_open(struct atm_vcc *vcc)
797 vcc->dev_data = new; 854 vcc->dev_data = new;
798 855
799 tasklet_disable(&instance->rx_channel.tasklet); 856 tasklet_disable(&instance->rx_channel.tasklet);
857 instance->cached_vcc = new;
858 instance->cached_vpi = vpi;
859 instance->cached_vci = vci;
800 list_add(&new->list, &instance->vcc_list); 860 list_add(&new->list, &instance->vcc_list);
801 tasklet_enable(&instance->rx_channel.tasklet); 861 tasklet_enable(&instance->rx_channel.tasklet);
802 862
@@ -836,6 +896,11 @@ static void usbatm_atm_close(struct atm_vcc *vcc)
836 down(&instance->serialize); /* vs self, usbatm_atm_open, usbatm_usb_disconnect */ 896 down(&instance->serialize); /* vs self, usbatm_atm_open, usbatm_usb_disconnect */
837 897
838 tasklet_disable(&instance->rx_channel.tasklet); 898 tasklet_disable(&instance->rx_channel.tasklet);
899 if (instance->cached_vcc == vcc_data) {
900 instance->cached_vcc = NULL;
901 instance->cached_vpi = ATM_VPI_UNSPEC;
902 instance->cached_vci = ATM_VCI_UNSPEC;
903 }
839 list_del(&vcc_data->list); 904 list_del(&vcc_data->list);
840 tasklet_enable(&instance->rx_channel.tasklet); 905 tasklet_enable(&instance->rx_channel.tasklet);
841 906
@@ -1146,6 +1211,16 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
1146 __func__, urb->transfer_buffer, urb->transfer_buffer_length, urb); 1211 __func__, urb->transfer_buffer, urb->transfer_buffer_length, urb);
1147 } 1212 }
1148 1213
1214 instance->cached_vpi = ATM_VPI_UNSPEC;
1215 instance->cached_vci = ATM_VCI_UNSPEC;
1216 instance->cell_buf = kmalloc(instance->rx_channel.stride, GFP_KERNEL);
1217
1218 if (!instance->cell_buf) {
1219 dev_err(dev, "%s: no memory for cell buffer!\n", __func__);
1220 error = -ENOMEM;
1221 goto fail_unbind;
1222 }
1223
1149 if (!(instance->flags & UDSL_SKIP_HEAVY_INIT) && driver->heavy_init) { 1224 if (!(instance->flags & UDSL_SKIP_HEAVY_INIT) && driver->heavy_init) {
1150 error = usbatm_heavy_init(instance); 1225 error = usbatm_heavy_init(instance);
1151 } else { 1226 } else {
@@ -1165,6 +1240,8 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
1165 if (instance->driver->unbind) 1240 if (instance->driver->unbind)
1166 instance->driver->unbind(instance, intf); 1241 instance->driver->unbind(instance, intf);
1167 fail_free: 1242 fail_free:
1243 kfree(instance->cell_buf);
1244
1168 for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { 1245 for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
1169 if (instance->urbs[i]) 1246 if (instance->urbs[i])
1170 kfree(instance->urbs[i]->transfer_buffer); 1247 kfree(instance->urbs[i]->transfer_buffer);
@@ -1236,6 +1313,8 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
1236 usb_free_urb(instance->urbs[i]); 1313 usb_free_urb(instance->urbs[i]);
1237 } 1314 }
1238 1315
1316 kfree(instance->cell_buf);
1317
1239 /* ATM finalize */ 1318 /* ATM finalize */
1240 if (instance->atm_dev) 1319 if (instance->atm_dev)
1241 atm_dev_deregister(instance->atm_dev); 1320 atm_dev_deregister(instance->atm_dev);
diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h
index 0e2caa0967c1..bdff534b941d 100644
--- a/drivers/usb/atm/usbatm.h
+++ b/drivers/usb/atm/usbatm.h
@@ -187,6 +187,13 @@ struct usbatm_data {
187 struct sk_buff_head sndqueue; 187 struct sk_buff_head sndqueue;
188 struct sk_buff *current_skb; /* being emptied */ 188 struct sk_buff *current_skb; /* being emptied */
189 189
190 struct usbatm_vcc_data *cached_vcc;
191 int cached_vci;
192 short cached_vpi;
193
194 unsigned char *cell_buf; /* holds partial rx cell */
195 unsigned int buf_usage;
196
190 struct urb *urbs[0]; 197 struct urb *urbs[0];
191}; 198};
192 199