diff options
author | Alan Cox <alan@lxorguk.ukuu.org.uk> | 2005-10-28 18:14:52 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-10-28 19:06:44 -0400 |
commit | 2c36ed22c6f64de94c6c3b7258dd7285bb093401 (patch) | |
tree | bf8ab970180df5abe28d0c75d993a86a063bd8d5 /drivers/net | |
parent | 63f57fb69b017230c77c40f1713e40885ae6d159 (diff) |
[PATCH] Better fixup for the orinoco driver
The latest kernel added a pretty ugly fix for the orinoco etherleak bug
which contains bogus skb->len checks already done by the caller and causes
copies of all odd sized frames (which are quite common)
While the skb->len check should be ripped out the other fix is harder to do
properly so I'm proposing for this the -mm tree only until next 2.6.x so
that it gets tested.
Instead of copying buffers around blindly this code implements a padding
aware version of the hermes buffer writing function which does padding as
the buffer is loaded and thus more cleanly and without bogus 1.5K copies.
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/hermes.c | 38 | ||||
-rw-r--r-- | drivers/net/wireless/hermes.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco.c | 11 |
3 files changed, 49 insertions, 2 deletions
diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c index eba0d9d2b7c5..579480dad374 100644 --- a/drivers/net/wireless/hermes.c +++ b/drivers/net/wireless/hermes.c | |||
@@ -444,6 +444,43 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, | |||
444 | return err; | 444 | return err; |
445 | } | 445 | } |
446 | 446 | ||
447 | /* Write a block of data to the chip's buffer with padding if | ||
448 | * neccessary, via the BAP. Synchronization/serialization is the | ||
449 | * caller's problem. len must be even. | ||
450 | * | ||
451 | * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware | ||
452 | */ | ||
453 | int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf, unsigned data_len, unsigned len, | ||
454 | u16 id, u16 offset) | ||
455 | { | ||
456 | int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; | ||
457 | int err = 0; | ||
458 | |||
459 | if (len < 0 || len % 2 || data_len > len) | ||
460 | return -EINVAL; | ||
461 | |||
462 | err = hermes_bap_seek(hw, bap, id, offset); | ||
463 | if (err) | ||
464 | goto out; | ||
465 | |||
466 | /* Transfer all the complete words of data */ | ||
467 | hermes_write_words(hw, dreg, buf, data_len/2); | ||
468 | /* If there is an odd byte left over pad and transfer it */ | ||
469 | if (data_len & 1) { | ||
470 | u8 end[2]; | ||
471 | end[1] = 0; | ||
472 | end[0] = ((unsigned char *)buf)[data_len - 1]; | ||
473 | hermes_write_words(hw, dreg, end, 1); | ||
474 | data_len ++; | ||
475 | } | ||
476 | /* Now send zeros for the padding */ | ||
477 | if (data_len < len) | ||
478 | hermes_clear_words(hw, dreg, (len - data_len) / 2); | ||
479 | /* Complete */ | ||
480 | out: | ||
481 | return err; | ||
482 | } | ||
483 | |||
447 | /* Read a Length-Type-Value record from the card. | 484 | /* Read a Length-Type-Value record from the card. |
448 | * | 485 | * |
449 | * If length is NULL, we ignore the length read from the card, and | 486 | * If length is NULL, we ignore the length read from the card, and |
@@ -531,6 +568,7 @@ EXPORT_SYMBOL(hermes_allocate); | |||
531 | 568 | ||
532 | EXPORT_SYMBOL(hermes_bap_pread); | 569 | EXPORT_SYMBOL(hermes_bap_pread); |
533 | EXPORT_SYMBOL(hermes_bap_pwrite); | 570 | EXPORT_SYMBOL(hermes_bap_pwrite); |
571 | EXPORT_SYMBOL(hermes_bap_pwrite_pad); | ||
534 | EXPORT_SYMBOL(hermes_read_ltv); | 572 | EXPORT_SYMBOL(hermes_read_ltv); |
535 | EXPORT_SYMBOL(hermes_write_ltv); | 573 | EXPORT_SYMBOL(hermes_write_ltv); |
536 | 574 | ||
diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h index ad28e3294360..a6bd472d75d4 100644 --- a/drivers/net/wireless/hermes.h +++ b/drivers/net/wireless/hermes.h | |||
@@ -376,6 +376,8 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len, | |||
376 | u16 id, u16 offset); | 376 | u16 id, u16 offset); |
377 | int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, | 377 | int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, |
378 | u16 id, u16 offset); | 378 | u16 id, u16 offset); |
379 | int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf, | ||
380 | unsigned data_len, unsigned len, u16 id, u16 offset); | ||
379 | int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen, | 381 | int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen, |
380 | u16 *length, void *buf); | 382 | u16 *length, void *buf); |
381 | int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, | 383 | int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, |
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 70a3477a2061..488ab06fb79f 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c | |||
@@ -542,14 +542,21 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) | |||
542 | stats->tx_errors++; | 542 | stats->tx_errors++; |
543 | goto fail; | 543 | goto fail; |
544 | } | 544 | } |
545 | /* Actual xfer length - allow for padding */ | ||
546 | len = ALIGN(data_len, 2); | ||
547 | if (len < ETH_ZLEN - ETH_HLEN) | ||
548 | len = ETH_ZLEN - ETH_HLEN; | ||
545 | } else { /* IEEE 802.3 frame */ | 549 | } else { /* IEEE 802.3 frame */ |
546 | data_len = len + ETH_HLEN; | 550 | data_len = len + ETH_HLEN; |
547 | data_off = HERMES_802_3_OFFSET; | 551 | data_off = HERMES_802_3_OFFSET; |
548 | p = skb->data; | 552 | p = skb->data; |
553 | /* Actual xfer length - round up for odd length packets */ | ||
554 | len = ALIGN(data_len, 2); | ||
555 | if (len < ETH_ZLEN) | ||
556 | len = ETH_ZLEN; | ||
549 | } | 557 | } |
550 | 558 | ||
551 | /* Round up for odd length packets */ | 559 | err = hermes_bap_pwrite_pad(hw, USER_BAP, p, data_len, len, |
552 | err = hermes_bap_pwrite(hw, USER_BAP, p, ALIGN(data_len, 2), | ||
553 | txfid, data_off); | 560 | txfid, data_off); |
554 | if (err) { | 561 | if (err) { |
555 | printk(KERN_ERR "%s: Error %d writing packet to BAP\n", | 562 | printk(KERN_ERR "%s: Error %d writing packet to BAP\n", |