aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@lxorguk.ukuu.org.uk>2005-10-28 18:14:52 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-10-28 19:06:44 -0400
commit2c36ed22c6f64de94c6c3b7258dd7285bb093401 (patch)
treebf8ab970180df5abe28d0c75d993a86a063bd8d5
parent63f57fb69b017230c77c40f1713e40885ae6d159 (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>
-rw-r--r--drivers/net/wireless/hermes.c38
-rw-r--r--drivers/net/wireless/hermes.h2
-rw-r--r--drivers/net/wireless/orinoco.c11
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 */
453int 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
532EXPORT_SYMBOL(hermes_bap_pread); 569EXPORT_SYMBOL(hermes_bap_pread);
533EXPORT_SYMBOL(hermes_bap_pwrite); 570EXPORT_SYMBOL(hermes_bap_pwrite);
571EXPORT_SYMBOL(hermes_bap_pwrite_pad);
534EXPORT_SYMBOL(hermes_read_ltv); 572EXPORT_SYMBOL(hermes_read_ltv);
535EXPORT_SYMBOL(hermes_write_ltv); 573EXPORT_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);
377int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, 377int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len,
378 u16 id, u16 offset); 378 u16 id, u16 offset);
379int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf,
380 unsigned data_len, unsigned len, u16 id, u16 offset);
379int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen, 381int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen,
380 u16 *length, void *buf); 382 u16 *length, void *buf);
381int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, 383int 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",