zd1211rw-d80211: Use ieee80211_tx_status

This makes zd1211rw-d80211 properly report the TX result of a frame via
ieee80211_tx_status. I'm not sure if we can do much better than this since
the hardware doesn't explicitly report the success/failure of TXed frames 
that require ACKs. We have to guess which ACKs match up with which
frames we're trying to send.

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

 drivers/net/wireless/d80211/zd1211rw/zd_chip.h |    3 +
 drivers/net/wireless/d80211/zd1211rw/zd_mac.c  |   96 ++++++++++++++++++++++++
 drivers/net/wireless/d80211/zd1211rw/zd_mac.h  |    2 +
 drivers/net/wireless/d80211/zd1211rw/zd_usb.c  |    8 --
 4 files changed, 99 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/d80211/zd1211rw/zd_chip.h 
b/drivers/net/wireless/d80211/zd1211rw/zd_chip.h
index 4eaec47..b9c225d 100644
--- a/drivers/net/wireless/d80211/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/d80211/zd1211rw/zd_chip.h
@@ -467,8 +467,9 @@
 #define RX_FILTER_BEACON               (1 <<  8)
 #define RX_FILTER_DISASSOC             (1 << 10)
 #define RX_FILTER_AUTH                 (1 << 11)
+#define RX_FILTER_ACK                  (1 << 29)
 #define AP_RX_FILTER                   0x0400feff
-#define STA_RX_FILTER                  0x0000ffff
+#define STA_RX_FILTER                  0x2000ffff
 
 /* Monitor mode sets filter to 0xfffff */
 
diff --git a/drivers/net/wireless/d80211/zd1211rw/zd_mac.c 
b/drivers/net/wireless/d80211/zd1211rw/zd_mac.c
index a76fa6a..6ee650f 100644
--- a/drivers/net/wireless/d80211/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/d80211/zd1211rw/zd_mac.c
@@ -153,6 +153,7 @@ static int zd_mac_stop(struct ieee80211_
 {
        struct zd_mac *mac = zd_dev_mac(dev);
        struct zd_chip *chip = &mac->chip;
+       struct sk_buff *skb;
 
        /*
         * The order here deliberately is a little different from the open()
@@ -167,6 +168,13 @@ static int zd_mac_stop(struct ieee80211_
        zd_chip_switch_radio_off(chip);
        zd_chip_disable_int(chip);
 
+       while ((skb = skb_dequeue(&mac->tx_queue))) {
+               struct ieee80211_tx_control *control =
+                       *(struct ieee80211_tx_control **)skb->cb;
+               kfree(control);
+               kfree_skb(skb);
+       }
+
        return 0;
 }
 
@@ -312,6 +320,7 @@ static int zd_mac_tx(struct ieee80211_hw
                     struct ieee80211_tx_control *control)
 {
        struct zd_mac *mac = zd_dev_mac(dev);
+       struct ieee80211_tx_control *control_copy;
        int r;
 
        if (skb_headroom(skb) < dev->extra_tx_headroom &&
@@ -325,11 +334,43 @@ static int zd_mac_tx(struct ieee80211_hw
        if (r)
                return r;
 
-       /* FIXME: figure out how to check if the TXed packet was ACKed */
-       kfree_skb(skb);
+       if (control->flags & IEEE80211_TXCTL_NO_ACK) {
+               kfree_skb(skb);
+               return 0;
+       }
+
+       control_copy = kmalloc(sizeof(*control_copy), GFP_ATOMIC);
+       if (control_copy)
+               memcpy(control_copy, control, sizeof(*control_copy));
+
+       *(struct ieee80211_tx_control **)skb->cb = control_copy;
+       skb_pull(skb, sizeof(struct zd_ctrlset));
+       skb_queue_tail(&mac->tx_queue, skb);
        return 0;
 }
 
+void zd_mac_tx_failed(struct ieee80211_hw *dev)
+{
+       struct zd_mac *mac = zd_dev_mac(dev);
+       struct ieee80211_tx_control *control;
+       struct sk_buff *skb;
+
+       skb = skb_dequeue(&mac->tx_queue);
+       if (!skb)
+               return;
+
+       control = *(struct ieee80211_tx_control **)skb->cb;
+       if (control) {
+               struct ieee80211_tx_status status = {{0}};
+               memcpy(&status.control, control, sizeof(status.control));
+               ieee80211_tx_status_irqsafe(dev, skb, &status);
+               kfree(control);
+       } else
+               kfree_skb(skb);
+
+       return;
+}
+
 struct zd_rt_hdr {
        struct ieee80211_radiotap_header rt_hdr;
        u8  rt_flags;
@@ -391,6 +432,52 @@ static int fill_rx_stats(struct ieee8021
        return 0;
 }
 
+static int filter_ack(struct ieee80211_hw *dev, struct ieee80211_hdr *rx_hdr,
+                     struct ieee80211_rx_status *stats)
+{
+       struct zd_mac *mac = zd_dev_mac(dev);
+       u16 fc = le16_to_cpu(rx_hdr->frame_control);
+       struct sk_buff *skb;
+       struct ieee80211_hdr *tx_hdr;
+       struct ieee80211_tx_control *control;
+       struct ieee80211_tx_status status = {{0}};
+
+       if ((fc & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) !=
+           (IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK))
+               return 0;
+
+       spin_lock(&mac->tx_queue.lock);
+
+       skb = skb_peek(&mac->tx_queue);
+       if (!skb) {
+               spin_unlock(&mac->tx_queue.lock);
+               return 1;
+       }
+
+       tx_hdr = (struct ieee80211_hdr *) skb->data;
+
+       if (!memcmp(tx_hdr->addr2, rx_hdr->addr1, ETH_ALEN))
+               skb = __skb_dequeue(&mac->tx_queue);
+       else {
+               spin_unlock(&mac->tx_queue.lock);
+               return 1;
+       }
+
+       spin_unlock(&mac->tx_queue.lock);
+
+       control = *(struct ieee80211_tx_control **)skb->cb;
+       if (control) {
+               memcpy(&status.control, control, sizeof(status.control));
+               status.flags = IEEE80211_TX_STATUS_ACK;
+               status.ack_signal = stats->ssi;
+               ieee80211_tx_status_irqsafe(dev, skb, &status);
+               kfree(control);
+       } else
+               kfree_skb(skb);
+
+       return 1;
+}
+
 int zd_mac_rx(struct ieee80211_hw *dev, const u8 *buffer, unsigned int length)
 {
        int r;
@@ -411,6 +498,10 @@ int zd_mac_rx(struct ieee80211_hw *dev,
                  sizeof(struct rx_status);
        buffer += ZD_PLCP_HEADER_SIZE;
 
+       if (length == (10 /* IEEE80211_1ADDR_LEN */ + FCS_LEN) &&
+           filter_ack(dev, (struct ieee80211_hdr *)buffer, &stats))
+               return 0;
+
        skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
        if (!skb)
                return -ENOMEM;
@@ -523,6 +614,7 @@ struct ieee80211_hw *zd_mac_alloc(struct
        dev->queues = 1;
        dev->extra_tx_headroom = sizeof(struct zd_ctrlset);
 
+       skb_queue_head_init(&mac->tx_queue);
        zd_chip_init(&mac->chip, dev, intf);
        housekeeping_init(mac);
 
diff --git a/drivers/net/wireless/d80211/zd1211rw/zd_mac.h 
b/drivers/net/wireless/d80211/zd1211rw/zd_mac.h
index cccf66c..e2ba410 100644
--- a/drivers/net/wireless/d80211/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/d80211/zd1211rw/zd_mac.h
@@ -135,6 +135,7 @@ struct zd_mac {
        int mode;
        int associated;
        u8 *hwaddr;
+       struct sk_buff_head tx_queue;
        struct ieee80211_channel channels[14];
        struct ieee80211_rate rates[12];
        struct ieee80211_hw_modes modes[2];
@@ -163,6 +164,7 @@ void zd_mac_clear(struct zd_mac *mac);
 int zd_mac_init_hw(struct ieee80211_hw *dev, u8 device_type);
 
 int zd_mac_rx(struct ieee80211_hw *dev, const u8 *buffer, unsigned int length);
+void zd_mac_tx_failed(struct ieee80211_hw *dev);
 
 #ifdef DEBUG
 void zd_dump_rx_status(const struct rx_status *status);
diff --git a/drivers/net/wireless/d80211/zd1211rw/zd_usb.c 
b/drivers/net/wireless/d80211/zd1211rw/zd_usb.c
index 9112820..bacb019 100644
--- a/drivers/net/wireless/d80211/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/d80211/zd1211rw/zd_usb.c
@@ -398,12 +398,6 @@ out:
        spin_unlock(&intr->lock);
 }
 
-static inline void handle_retry_failed_int(struct urb *urb)
-{
-       dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
-}
-
-
 static void int_urb_complete(struct urb *urb)
 {
        int r;
@@ -439,7 +433,7 @@ static void int_urb_complete(struct urb
                handle_regs_int(urb);
                break;
        case USB_INT_ID_RETRY_FAILED:
-               handle_retry_failed_int(urb);
+               zd_mac_tx_failed(zd_usb_to_dev(urb->context));
                break;
        default:
                dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb,

Attachment: pgpxcrdajUMhk.pgp
Description: PGP signature

Reply via email to