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,
pgpxcrdajUMhk.pgp
Description: PGP signature