]> err.no Git - linux-2.6/blobdiff - drivers/net/wireless/orinoco.c
Workaround kernel BUG_ON panic caused by unexpected duplicate packets.
[linux-2.6] / drivers / net / wireless / orinoco.c
index 1ae301c622817f699a6f1a927c75cda7ddbab059..488ab06fb79f46e81061f75d72c872121f286ee5 100644 (file)
@@ -492,7 +492,11 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* Length of the packet body */
        /* FIXME: what if the skb is smaller than this? */
-       len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN);
+       len = max_t(int, ALIGN(skb->len, 2), ETH_ZLEN);
+       skb = skb_padto(skb, len);
+       if (skb == NULL)
+               goto fail;
+       len -= ETH_HLEN;
 
        eh = (struct ethhdr *)skb->data;
 
@@ -538,14 +542,21 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                        stats->tx_errors++;
                        goto fail;
                }
+               /* Actual xfer length - allow for padding */
+               len = ALIGN(data_len, 2);
+               if (len < ETH_ZLEN - ETH_HLEN)
+                       len = ETH_ZLEN - ETH_HLEN;
        } else { /* IEEE 802.3 frame */
                data_len = len + ETH_HLEN;
                data_off = HERMES_802_3_OFFSET;
                p = skb->data;
+               /* Actual xfer length - round up for odd length packets */
+               len = ALIGN(data_len, 2);
+               if (len < ETH_ZLEN)
+                       len = ETH_ZLEN;
        }
 
-       /* Round up for odd length packets */
-       err = hermes_bap_pwrite(hw, USER_BAP, p, ALIGN(data_len, 2),
+       err = hermes_bap_pwrite_pad(hw, USER_BAP, p, data_len, len,
                                txfid, data_off);
        if (err) {
                printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
@@ -561,8 +572,9 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
                                txfid, NULL);
        if (err) {
                netif_start_queue(dev);
-               printk(KERN_ERR "%s: Error %d transmitting packet\n",
-                      dev->name, err);
+               if (net_ratelimit())
+                       printk(KERN_ERR "%s: Error %d transmitting packet\n",
+                               dev->name, err);
                stats->tx_errors++;
                goto fail;
        }
@@ -623,10 +635,10 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw)
        if (fid == DUMMY_FID)
                return; /* Nothing's really happened */
 
-       /* Read the frame header */
+       /* Read part of the frame header - we need status and addr1 */
        err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
-                              sizeof(struct hermes_tx_descriptor) +
-                              sizeof(struct ieee80211_hdr_4addr),
+                              offsetof(struct hermes_tx_descriptor_802_11,
+                                       addr2),
                               fid, 0);
 
        hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);