adm8211: Restore frame header after TX

This patch makes the adm8211 driver restore the TX frame's header to
the original 802.11 header before returning it to the 802.11 stack. This allows
the d80211 rate control algorithm to work correctly.

Signed-off-by: Michael Wu <[EMAIL PROTECTED]>
---

 drivers/net/wireless/d80211/adm8211/adm8211.c |   79 +++++++++++++------------
 drivers/net/wireless/d80211/adm8211/adm8211.h |   13 +++-
 2 files changed, 49 insertions(+), 43 deletions(-)

diff --git a/drivers/net/wireless/d80211/adm8211/adm8211.c 
b/drivers/net/wireless/d80211/adm8211/adm8211.c
index 4cfddf1..be4a058 100644
--- a/drivers/net/wireless/d80211/adm8211/adm8211.c
+++ b/drivers/net/wireless/d80211/adm8211/adm8211.c
@@ -423,7 +423,6 @@ static void adm8211_interrupt_tci(struct
             priv->cur_tx - dirty_tx > 0; dirty_tx++) {
                unsigned entry = dirty_tx % priv->tx_ring_size;
                u32 status = le32_to_cpu(priv->tx_ring[entry].status);
-               struct sk_buff *skb;
 
                if (status & TDES0_CONTROL_OWN ||
                    !(status & TDES0_CONTROL_DONE))
@@ -438,15 +437,19 @@ static void adm8211_interrupt_tci(struct
                } else
                        priv->tx_buffers[entry].tx_status.ack = 1;
 
-               skb = priv->tx_buffers[entry].skb;
                pci_unmap_single(priv->pdev, priv->tx_buffers[entry].mapping,
-                                skb->len, PCI_DMA_TODEVICE);
+                                priv->tx_buffers[entry].skb->len, 
PCI_DMA_TODEVICE);
 
                if (priv->tx_buffers[entry].tx_status.control.req_tx_status ||
-                   priv->tx_buffers[entry].unicast)
+                   
!is_multicast_ether_addr(ieee80211_get_DA(&priv->tx_buffers[entry].hdr))) {
+                       struct ieee80211_hdr *hdr;
+                       size_t hdrlen = 
ieee80211_get_hdrlen(le16_to_cpu(priv->tx_buffers[entry].hdr.frame_control));
+                       hdr = (struct ieee80211_hdr *) 
skb_pull(priv->tx_buffers[entry].skb,
+                                                               sizeof(struct 
adm8211_tx_hdr) - hdrlen);
+                       memcpy(hdr, &priv->tx_buffers[entry].hdr, hdrlen);
                        ieee80211_tx_status_irqsafe(dev, 
priv->tx_buffers[entry].skb,
                                                    
&priv->tx_buffers[entry].tx_status);
-               else
+               } else
                        dev_kfree_skb_irq(priv->tx_buffers[entry].skb);
                priv->tx_buffers[entry].skb = NULL;
        }
@@ -1527,7 +1530,8 @@ static int adm8211_init_rings(struct net
 {
        struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
        struct adm8211_desc *desc = NULL;
-       struct adm8211_ring_info *info;
+       struct adm8211_rx_ring_info *rx_info;
+       struct adm8211_tx_ring_info *tx_info;
        unsigned int i;
 
        for (i = 0; i < priv->rx_ring_size; i++) {
@@ -1542,26 +1546,26 @@ static int adm8211_init_rings(struct net
 
        for (i = 0; i < priv->rx_ring_size; i++) {
                desc = &priv->rx_ring[i];
-               info = &priv->rx_buffers[i];
+               rx_info = &priv->rx_buffers[i];
 
-               info->skb = dev_alloc_skb(RX_PKT_SIZE);
-               if (info->skb == NULL)
+               rx_info->skb = dev_alloc_skb(RX_PKT_SIZE);
+               if (rx_info->skb == NULL)
                        break;
-               info->mapping = pci_map_single(priv->pdev, info->skb->tail,
-                                              RX_PKT_SIZE,
-                                              PCI_DMA_FROMDEVICE);
-               info->skb->dev = dev;
-               desc->buffer1 = cpu_to_le32(info->mapping);
-               desc->status = cpu_to_le32( RDES0_STATUS_OWN | RDES0_STATUS_SQL 
);
+               rx_info->mapping = pci_map_single(priv->pdev, 
rx_info->skb->tail,
+                                                 RX_PKT_SIZE,
+                                                 PCI_DMA_FROMDEVICE);
+               rx_info->skb->dev = dev;
+               desc->buffer1 = cpu_to_le32(rx_info->mapping);
+               desc->status = cpu_to_le32(RDES0_STATUS_OWN | RDES0_STATUS_SQL);
        }
 
        /* Setup TX ring. TX buffers descriptors will be filled in as needed */
        for (i = 0; i < priv->tx_ring_size; i++) {
                desc = &priv->tx_ring[i];
-               info = &priv->tx_buffers[i];
+               tx_info = &priv->tx_buffers[i];
 
-               info->skb = NULL;
-               info->mapping = 0;
+               tx_info->skb = NULL;
+               tx_info->mapping = 0;
                desc->status = 0;
        }
        desc->length = cpu_to_le32(TDES1_CONTROL_TER);
@@ -1750,7 +1754,8 @@ #define IEEE80211_DUR_DS_SIFS             10
 
 /* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */
 static void adm8211_tx_raw(struct net_device *dev, struct sk_buff *skb,
-                          u16 plcp_signal, struct ieee80211_tx_control 
*control, int unicast)
+                          u16 plcp_signal, struct ieee80211_tx_control 
*control,
+                          struct ieee80211_hdr *hdr)
 {
        struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
        unsigned long flags;
@@ -1780,7 +1785,7 @@ static void adm8211_tx_raw(struct net_de
        priv->tx_buffers[entry].skb = skb;
        priv->tx_buffers[entry].mapping = mapping;
        memcpy(&priv->tx_buffers[entry].tx_status.control, control, 
sizeof(*control));
-       priv->tx_buffers[entry].unicast = unicast;
+       memcpy(&priv->tx_buffers[entry].hdr, hdr, sizeof(*hdr));
        priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping);
 
        if (entry == priv->tx_ring_size - 1)
@@ -1806,14 +1811,12 @@ static int adm8211_tx(struct net_device 
                      struct ieee80211_tx_control *control)
 {
        struct adm8211_tx_hdr *txhdr;
-       struct ieee80211_hdr *hdr;
-       u16 fc_;
-       __le16 fc;
-       u8 dst[ETH_ALEN];
+       u16 fc;
        size_t payload_len, hdrlen;
        int plcp, dur, len;
        int plcp_signal;
        int short_preamble;
+       struct ieee80211_hdr hdr;
 
        if (control->tx_rate < 0) {
                short_preamble = 1;
@@ -1823,14 +1826,11 @@ static int adm8211_tx(struct net_device 
                plcp_signal = control->tx_rate;
        }
 
-       hdr = (struct ieee80211_hdr *)skb->data;
-       fc  = hdr->frame_control;
-       fc_ = le16_to_cpu(fc);
-       memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
+       memcpy(&hdr, skb->data, sizeof(hdr));
 
-       hdrlen = ieee80211_get_hdrlen(fc_);
+       fc = le16_to_cpu(hdr.frame_control) & ~WLAN_FC_ISWEP;
+       hdrlen = ieee80211_get_hdrlen(fc);
        skb_pull(skb, hdrlen);
-       fc_ &= ~WLAN_FC_ISWEP;
        payload_len = skb->len;
 
        if (skb_headroom(skb) < sizeof(struct adm8211_tx_hdr)) {
@@ -1844,13 +1844,13 @@ static int adm8211_tx(struct net_device 
 
        txhdr = (struct adm8211_tx_hdr *) skb_push(skb, sizeof(*txhdr));
        memset(txhdr, 0, sizeof(*txhdr));
-       memcpy(txhdr->da, dst, ETH_ALEN);
+       memcpy(txhdr->da, ieee80211_get_DA(&hdr), ETH_ALEN);
        txhdr->signal = plcp_signal;
        txhdr->frame_body_size = cpu_to_le16(payload_len);
-       txhdr->frame_control = fc;
+       txhdr->frame_control = hdr.frame_control;
 
        len = hdrlen + payload_len + FCS_LEN;
-       if (fc_ & WLAN_FC_ISWEP)
+       if (fc & WLAN_FC_ISWEP)
                len += 8;
 
        txhdr->frag = cpu_to_le16(0x0FFF);
@@ -1869,12 +1869,12 @@ static int adm8211_tx(struct net_device 
        if (control->use_rts_cts)
                txhdr->header_control |= 
cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
 
-       if (fc_ & WLAN_FC_ISWEP)
+       if (fc & WLAN_FC_ISWEP)
                txhdr->header_control |= 
cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);
 
        txhdr->retry_limit = control->retry_limit;
 
-       adm8211_tx_raw(dev, skb, plcp_signal, control, 
!is_multicast_ether_addr(dst));
+       adm8211_tx_raw(dev, skb, plcp_signal, control, &hdr);
 
        return NETDEV_TX_OK;
 }
@@ -1884,12 +1884,12 @@ static int adm8211_alloc_rings(struct ne
        struct adm8211_priv *priv = ieee80211_dev_hw_data(dev);
        unsigned int ring_size;
 
-       priv->rx_buffers = kmalloc(sizeof(struct adm8211_ring_info) *
-                               (priv->rx_ring_size + priv->tx_ring_size), 
GFP_KERNEL);
+       priv->rx_buffers = kmalloc(sizeof(struct adm8211_rx_ring_info) * 
priv->rx_ring_size +
+                                  sizeof(struct adm8211_tx_ring_info) * 
priv->tx_ring_size, GFP_KERNEL);
        if (!priv->rx_buffers)
                return -ENOMEM;
 
-       priv->tx_buffers = ((void *)priv->rx_buffers) + sizeof(struct 
adm8211_ring_info) * priv->tx_ring_size;
+       priv->tx_buffers = ((void *)priv->rx_buffers) + sizeof(struct 
adm8211_rx_ring_info) * priv->rx_ring_size;
 
        /* Allocate TX/RX descriptors */
        ring_size = sizeof(struct adm8211_desc) * priv->rx_ring_size +
@@ -1899,7 +1899,8 @@ static int adm8211_alloc_rings(struct ne
 
        if (!priv->rx_ring) {
                kfree(priv->rx_buffers);
-               priv->rx_buffers = priv->tx_buffers = NULL;
+               priv->rx_buffers = NULL;
+               priv->tx_buffers = NULL;
                return -ENOMEM;
        }
 
diff --git a/drivers/net/wireless/d80211/adm8211/adm8211.h 
b/drivers/net/wireless/d80211/adm8211/adm8211.h
index 13965b4..89e0fdf 100644
--- a/drivers/net/wireless/d80211/adm8211/adm8211.h
+++ b/drivers/net/wireless/d80211/adm8211/adm8211.h
@@ -439,11 +439,16 @@ #define ADM8211_SRAM_A_SIZE      0x0200
 #define ADM8211_SRAM_B_SIZE      0x01c0
 #define ADM8211_SRAM_SIZE ADM8211_SRAM(SIZE)
 
-struct adm8211_ring_info {
+struct adm8211_rx_ring_info {
+       struct sk_buff *skb;
+       dma_addr_t mapping;
+};
+
+struct adm8211_tx_ring_info {
        struct sk_buff *skb;
        dma_addr_t mapping;
        struct ieee80211_tx_status tx_status;
-       int unicast;
+       struct ieee80211_hdr hdr;
 };
 
 struct adm8211_eeprom {
@@ -521,8 +526,8 @@ struct adm8211_priv {
        struct adm8211_desc *tx_ring;
        dma_addr_t rx_ring_dma;
        dma_addr_t tx_ring_dma;
-       struct adm8211_ring_info *rx_buffers;
-       struct adm8211_ring_info *tx_buffers;
+       struct adm8211_rx_ring_info *rx_buffers;
+       struct adm8211_tx_ring_info *tx_buffers;
        unsigned rx_ring_size, tx_ring_size;
        unsigned cur_tx, dirty_tx, cur_rx;
 

Attachment: pgpVxaxRFSwVX.pgp
Description: PGP signature

Reply via email to