pci_unmap_single(priv->pdev, info->mapping,
                                 info->skb->len, PCI_DMA_TODEVICE);
 
-               memset(&txi->status, 0, sizeof(txi->status));
+               ieee80211_tx_info_clear_status(txi);
+
                skb_pull(skb, sizeof(struct adm8211_tx_hdr));
                memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen);
-               if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
-                       if (status & TDES0_STATUS_ES)
-                               txi->status.excessive_retries = 1;
-                       else
-                               txi->flags |= IEEE80211_TX_STAT_ACK;
-               }
+               if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) &&
+                   !(status & TDES0_STATUS_ES))
+                       txi->flags |= IEEE80211_TX_STAT_ACK;
+
                ieee80211_tx_status_irqsafe(dev, skb);
 
                info->skb = NULL;
        struct ieee80211_hdr *hdr;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info);
+       u8 rc_flags;
 
-       short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE);
+       rc_flags = info->control.rates[0].flags;
+       short_preamble = !!(rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
        plcp_signal = txrate->bitrate;
 
        hdr = (struct ieee80211_hdr *)skb->data;
        if (short_preamble)
                txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);
 
-       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+       if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
                txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
 
-       txhdr->retry_limit = info->control.retry_limit;
+       txhdr->retry_limit = info->control.rates[0].count;
 
        adm8211_tx_raw(dev, skb, plcp_signal, hdrlen);
 
 
 
        /* set up multi-rate retry capabilities */
        if (sc->ah->ah_version == AR5K_AR5212) {
-               hw->max_altrates = 3;
-               hw->max_altrate_tries = 11;
+               hw->max_rates = 4;
+               hw->max_rate_tries = 11;
        }
 
        /* Finish private driver data initialization */
                ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
                (sc->power_level * 2),
                ieee80211_get_tx_rate(sc->hw, info)->hw_value,
-               info->control.retry_limit, keyidx, 0, flags, 0, 0);
+               info->control.rates[0].count, keyidx, 0, flags, 0, 0);
        if (ret)
                goto err_unmap;
 
                        break;
 
                mrr_rate[i] = rate->hw_value;
-               mrr_tries[i] = info->control.retries[i].limit;
+               mrr_tries[i] = info->control.rates[i + 1].count;
        }
 
        ah->ah_setup_mrr_tx_desc(ah, ds,
                pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
                                PCI_DMA_TODEVICE);
 
-               memset(&info->status, 0, sizeof(info->status));
-               info->tx_rate_idx = ath5k_hw_to_driver_rix(sc,
-                               ts.ts_rate[ts.ts_final_idx]);
-               info->status.retry_count = ts.ts_longretry;
-
+               ieee80211_tx_info_clear_status(info);
                for (i = 0; i < 4; i++) {
-                       struct ieee80211_tx_altrate *r =
-                               &info->status.retries[i];
+                       struct ieee80211_tx_rate *r =
+                               &info->status.rates[i];
 
                        if (ts.ts_rate[i]) {
-                               r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
-                               r->limit = ts.ts_retry[i];
+                               r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]);
+                               r->count = ts.ts_retry[i];
                        } else {
-                               r->rate_idx = -1;
-                               r->limit = 0;
+                               r->idx = -1;
+                               r->count = 0;
                        }
                }
 
-               info->status.excessive_retries = 0;
+               /* count the successful attempt as well */
+               info->status.rates[ts.ts_final_idx].count++;
+
                if (unlikely(ts.ts_status)) {
                        sc->ll_stats.dot11ACKFailureCount++;
-                       if (ts.ts_status & AR5K_TXERR_XRETRY)
-                               info->status.excessive_retries = 1;
-                       else if (ts.ts_status & AR5K_TXERR_FILT)
+                       if (ts.ts_status & AR5K_TXERR_FILT)
                                info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
                } else {
                        info->flags |= IEEE80211_TX_STAT_ACK;
 
        DPRINTF(sc, ATH_DBG_XMIT,
                "%s: TX complete: skb: %p\n", __func__, skb);
 
+       ieee80211_tx_info_clear_status(tx_info);
        if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
                tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
-               /* free driver's private data area of tx_info */
-               if (tx_info->driver_data[0] != NULL)
-                       kfree(tx_info->driver_data[0]);
-                       tx_info->driver_data[0] = NULL;
+               /* free driver's private data area of tx_info, XXX: HACK! */
+               if (tx_info->control.vif != NULL)
+                       kfree(tx_info->control.vif);
+                       tx_info->control.vif = NULL;
        }
 
        if (tx_status->flags & ATH_TX_BAR) {
                tx_status->flags &= ~ATH_TX_BAR;
        }
 
-       if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) {
-               if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
-                       /* Frame was not ACKed, but an ACK was expected */
-                       tx_info->status.excessive_retries = 1;
-               }
-       } else {
+       if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
                /* Frame was ACKed */
                tx_info->flags |= IEEE80211_TX_STAT_ACK;
        }
 
-       tx_info->status.retry_count = tx_status->retries;
+       tx_info->status.rates[0].count = tx_status->retries + 1;
 
        ieee80211_tx_status(hw, skb);
        if (an)
 
 
        hdr = (struct ieee80211_hdr *)skb->data;
        fc = hdr->frame_control;
-       tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+       /* XXX: UGLY HACK!! */
+       tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
 
        spin_lock_bh(&sc->node_lock);
        an = ath_node_find(sc, hdr->addr1);
        spin_unlock_bh(&sc->node_lock);
 
-       if (!an || !priv_sta || !ieee80211_is_data(fc)) {
-               if (tx_info->driver_data[0] != NULL) {
-                       kfree(tx_info->driver_data[0]);
-                       tx_info->driver_data[0] = NULL;
-               }
+       if (tx_info_priv == NULL)
                return;
-       }
-       if (tx_info->driver_data[0] != NULL) {
+
+       if (an && priv_sta && ieee80211_is_data(fc))
                ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv);
-               kfree(tx_info->driver_data[0]);
-               tx_info->driver_data[0] = NULL;
-       }
+
+       kfree(tx_info_priv);
+       tx_info->control.vif = NULL;
 }
 
 static void ath_tx_aggr_resp(struct ath_softc *sc,
        }
 }
 
-static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
-                        struct ieee80211_sta *sta, void *priv_sta,
-                        struct sk_buff *skb, struct rate_selection *sel)
+static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+                        struct ieee80211_tx_rate_control *txrc)
 {
+       struct ieee80211_supported_band *sband = txrc->sband;
+       struct sk_buff *skb = txrc->skb;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct ath_softc *sc = priv;
        struct ieee80211_hw *hw = sc->hw;
 
        DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
 
-       /* allocate driver private area of tx_info */
-       tx_info->driver_data[0] = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
-       ASSERT(tx_info->driver_data[0] != NULL);
-       tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+       /* allocate driver private area of tx_info, XXX: UGLY HACK! */
+       tx_info->control.vif = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
+       tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
+       ASSERT(tx_info_priv != NULL);
 
        lowest_idx = rate_lowest_index(sband, sta);
        tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10;
        /* lowest rate for management and multicast/broadcast frames */
        if (!ieee80211_is_data(fc) ||
            is_multicast_ether_addr(hdr->addr1) || !sta) {
-               sel->rate_idx = lowest_idx;
+               tx_info->control.rates[0].idx = lowest_idx;
                return;
        }
 
                          tx_info_priv->rcs,
                          &is_probe,
                          false);
+#if 0
        if (is_probe)
                sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate;
+#endif
 
        /* Ratecontrol sometimes returns invalid rate index */
        if (tx_info_priv->rcs[0].rix != 0xff)
        else
                tx_info_priv->rcs[0].rix = ath_rc_priv->prev_data_rix;
 
-       sel->rate_idx = tx_info_priv->rcs[0].rix;
+       tx_info->control.rates[0].idx = tx_info_priv->rcs[0].rix;
 
        /* Check if aggregation has to be enabled for this tid */
 
 
 
        hdr = (struct ieee80211_hdr *)skb->data;
        fc = hdr->frame_control;
-       tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+
+       /* XXX: HACK! */
+       tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
 
        if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
                txctl->use_minrate = 1;
 
        if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
                txctl->flags |= ATH9K_TXDESC_NOACK;
-       if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+
+       if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
                txctl->flags |= ATH9K_TXDESC_RTSENA;
 
        /*
         * Setup for rate calculations.
         */
-       tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+
+       /* XXX: HACK! */
+       tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
        rcs = tx_info_priv->rcs;
 
        if (ieee80211_is_data(fc) && !txctl->use_minrate) {
 
        skb = (struct sk_buff *)bf->bf_mpdu;
        tx_info = IEEE80211_SKB_CB(skb);
-       tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+
+       /* XXX: HACK! */
+       tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
        memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
 
        /* update starting sequence number for subsequent ADDBA request */
                }
                skb = bf->bf_mpdu;
                tx_info = IEEE80211_SKB_CB(skb);
-               tx_info_priv = (struct ath_tx_info_priv *)
-                       tx_info->driver_data[0];
+
+               /* XXX: HACK! */
+               tx_info_priv = (struct ath_tx_info_priv *) tx_info->control.vif;
                if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
                        tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
                if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
 
        skb = (struct sk_buff *)bf->bf_mpdu;
        tx_info = IEEE80211_SKB_CB(skb);
-       tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+       /* XXX: HACK! */
+       tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
        memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
 
        /* Add sub-frame to BAW */
        skb = (struct sk_buff *)bf->bf_mpdu;
        tx_info = IEEE80211_SKB_CB(skb);
        tx_info_priv = (struct ath_tx_info_priv *)
-               tx_info->driver_data[0];
+               tx_info->control.vif; /* XXX: HACK! */
        memcpy(bf->bf_rcs,
                tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0]));
 
 
        bf->bf_flags = txctl->flags;
        bf->bf_keytype = txctl->keytype;
-       tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0];
+       /* XXX: HACK! */
+       tx_info_priv = (struct ath_tx_info_priv *)tx_info->control.vif;
        rcs = tx_info_priv->rcs;
        bf->bf_rcs[0] = rcs[0];
        bf->bf_rcs[1] = rcs[1];
 
 
                        info = IEEE80211_SKB_CB(meta->skb);
 
-                       memset(&info->status, 0, sizeof(info->status));
-
                        /*
                         * Call back to inform the ieee80211 subsystem about
                         * the status of the transmission.
                         */
-                       frame_succeed = b43_fill_txstatus_report(info, status);
+                       frame_succeed = b43_fill_txstatus_report(dev, info, status);
 #ifdef CONFIG_B43_DEBUG
                        if (frame_succeed)
                                ring->nr_succeed_tx_packets++;
 
                BIT(NL80211_IFTYPE_ADHOC);
 
        hw->queues = b43_modparam_qos ? 4 : 1;
-       hw->max_altrates = 1;
+       hw->max_rates = 2;
        SET_IEEE80211_DEV(hw, dev->dev);
        if (is_valid_ether_addr(sprom->et1mac))
                SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
 
        spin_lock(&q->lock); /* IRQs are already disabled. */
 
        info = IEEE80211_SKB_CB(pack->skb);
-       memset(&info->status, 0, sizeof(info->status));
 
-       b43_fill_txstatus_report(info, status);
+       b43_fill_txstatus_report(dev, info, status);
 
        total_len = pack->skb->len + b43_txhdr_size(dev);
        total_len = roundup(total_len, 4);
 
                       u8 *_txhdr,
                       const unsigned char *fragment_data,
                       unsigned int fragment_len,
-                      const struct ieee80211_tx_info *info,
+                      struct ieee80211_tx_info *info,
                       u16 cookie)
 {
        struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr;
        u16 phy_ctl = 0;
        u8 extra_ft = 0;
        struct ieee80211_rate *txrate;
+       struct ieee80211_tx_rate *rates;
 
        memset(txhdr, 0, sizeof(*txhdr));
 
                phy_ctl |= B43_TXH_PHY_ENC_OFDM;
        else
                phy_ctl |= B43_TXH_PHY_ENC_CCK;
-       if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
                phy_ctl |= B43_TXH_PHY_SHORTPRMBL;
 
        switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) {
                B43_WARN_ON(1);
        }
 
+       rates = info->control.rates;
        /* MAC control */
        if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
                mac_ctl |= B43_TXH_MAC_ACK;
                mac_ctl |= B43_TXH_MAC_STMSDU;
        if (phy->type == B43_PHYTYPE_A)
                mac_ctl |= B43_TXH_MAC_5GHZ;
-       if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
+
+       /* Overwrite rates[0].count to make the retry calculation
+        * in the tx status easier. need the actual retry limit to
+        * detect whether the fallback rate was used.
+        */
+       if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+           (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) {
+               rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count;
                mac_ctl |= B43_TXH_MAC_LONGFRAME;
+       } else {
+               rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count;
+       }
 
        /* Generate the RTS or CTS-to-self frame */
-       if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
-           (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
+       if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+           (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
                unsigned int len;
                struct ieee80211_hdr *hdr;
                int rts_rate, rts_rate_fb;
                rts_rate_fb = b43_calc_fallback_rate(rts_rate);
                rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
 
-               if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+               if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
                        struct ieee80211_cts *cts;
 
                        if (b43_is_old_txhdr_format(dev)) {
 /* Fill out the mac80211 TXstatus report based on the b43-specific
  * txstatus report data. This returns a boolean whether the frame was
  * successfully transmitted. */
-bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
+bool b43_fill_txstatus_report(struct b43_wldev *dev,
+                             struct ieee80211_tx_info *report,
                              const struct b43_txstatus *status)
 {
        bool frame_success = 1;
+       int retry_limit;
+
+       /* preserve the confiured retry limit before clearing the status
+        * The xmit function has overwritten the rc's value with the actual
+        * retry limit done by the hardware */
+       retry_limit = report->status.rates[0].count;
+       ieee80211_tx_info_clear_status(report);
 
        if (status->acked) {
                /* The frame was ACKed. */
                if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) {
                        /* ...but we expected an ACK. */
                        frame_success = 0;
-                       report->status.excessive_retries = 1;
                }
        }
        if (status->frame_count == 0) {
                /* The frame was not transmitted at all. */
-               report->status.retry_count = 0;
-       } else
-               report->status.retry_count = status->frame_count - 1;
+               report->status.rates[0].count = 0;
+       } else if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
+               /*
+                * If the short retries (RTS, not data frame) have exceeded
+                * the limit, the hw will not have tried the selected rate,
+                * but will have used the fallback rate instead.
+                * Don't let the rate control count attempts for the selected
+                * rate in this case, otherwise the statistics will be off.
+                */
+               report->status.rates[0].count = 0;
+               report->status.rates[1].count = status->frame_count;
+       } else {
+               if (status->frame_count > retry_limit) {
+                       report->status.rates[0].count = retry_limit;
+                       report->status.rates[1].count = status->frame_count -
+                                       retry_limit;
+
+               } else {
+                       report->status.rates[0].count = status->frame_count;
+                       report->status.rates[1].idx = -1;
+               }
+       }
 
        return frame_success;
 }
 
                       u8 * txhdr,
                       const unsigned char *fragment_data,
                       unsigned int fragment_len,
-                      const struct ieee80211_tx_info *txctl, u16 cookie);
+                      struct ieee80211_tx_info *txctl, u16 cookie);
 
 /* Transmit Status */
 struct b43_txstatus {
 
 void b43_handle_txstatus(struct b43_wldev *dev,
                         const struct b43_txstatus *status);
-bool b43_fill_txstatus_report(struct ieee80211_tx_info *report,
+bool b43_fill_txstatus_report(struct b43_wldev *dev,
+                             struct ieee80211_tx_info *report,
                              const struct b43_txstatus *status);
 
 void b43_tx_suspend(struct b43_wldev *dev);
 
        struct b43legacy_dmaring *ring;
        struct b43legacy_dmadesc_generic *desc;
        struct b43legacy_dmadesc_meta *meta;
+       int retry_limit;
        int slot;
 
        ring = parse_cookie(dev, status->cookie, &slot);
                        struct ieee80211_tx_info *info;
                        BUG_ON(!meta->skb);
                        info = IEEE80211_SKB_CB(meta->skb);
-                       /* Call back to inform the ieee80211 subsystem about the
-                        * status of the transmission.
-                        * Some fields of txstat are already filled in dma_tx().
-                        */
 
-                       memset(&info->status, 0, sizeof(info->status));
+                       /* preserve the confiured retry limit before clearing the status
+                        * The xmit function has overwritten the rc's value with the actual
+                        * retry limit done by the hardware */
+                       retry_limit = info->status.rates[0].count;
+                       ieee80211_tx_info_clear_status(info);
 
-                       if (status->acked) {
+                       if (status->acked)
                                info->flags |= IEEE80211_TX_STAT_ACK;
+
+                       if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
+                               /*
+                                * If the short retries (RTS, not data frame) have exceeded
+                                * the limit, the hw will not have tried the selected rate,
+                                * but will have used the fallback rate instead.
+                                * Don't let the rate control count attempts for the selected
+                                * rate in this case, otherwise the statistics will be off.
+                                */
+                               info->status.rates[0].count = 0;
+                               info->status.rates[1].count = status->frame_count;
                        } else {
-                               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
-                                        info->status.excessive_retries = 1;
+                               if (status->frame_count > retry_limit) {
+                                       info->status.rates[0].count = retry_limit;
+                                       info->status.rates[1].count = status->frame_count -
+                                                       retry_limit;
+
+                               } else {
+                                       info->status.rates[0].count = status->frame_count;
+                                       info->status.rates[1].idx = -1;
+                               }
                        }
-                       if (status->frame_count == 0) {
-                               /* The frame was not transmitted at all. */
-                               info->status.retry_count = 0;
-                       } else
-                               info->status.retry_count = status->frame_count
-                                                          - 1;
+
+                       /* Call back to inform the ieee80211 subsystem about the
+                        * status of the transmission.
+                        * Some fields of txstat are already filled in dma_tx().
+                        */
                        ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb);
                        /* skb is freed by ieee80211_tx_status_irqsafe() */
                        meta->skb = NULL;
 
                BIT(NL80211_IFTYPE_WDS) |
                BIT(NL80211_IFTYPE_ADHOC);
        hw->queues = 1; /* FIXME: hardware has more queues */
-       hw->max_altrates = 1;
+       hw->max_rates = 2;
        SET_IEEE80211_DEV(hw, dev->dev);
        if (is_valid_ether_addr(sprom->et1mac))
                SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac);
 
        struct b43legacy_pioqueue *queue;
        struct b43legacy_pio_txpacket *packet;
        struct ieee80211_tx_info *info;
+       int retry_limit;
 
        queue = parse_cookie(dev, status->cookie, &packet);
        B43legacy_WARN_ON(!queue);
                                sizeof(struct b43legacy_txhdr_fw3));
 
        info = IEEE80211_SKB_CB(packet->skb);
-       memset(&info->status, 0, sizeof(info->status));
+
+       /* preserve the confiured retry limit before clearing the status
+        * The xmit function has overwritten the rc's value with the actual
+        * retry limit done by the hardware */
+       retry_limit = info->status.rates[0].count;
+       ieee80211_tx_info_clear_status(info);
 
        if (status->acked)
                info->flags |= IEEE80211_TX_STAT_ACK;
-       info->status.retry_count = status->frame_count - 1;
+
+       if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
+               /*
+                * If the short retries (RTS, not data frame) have exceeded
+                * the limit, the hw will not have tried the selected rate,
+                * but will have used the fallback rate instead.
+                * Don't let the rate control count attempts for the selected
+                * rate in this case, otherwise the statistics will be off.
+                */
+               info->status.rates[0].count = 0;
+               info->status.rates[1].count = status->frame_count;
+       } else {
+               if (status->frame_count > retry_limit) {
+                       info->status.rates[0].count = retry_limit;
+                       info->status.rates[1].count = status->frame_count -
+                                       retry_limit;
+
+               } else {
+                       info->status.rates[0].count = status->frame_count;
+                       info->status.rates[1].idx = -1;
+               }
+       }
        ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb);
        packet->skb = NULL;
 
 
                               struct b43legacy_txhdr_fw3 *txhdr,
                               const unsigned char *fragment_data,
                               unsigned int fragment_len,
-                              const struct ieee80211_tx_info *info,
+                              struct ieee80211_tx_info *info,
                               u16 cookie)
 {
        const struct ieee80211_hdr *wlhdr;
        u32 mac_ctl = 0;
        u16 phy_ctl = 0;
        struct ieee80211_rate *tx_rate;
+       struct ieee80211_tx_rate *rates;
 
        wlhdr = (const struct ieee80211_hdr *)fragment_data;
 
        /* PHY TX Control word */
        if (rate_ofdm)
                phy_ctl |= B43legacy_TX4_PHY_OFDM;
-       if (dev->short_preamble)
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
                phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
        switch (info->antenna_sel_tx) {
        case 0:
        }
 
        /* MAC control */
+       rates = info->control.rates;
        if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
                mac_ctl |= B43legacy_TX4_MAC_ACK;
        if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
                mac_ctl |= B43legacy_TX4_MAC_STMSDU;
        if (rate_fb_ofdm)
                mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
-       if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
+
+       /* Overwrite rates[0].count to make the retry calculation
+        * in the tx status easier. need the actual retry limit to
+        * detect whether the fallback rate was used.
+        */
+       if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+           (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) {
+               rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count;
                mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
+       } else {
+               rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count;
+       }
 
        /* Generate the RTS or CTS-to-self frame */
-       if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
-           (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
+       if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+           (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) {
                unsigned int len;
                struct ieee80211_hdr *hdr;
                int rts_rate;
                if (rts_rate_fb_ofdm)
                        mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
 
-               if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+               if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
                        ieee80211_ctstoself_get(dev->wl->hw,
                                                info->control.vif,
                                                fragment_data,
                              u8 *txhdr,
                              const unsigned char *fragment_data,
                              unsigned int fragment_len,
-                             const struct ieee80211_tx_info *info,
+                             struct ieee80211_tx_info *info,
                              u16 cookie)
 {
        return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
 
                              u8 *txhdr,
                              const unsigned char *fragment_data,
                              unsigned int fragment_len,
-                             const struct ieee80211_tx_info *info,
+                             struct ieee80211_tx_info *info,
                              u16 cookie);
 
 
 
 }
 
 
-/*
- * get ieee prev rate from rate scale table.
- * for A and B mode we need to overright prev
- * value
- */
-static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate)
-{
-       int next_rate = iwl3945_get_prev_ieee_rate(rate);
-
-       switch (priv->band) {
-       case IEEE80211_BAND_5GHZ:
-               if (rate == IWL_RATE_12M_INDEX)
-                       next_rate = IWL_RATE_9M_INDEX;
-               else if (rate == IWL_RATE_6M_INDEX)
-                       next_rate = IWL_RATE_6M_INDEX;
-               break;
-/* XXX cannot be invoked in current mac80211 so not a regression
-       case MODE_IEEE80211B:
-               if (rate == IWL_RATE_11M_INDEX_TABLE)
-                       next_rate = IWL_RATE_5M_INDEX_TABLE;
-               break;
- */
-       default:
-               break;
-       }
-
-       return next_rate;
-}
 /**
  * rs_tx_status - Update rate control values based on Tx results
  *
                         struct ieee80211_sta *sta, void *priv_sta,
                         struct sk_buff *skb)
 {
-       u8 retries, current_count;
+       u8 retries = 0, current_count;
        int scale_rate_index, first_index, last_index;
        unsigned long flags;
        struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate;
        struct iwl3945_rs_sta *rs_sta = priv_sta;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       int i;
 
        IWL_DEBUG_RATE("enter\n");
 
-       retries = info->status.retry_count;
-       first_index = sband->bitrates[info->tx_rate_idx].hw_value;
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++)
+               retries += info->status.rates[i].count;
+       retries--;
+
+       first_index = sband->bitrates[info->status.rates[0].idx].hw_value;
        if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
                IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index);
                return;
                        last_index = scale_rate_index;
                } else {
                        current_count = priv->retry_rate;
-                       last_index = rs_adjust_next_rate(priv,
+                       last_index = iwl3945_rs_next_rate(priv,
                                                         scale_rate_index);
                }
 
 
                if (retries)
                        scale_rate_index =
-                           rs_adjust_next_rate(priv, scale_rate_index);
+                           iwl3945_rs_next_rate(priv, scale_rate_index);
        }
 
 
  * rate table and must reference the driver allocated rate table
  *
  */
-static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
-                       struct ieee80211_sta *sta, void *priv_sta,
-                       struct sk_buff *skb, struct rate_selection *sel)
+static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
+                       void *priv_sta, struct ieee80211_tx_rate_control *txrc)
 {
+       struct ieee80211_supported_band *sband = txrc->sband;
+       struct sk_buff *skb = txrc->skb;
        u8 low = IWL_RATE_INVALID;
        u8 high = IWL_RATE_INVALID;
        u16 high_low;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        u16 fc, rate_mask;
        struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        IWL_DEBUG_RATE("enter\n");
 
            is_multicast_ether_addr(hdr->addr1) ||
            !sta || !priv_sta) {
                IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
-               sel->rate_idx = rate_lowest_index(sband, sta);
+               info->control.rates[0].idx = rate_lowest_index(sband, sta);
                return;
        }
 
 
        rs_sta->last_txrate_idx = index;
        if (sband->band == IEEE80211_BAND_5GHZ)
-               sel->rate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE;
+               info->control.rates[0].idx = rs_sta->last_txrate_idx -
+                               IWL_FIRST_OFDM_RATE;
        else
-               sel->rate_idx = rs_sta->last_txrate_idx;
+               info->control.rates[0].idx = rs_sta->last_txrate_idx;
 
        IWL_DEBUG_RATE("leave: %d\n", index);
 }
 
 }
 #endif
 
+/*
+ * get ieee prev rate from rate scale table.
+ * for A and B mode we need to overright prev
+ * value
+ */
+int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate)
+{
+       int next_rate = iwl3945_get_prev_ieee_rate(rate);
+
+       switch (priv->band) {
+       case IEEE80211_BAND_5GHZ:
+               if (rate == IWL_RATE_12M_INDEX)
+                       next_rate = IWL_RATE_9M_INDEX;
+               else if (rate == IWL_RATE_6M_INDEX)
+                       next_rate = IWL_RATE_6M_INDEX;
+               break;
+/* XXX cannot be invoked in current mac80211 so not a regression
+       case MODE_IEEE80211B:
+               if (rate == IWL_RATE_11M_INDEX_TABLE)
+                       next_rate = IWL_RATE_5M_INDEX_TABLE;
+               break;
+ */
+       default:
+               break;
+       }
+
+       return next_rate;
+}
+
 
 /**
  * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd
        struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
        u32  status = le32_to_cpu(tx_resp->status);
        int rate_idx;
+       int fail, i;
 
        if ((index >= txq->q.n_bd) || (iwl3945_x2_queue_used(&txq->q, index) == 0)) {
                IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
        }
 
        info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
-       memset(&info->status, 0, sizeof(info->status));
+       ieee80211_tx_info_clear_status(info);
+
+       /* Fill the MRR chain with some info about on-chip retransmissions */
+       rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
+       if (info->band == IEEE80211_BAND_5GHZ)
+               rate_idx -= IWL_FIRST_OFDM_RATE;
+
+       fail = tx_resp->failure_frame;
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               int next = iwl3945_rs_next_rate(priv, rate_idx);
+
+               info->status.rates[i].idx = rate_idx;
+
+               /*
+                * Put remaining into the last count as best approximation
+                * of saying exactly what the hardware would have done...
+                */
+               if ((rate_idx == next) || (i == IEEE80211_TX_MAX_RATES - 1)) {
+                       info->status.rates[i].count = fail;
+                       break;
+               }
+
+               info->status.rates[i].count = priv->retry_rate;
+               fail -= priv->retry_rate;
+               rate_idx = next;
+               if (fail <= 0)
+                       break;
+       }
+       info->status.rates[i].count++; /* add final attempt */
 
-       info->status.retry_count = tx_resp->failure_frame;
        /* tx_status->rts_retry_count = tx_resp->failure_rts; */
        info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ?
                                IEEE80211_TX_STAT_ACK : 0;
                        txq_id, iwl3945_get_tx_fail_reason(status), status,
                        tx_resp->rate, tx_resp->failure_frame);
 
-       rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate);
-       if (info->band == IEEE80211_BAND_5GHZ)
-               rate_idx -= IWL_FIRST_OFDM_RATE;
-       info->tx_rate_idx = rate_idx;
        IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
        iwl3945_tx_queue_reclaim(priv, txq_id, index);
 
 
 extern const struct iwl3945_channel_info *iwl3945_get_channel_info(
        const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel);
 
+extern int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate);
+
 /* Requires full declaration of iwl3945_priv before including */
 #include "iwl-3945-io.h"
 
 
 static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
                        __le32 *tx_flags)
 {
-       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
                *tx_flags |= TX_CMD_FLG_RTS_MSK;
                *tx_flags &= ~TX_CMD_FLG_CTS_MSK;
-       } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+       } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
                *tx_flags &= ~TX_CMD_FLG_RTS_MSK;
                *tx_flags |= TX_CMD_FLG_CTS_MSK;
        }
                                   agg->frame_count, agg->start_idx, idx);
 
                info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
-               info->status.retry_count = tx_resp->failure_frame;
+               info->status.rates[0].count = tx_resp->failure_frame + 1;
                info->flags &= ~IEEE80211_TX_CTL_AMPDU;
                info->flags |= iwl_is_tx_success(status)?
                        IEEE80211_TX_STAT_ACK : 0;
                        iwl_txq_check_empty(priv, sta_id, tid, txq_id);
                }
        } else {
-               info->status.retry_count = tx_resp->failure_frame;
+               info->status.rates[0].count = tx_resp->failure_frame + 1;
                info->flags |=
                        iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
                iwl_hwrate_to_tx_control(priv,
 
 static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
                        __le32 *tx_flags)
 {
-       if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
-           (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
+       if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+           (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
                *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;
        else
                *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;
                                   agg->frame_count, agg->start_idx, idx);
 
                info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
-               info->status.retry_count = tx_resp->failure_frame;
+               info->status.rates[0].count = tx_resp->failure_frame + 1;
                info->flags &= ~IEEE80211_TX_CTL_AMPDU;
                info->flags |= iwl_is_tx_success(status)?
                        IEEE80211_TX_STAT_ACK : 0;
                        iwl_txq_check_empty(priv, sta_id, tid, txq_id);
                }
        } else {
-               info->status.retry_count = tx_resp->failure_frame;
+               info->status.rates[0].count = tx_resp->failure_frame + 1;
                info->flags =
                        iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0;
                iwl_hwrate_to_tx_control(priv,
 
            !(info->flags & IEEE80211_TX_STAT_AMPDU))
                return;
 
-       retries = info->status.retry_count;
+       retries = info->status.rates[0].count - 1;
 
        if (retries > 15)
                retries = 15;
        if (priv->band == IEEE80211_BAND_5GHZ)
                rs_index -= IWL_FIRST_OFDM_RATE;
 
-       if ((info->tx_rate_idx < 0) ||
-           (tbl_type.is_SGI ^
-               !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) ||
-           (tbl_type.is_fat ^
-               !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) ||
-           (tbl_type.is_dup ^
-               !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) ||
-           (tbl_type.ant_type ^ info->antenna_sel_tx) ||
-           (!!(tx_rate & RATE_MCS_HT_MSK) ^
-               !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) ||
-           (!!(tx_rate & RATE_MCS_GF_MSK) ^
-               !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) ||
+       if ((info->status.rates[0].idx < 0) ||
+           (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) ||
+           (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) ||
+           (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) ||
+           (tbl_type.ant_type != info->antenna_sel_tx) ||
+           (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) ||
+           (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) ||
            (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate !=
-            hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) {
+            hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) {
                IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate);
                goto out;
        }
        return;
 }
 
-static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband,
-                       struct ieee80211_sta *sta, void *priv_sta,
-                       struct sk_buff *skb, struct rate_selection *sel)
+static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
+                       struct ieee80211_tx_rate_control *txrc)
 {
 
        int i;
+       struct sk_buff *skb = txrc->skb;
+       struct ieee80211_supported_band *sband = txrc->sband;
        struct iwl_priv *priv = (struct iwl_priv *)priv_r;
        struct ieee80211_conf *conf = &priv->hw->conf;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        __le16 fc;
        struct iwl_lq_sta *lq_sta;
 
        fc = hdr->frame_control;
        if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) ||
            !sta || !priv_sta) {
-               sel->rate_idx = rate_lowest_index(sband, sta);
+               info->control.rates[0].idx = rate_lowest_index(sband, sta);
                return;
        }
 
        }
 
        if ((i < 0) || (i > IWL_RATE_COUNT)) {
-               sel->rate_idx = rate_lowest_index(sband, sta);
+               info->control.rates[0].idx = rate_lowest_index(sband, sta);
                return;
        }
 
        if (sband->band == IEEE80211_BAND_5GHZ)
                i -= IWL_FIRST_OFDM_RATE;
-       sel->rate_idx = i;
+       info->control.rates[0].idx = i;
 }
 
 static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
 
  * translate ucode response to mac80211 tx status control values
  */
 void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
-                                 struct ieee80211_tx_info *control)
+                                 struct ieee80211_tx_info *info)
 {
        int rate_index;
+       struct ieee80211_tx_rate *r = &info->control.rates[0];
 
-       control->antenna_sel_tx =
+       info->antenna_sel_tx =
                ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS);
        if (rate_n_flags & RATE_MCS_HT_MSK)
-               control->flags |= IEEE80211_TX_CTL_OFDM_HT;
+               r->flags |= IEEE80211_TX_RC_MCS;
        if (rate_n_flags & RATE_MCS_GF_MSK)
-               control->flags |= IEEE80211_TX_CTL_GREEN_FIELD;
+               r->flags |= IEEE80211_TX_RC_GREEN_FIELD;
        if (rate_n_flags & RATE_MCS_FAT_MSK)
-               control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH;
+               r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
        if (rate_n_flags & RATE_MCS_DUP_MSK)
-               control->flags |= IEEE80211_TX_CTL_DUP_DATA;
+               r->flags |= IEEE80211_TX_RC_DUP_DATA;
        if (rate_n_flags & RATE_MCS_SGI_MSK)
-               control->flags |= IEEE80211_TX_CTL_SHORT_GI;
+               r->flags |= IEEE80211_TX_RC_SHORT_GI;
        rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags);
-       if (control->band == IEEE80211_BAND_5GHZ)
+       if (info->band == IEEE80211_BAND_5GHZ)
                rate_index -= IWL_FIRST_OFDM_RATE;
-       control->tx_rate_idx = rate_index;
+       r->idx = rate_index;
 }
 EXPORT_SYMBOL(iwl_hwrate_to_tx_control);
 
 
 {
        __le16 fc = hdr->frame_control;
        __le32 tx_flags = cmd->cmd.tx.tx_flags;
+       u8 rc_flags = info->control.rates[0].flags;
 
        cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
        if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
                tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
        }
 
-       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+       if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
                tx_flags |= TX_CMD_FLG_RTS_MSK;
                tx_flags &= ~TX_CMD_FLG_CTS_MSK;
-       } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+       } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
                tx_flags &= ~TX_CMD_FLG_RTS_MSK;
                tx_flags |= TX_CMD_FLG_CTS_MSK;
        }
 
 void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail)
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb);
-       memset(&info->status, 0, sizeof(info->status));
+
+       ieee80211_tx_info_clear_status(info);
        /*
         * Commented out, otherwise we never go beyond 1Mbit/s using mac80211
         * default pid rc algorithm.
         *
         * info->status.retry_count = MRVL_DEFAULT_RETRIES - retrycnt;
         */
-       info->status.excessive_retries = fail ? 1 : 0;
        if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail)
                info->flags |= IEEE80211_TX_STAT_ACK;
        skb_pull(priv->tx_skb, sizeof(struct txpd));
 
        /* TODO: set mactime */
        rx_status.freq = data->channel->center_freq;
        rx_status.band = data->channel->band;
-       rx_status.rate_idx = info->tx_rate_idx;
+       rx_status.rate_idx = info->control.rates[0].idx;
        /* TODO: simulate signal strength (and optional packet drop) */
 
        /* Copy skb to all enabled radios that are on the current frequency */
        if (txi->control.sta)
                hwsim_check_sta_magic(txi->control.sta);
 
-       memset(&txi->status, 0, sizeof(txi->status));
-       if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) {
-               if (ack)
-                       txi->flags |= IEEE80211_TX_STAT_ACK;
-               else
-                       txi->status.excessive_retries = 1;
-       }
+       ieee80211_tx_info_clear_status(txi);
+       if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack)
+               txi->flags |= IEEE80211_TX_STAT_ACK;
        ieee80211_tx_status_irqsafe(hw, skb);
        return NETDEV_TX_OK;
 }
 
        spin_lock_irqsave(&priv->tx_queue.lock, flags);
        while (entry != (struct sk_buff *)&priv->tx_queue) {
                struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
-               range = (void *)info->driver_data;
+               range = (void *)info->rate_driver_data;
                if (range->start_addr == addr) {
                        struct p54_control_hdr *entry_hdr;
                        struct p54_tx_control_allocdata *entry_data;
                                struct memrecord *mr;
 
                                ni = IEEE80211_SKB_CB(entry->next);
-                               mr = (struct memrecord *)ni->driver_data;
+                               mr = (struct memrecord *)ni->rate_driver_data;
                                freed = mr->start_addr - last_addr;
                        } else
                                freed = priv->rx_end - last_addr;
                        __skb_unlink(entry, &priv->tx_queue);
                        spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
 
-                       memset(&info->status, 0, sizeof(info->status));
+                       ieee80211_tx_info_clear_status(info);
                        entry_hdr = (struct p54_control_hdr *) entry->data;
                        entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
                        if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
                        if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
                                if (!(payload->status & 0x01))
                                        info->flags |= IEEE80211_TX_STAT_ACK;
-                               else
-                                       info->status.excessive_retries = 1;
                        }
-                       info->status.retry_count = payload->retries - 1;
+                       info->status.rates[0].count = payload->retries;
                        info->status.ack_signal = p54_rssi_to_dbm(dev,
                                        le16_to_cpu(payload->ack_rssi));
                        skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
        while (left--) {
                u32 hole_size;
                struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
-               struct memrecord *range = (void *)info->driver_data;
+               struct memrecord *range = (void *)info->rate_driver_data;
                hole_size = range->start_addr - last_addr;
                if (!target_skb && hole_size >= len) {
                        target_skb = entry->prev;
                largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
                if (!skb_queue_empty(&priv->tx_queue)) {
                        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb);
-                       struct memrecord *range = (void *)info->driver_data;
+                       struct memrecord *range = (void *)info->rate_driver_data;
                        target_addr = range->end_addr;
                }
        } else
 
        if (skb) {
                struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-               struct memrecord *range = (void *)info->driver_data;
+               struct memrecord *range = (void *)info->rate_driver_data;
                range->start_addr = target_addr;
                range->end_addr = target_addr + len;
                __skb_queue_after(&priv->tx_queue, target_skb, skb);
        size_t padding, len;
        u8 rate;
        u8 cts_rate = 0x20;
+       u8 rc_flags;
 
        current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4];
        if (unlikely(current_queue->len > current_queue->limit))
                hdr->magic1 = cpu_to_le16(0x0010);
        hdr->len = cpu_to_le16(len);
        hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1);
-       hdr->retry1 = hdr->retry2 = info->control.retry_limit;
+       hdr->retry1 = hdr->retry2 = info->control.rates[0].count;
 
        /* TODO: add support for alternate retry TX rates */
        rate = ieee80211_get_tx_rate(dev, info)->hw_value;
-       if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) {
+       rc_flags = info->control.rates[0].flags;
+       if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
                rate |= 0x10;
                cts_rate |= 0x10;
        }
-       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+       if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
                rate |= 0x40;
                cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value;
-       } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+       } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
                rate |= 0x20;
                cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value;
        }
 
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+       struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
        enum data_queue_qid qid = skb_get_queue_mapping(entry->skb);
+       u8 rate_idx, rate_flags;
 
        /*
         * Unmap the skb.
        rt2x00dev->link.qual.tx_failed +=
            test_bit(TXDONE_FAILURE, &txdesc->flags);
 
+       rate_idx = skbdesc->tx_rate_idx;
+       rate_flags = skbdesc->tx_rate_flags;
+
        /*
         * Initialize TX status
         */
        memset(&tx_info->status, 0, sizeof(tx_info->status));
        tx_info->status.ack_signal = 0;
-       tx_info->status.excessive_retries =
-           test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags);
-       tx_info->status.retry_count = txdesc->retry;
+       tx_info->status.rates[0].idx = rate_idx;
+       tx_info->status.rates[0].flags = rate_flags;
+       tx_info->status.rates[0].count = txdesc->retry + 1;
+       tx_info->status.rates[1].idx = -1; /* terminate */
 
        if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
                if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
                        rt2x00dev->low_level_stats.dot11ACKFailureCount++;
        }
 
-       if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+       if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
                if (test_bit(TXDONE_SUCCESS, &txdesc->flags))
                        rt2x00dev->low_level_stats.dot11RTSSuccessCount++;
                else if (test_bit(TXDONE_FAILURE, &txdesc->flags))
 
        unsigned int data_length;
        int retval = 0;
 
-       if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+       if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
                data_length = sizeof(struct ieee80211_cts);
        else
                data_length = sizeof(struct ieee80211_rts);
         */
        memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb));
        rts_info = IEEE80211_SKB_CB(skb);
-       rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS;
-       rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT;
+       rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS;
+       rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT;
        rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS;
 
-       if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+       if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
                rts_info->flags |= IEEE80211_TX_CTL_NO_ACK;
        else
                rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
                data_length += rt2x00crypto_tx_overhead(tx_info);
 #endif /* CONFIG_RT2X00_LIB_CRYPTO */
 
-       if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+       if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
                ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif,
                                        frag_skb->data, data_length, tx_info,
                                        (struct ieee80211_cts *)(skb->data));
         * inside the hardware.
         */
        frame_control = le16_to_cpu(ieee80211hdr->frame_control);
-       if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS |
-                              IEEE80211_TX_CTL_USE_CTS_PROTECT)) &&
+       if ((tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS |
+                                               IEEE80211_TX_RC_USE_CTS_PROTECT)) &&
            !rt2x00dev->ops->hw->set_rts_threshold) {
                if (rt2x00queue_available(queue) <= 1)
                        goto exit_fail;
 
        /*
         * Determine retry information.
         */
-       txdesc->retry_limit = tx_info->control.retry_limit;
-       if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT)
+       txdesc->retry_limit = tx_info->control.rates[0].count - 1;
+       /*
+        * XXX: If at this point we knew whether the HW is going to use
+        *      the RETRY_MODE bit or the retry_limit (currently all
+        *      use the RETRY_MODE bit) we could do something like b43
+        *      does, set the RETRY_MODE bit when the RC algorithm is
+        *      requesting more than the long retry limit.
+        */
+       if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
                __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags);
 
        /*
 
 int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb)
 {
+       struct ieee80211_tx_info *tx_info;
        struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX);
        struct txentry_desc txdesc;
        struct skb_frame_desc *skbdesc;
        unsigned int iv_len = 0;
+       u8 rate_idx, rate_flags;
 
        if (unlikely(rt2x00queue_full(queue)))
                return -EINVAL;
                iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len;
 
        /*
-        * All information is retreived from the skb->cb array,
+        * All information is retrieved from the skb->cb array,
         * now we should claim ownership of the driver part of that
-        * array.
+        * array, preserving the bitrate index and flags.
         */
+       tx_info = IEEE80211_SKB_CB(skb);
+       rate_idx = tx_info->control.rates[0].idx;
+       rate_flags = tx_info->control.rates[0].flags;
        skbdesc = get_skb_frame_desc(entry->skb);
        memset(skbdesc, 0, sizeof(*skbdesc));
        skbdesc->entry = entry;
+       skbdesc->tx_rate_idx = rate_idx;
+       skbdesc->tx_rate_flags = rate_flags;
 
        /*
         * When hardware encryption is supported, and this frame
 
  *
  * @flags: Frame flags, see &enum skb_frame_desc_flags.
  * @desc_len: Length of the frame descriptor.
+ * @tx_rate_idx: the index of the TX rate, used for TX status reporting
+ * @tx_rate_flags: the TX rate flags, used for TX status reporting
  * @desc: Pointer to descriptor part of the frame.
  *     Note that this pointer could point to something outside
  *     of the scope of the skb->data pointer.
  * @entry: The entry to which this sk buffer belongs.
  */
 struct skb_frame_desc {
-       unsigned int flags;
+       u8 flags;
+
+       u8 desc_len;
+       u8 tx_rate_idx;
+       u8 tx_rate_flags;
 
-       unsigned int desc_len;
        void *desc;
 
        __le32 iv;
 
                                 skb->len, PCI_DMA_TODEVICE);
 
                info = IEEE80211_SKB_CB(skb);
-               memset(&info->status, 0, sizeof(info->status));
+               ieee80211_tx_info_clear_status(info);
 
-               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
-                       if (flags & RTL818X_TX_DESC_FLAG_TX_OK)
-                               info->flags |= IEEE80211_TX_STAT_ACK;
-                       else
-                               info->status.excessive_retries = 1;
-               }
-               info->status.retry_count = flags & 0xFF;
+               if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+                   (flags & RTL818X_TX_DESC_FLAG_TX_OK))
+                       info->flags |= IEEE80211_TX_STAT_ACK;
+
+               info->status.rates[0].count = (flags & 0xFF) + 1;
 
                ieee80211_tx_status_irqsafe(dev, skb);
                if (ring->entries - skb_queue_len(&ring->queue) == 2)
        unsigned int idx, prio;
        dma_addr_t mapping;
        u32 tx_flags;
+       u8 rc_flags;
        u16 plcp_len = 0;
        __le16 rts_duration = 0;
 
                tx_flags |= RTL818X_TX_DESC_FLAG_DMA |
                            RTL818X_TX_DESC_FLAG_NO_ENC;
 
-       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+       rc_flags = info->control.rates[0].flags;
+       if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
                tx_flags |= RTL818X_TX_DESC_FLAG_RTS;
                tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
-       } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+       } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
                tx_flags |= RTL818X_TX_DESC_FLAG_CTS;
                tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
        }
 
-       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+       if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS)
                rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len,
                                                      info);
 
        entry->plcp_len = cpu_to_le16(plcp_len);
        entry->tx_buf = cpu_to_le32(mapping);
        entry->frame_len = cpu_to_le32(skb->len);
-       entry->flags2 = info->control.retries[0].rate_idx >= 0 ?
+       entry->flags2 = info->control.rates[1].idx >= 0 ?
                ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0;
-       entry->retry_limit = info->control.retry_limit;
+       entry->retry_limit = info->control.rates[0].count;
        entry->flags = cpu_to_le32(tx_flags);
        __skb_queue_tail(&ring->queue, skb);
        if (ring->entries - skb_queue_len(&ring->queue) < 2)
        priv = dev->priv;
        priv->pdev = pdev;
 
-       dev->max_altrates = 1;
+       dev->max_rates = 2;
        SET_IEEE80211_DEV(dev, &pdev->dev);
        pci_set_drvdata(pdev, dev);
 
 
 {
        struct sk_buff *skb = (struct sk_buff *)urb->context;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct ieee80211_hw *hw = info->driver_data[0];
+       struct ieee80211_hw *hw = info->rate_driver_data[0];
        struct rtl8187_priv *priv = hw->priv;
 
-       usb_free_urb(info->driver_data[1]);
+       usb_free_urb(info->rate_driver_data[1]);
        skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) :
                                          sizeof(struct rtl8187_tx_hdr));
-       memset(&info->status, 0, sizeof(info->status));
+       ieee80211_tx_info_clear_status(info);
        info->flags |= IEEE80211_TX_STAT_ACK;
        ieee80211_tx_status_irqsafe(hw, skb);
 }
        flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24;
        if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control))
                flags |= RTL818X_TX_DESC_FLAG_MOREFRAG;
-       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) {
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
                flags |= RTL818X_TX_DESC_FLAG_RTS;
                flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
                rts_dur = ieee80211_rts_duration(dev, priv->vif,
                                                 skb->len, info);
-       } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) {
+       } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
                flags |= RTL818X_TX_DESC_FLAG_CTS;
                flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19;
        }
                hdr->flags = cpu_to_le32(flags);
                hdr->len = 0;
                hdr->rts_duration = rts_dur;
-               hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
+               hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
                buf = hdr;
 
                ep = 2;
                memset(hdr, 0, sizeof(*hdr));
                hdr->flags = cpu_to_le32(flags);
                hdr->rts_duration = rts_dur;
-               hdr->retry = cpu_to_le32(info->control.retry_limit << 8);
+               hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8);
                hdr->tx_duration =
                        ieee80211_generic_frame_duration(dev, priv->vif,
                                                         skb->len, txrate);
                        ep = epmap[skb_get_queue_mapping(skb)];
        }
 
-       info->driver_data[0] = dev;
-       info->driver_data[1] = urb;
+       info->rate_driver_data[0] = dev;
+       info->rate_driver_data[1] = urb;
 
        usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep),
                          buf, skb->len, rtl8187_tx_cb, skb);
 
  * If no status information has been requested, the skb is freed.
  */
 static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
-                     u32 flags, int ackssi, bool success)
+                     int ackssi, bool success)
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
-       memset(&info->status, 0, sizeof(info->status));
+       ieee80211_tx_info_clear_status(info);
 
-       if (!success)
-               info->status.excessive_retries = 1;
-       info->flags |= flags;
+       if (success)
+               info->flags |= IEEE80211_TX_STAT_ACK;
        info->status.ack_signal = ackssi;
        ieee80211_tx_status_irqsafe(hw, skb);
 }
        if (skb == NULL)
                return;
 
-       tx_status(hw, skb, 0, 0, 0);
+       tx_status(hw, skb, 0, 0);
 }
 
 /**
 void zd_mac_tx_to_dev(struct sk_buff *skb, int error)
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct ieee80211_hw *hw = info->driver_data[0];
+       struct ieee80211_hw *hw = info->rate_driver_data[0];
 
        skb_pull(skb, sizeof(struct zd_ctrlset));
        if (unlikely(error ||
            (info->flags & IEEE80211_TX_CTL_NO_ACK))) {
-               tx_status(hw, skb, 0, 0, !error);
+               tx_status(hw, skb, 0, !error);
        } else {
                struct sk_buff_head *q =
                        &zd_hw_mac(hw)->ack_wait_queue;
 }
 
 static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
-                          struct ieee80211_hdr *header, u32 flags)
+                          struct ieee80211_hdr *header,
+                          struct ieee80211_tx_info *info)
 {
        /*
         * CONTROL TODO:
        cs->control = 0;
 
        /* First fragment */
-       if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
+       if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
                cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
 
        /* Multicast */
        if (ieee80211_is_pspoll(header->frame_control))
                cs->control |= ZD_CS_PS_POLL_FRAME;
 
-       if (flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
                cs->control |= ZD_CS_RTS;
 
-       if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
                cs->control |= ZD_CS_SELF_CTS;
 
        /* FIXME: Management frame? */
        txrate = ieee80211_get_tx_rate(mac->hw, info);
 
        cs->modulation = txrate->hw_value;
-       if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE)
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
                cs->modulation = txrate->hw_value_short;
 
        cs->tx_length = cpu_to_le16(frag_len);
 
-       cs_set_control(mac, cs, hdr, info->flags);
+       cs_set_control(mac, cs, hdr, info);
 
        packet_length = frag_len + sizeof(struct zd_ctrlset) + 10;
        ZD_ASSERT(packet_length <= 0xffff);
        if (r)
                return r;
 
-       info->driver_data[0] = hw;
+       info->rate_driver_data[0] = hw;
 
        r = zd_usb_tx(&mac->chip.usb, skb);
        if (r)
                if (likely(!compare_ether_addr(tx_hdr->addr2, rx_hdr->addr1)))
                {
                        __skb_unlink(skb, q);
-                       tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1);
+                       tx_status(hw, skb, stats->signal, 1);
                        goto out;
                }
        }
 
         * it might be freed by zd_mac_tx_to_dev or mac80211)
         */
        info = IEEE80211_SKB_CB(skb);
-       usb = &zd_hw_mac(info->driver_data[0])->chip.usb;
+       usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb;
        zd_mac_tx_to_dev(skb, urb->status);
        free_tx_urb(usb, urb);
        tx_dec_submitted_urbs(usb);
 
  * These flags are used with the @flags member of &ieee80211_tx_info.
  *
  * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame.
- * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame
- * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g.,
- *     for combined 802.11g / 802.11b networks)
+ * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence
+ *     number to this frame, taking care of not overwriting the fragment
+ *     number and increasing the sequence number only when the
+ *     IEEE80211_TX_CTL_FIRST_FRAGMENT flag is set. mac80211 will properly
+ *     assign sequence numbers to QoS-data frames but cannot do so correctly
+ *     for non-QoS-data and management frames because beacons need them from
+ *     that counter as well and mac80211 cannot guarantee proper sequencing.
+ *     If this flag is set, the driver should instruct the hardware to
+ *     assign a sequence number to the frame or assign one itself. Cf. IEEE
+ *     802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for
+ *     beacons and always be clear for frames without a sequence number field.
  * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack
- * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: TBD
  * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination
  *     station
- * @IEEE80211_TX_CTL_REQUEUE: TBD
  * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame
- * @IEEE80211_TX_CTL_SHORT_PREAMBLE: TBD
- * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the
- *     through set_retry_limit configured long retry value
  * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon
  * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU
- * @IEEE80211_TX_CTL_OFDM_HT: this frame can be sent in HT OFDM rates. number
- *     of streams when this flag is on can be extracted from antenna_sel_tx,
- *     so if 1 antenna is marked use SISO, 2 antennas marked use MIMO, n
- *     antennas marked use MIMO_n.
- * @IEEE80211_TX_CTL_GREEN_FIELD: use green field protection for this frame
- * @IEEE80211_TX_CTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width
- * @IEEE80211_TX_CTL_DUP_DATA: duplicate data frame on both 20 Mhz channels
- * @IEEE80211_TX_CTL_SHORT_GI: send this frame using short guard interval
- * @IEEE80211_TX_CTL_INJECTED: TBD
+ * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211.
  * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted
  *     because the destination STA was in powersave mode.
  * @IEEE80211_TX_STAT_ACK: Frame was acknowledged
  *     is for the whole aggregation.
  * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned,
  *     so consider using block ack request (BAR).
- * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence
- *     number to this frame, taking care of not overwriting the fragment
- *     number and increasing the sequence number only when the
- *     IEEE80211_TX_CTL_FIRST_FRAGMENT flags is set. mac80211 will properly
- *     assign sequence numbers to QoS-data frames but cannot do so correctly
- *     for non-QoS-data and management frames because beacons need them from
- *     that counter as well and mac80211 cannot guarantee proper sequencing.
- *     If this flag is set, the driver should instruct the hardware to
- *     assign a sequence number to the frame or assign one itself. Cf. IEEE
- *     802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for
- *     beacons always be clear for frames without a sequence number field.
+ * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be
+ *     set by rate control algorithms to indicate probe rate, will
+ *     be cleared for fragmented frames (except on the last fragment)
+ * @IEEE80211_TX_CTL_REQUEUE: REMOVE THIS
  */
 enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_REQ_TX_STATUS          = BIT(0),
-       IEEE80211_TX_CTL_USE_RTS_CTS            = BIT(2),
-       IEEE80211_TX_CTL_USE_CTS_PROTECT        = BIT(3),
-       IEEE80211_TX_CTL_NO_ACK                 = BIT(4),
-       IEEE80211_TX_CTL_RATE_CTRL_PROBE        = BIT(5),
-       IEEE80211_TX_CTL_CLEAR_PS_FILT          = BIT(6),
-       IEEE80211_TX_CTL_REQUEUE                = BIT(7),
-       IEEE80211_TX_CTL_FIRST_FRAGMENT         = BIT(8),
-       IEEE80211_TX_CTL_SHORT_PREAMBLE         = BIT(9),
-       IEEE80211_TX_CTL_LONG_RETRY_LIMIT       = BIT(10),
-       IEEE80211_TX_CTL_SEND_AFTER_DTIM        = BIT(12),
-       IEEE80211_TX_CTL_AMPDU                  = BIT(13),
-       IEEE80211_TX_CTL_OFDM_HT                = BIT(14),
-       IEEE80211_TX_CTL_GREEN_FIELD            = BIT(15),
-       IEEE80211_TX_CTL_40_MHZ_WIDTH           = BIT(16),
-       IEEE80211_TX_CTL_DUP_DATA               = BIT(17),
-       IEEE80211_TX_CTL_SHORT_GI               = BIT(18),
-       IEEE80211_TX_CTL_INJECTED               = BIT(19),
-       IEEE80211_TX_STAT_TX_FILTERED           = BIT(20),
-       IEEE80211_TX_STAT_ACK                   = BIT(21),
-       IEEE80211_TX_STAT_AMPDU                 = BIT(22),
-       IEEE80211_TX_STAT_AMPDU_NO_BACK         = BIT(23),
-       IEEE80211_TX_CTL_ASSIGN_SEQ             = BIT(24),
+       IEEE80211_TX_CTL_ASSIGN_SEQ             = BIT(1),
+       IEEE80211_TX_CTL_NO_ACK                 = BIT(2),
+       IEEE80211_TX_CTL_CLEAR_PS_FILT          = BIT(3),
+       IEEE80211_TX_CTL_FIRST_FRAGMENT         = BIT(4),
+       IEEE80211_TX_CTL_SEND_AFTER_DTIM        = BIT(5),
+       IEEE80211_TX_CTL_AMPDU                  = BIT(6),
+       IEEE80211_TX_CTL_INJECTED               = BIT(7),
+       IEEE80211_TX_STAT_TX_FILTERED           = BIT(8),
+       IEEE80211_TX_STAT_ACK                   = BIT(9),
+       IEEE80211_TX_STAT_AMPDU                 = BIT(10),
+       IEEE80211_TX_STAT_AMPDU_NO_BACK         = BIT(11),
+       IEEE80211_TX_CTL_RATE_CTRL_PROBE        = BIT(12),
+
+       /* XXX: remove this */
+       IEEE80211_TX_CTL_REQUEUE                = BIT(13),
 };
 
+enum mac80211_rate_control_flags {
+       IEEE80211_TX_RC_USE_RTS_CTS             = BIT(0),
+       IEEE80211_TX_RC_USE_CTS_PROTECT         = BIT(1),
+       IEEE80211_TX_RC_USE_SHORT_PREAMBLE      = BIT(2),
+
+       /* rate index is an MCS rate number instead of an index */
+       IEEE80211_TX_RC_MCS                     = BIT(3),
+       IEEE80211_TX_RC_GREEN_FIELD             = BIT(4),
+       IEEE80211_TX_RC_40_MHZ_WIDTH            = BIT(5),
+       IEEE80211_TX_RC_DUP_DATA                = BIT(6),
+       IEEE80211_TX_RC_SHORT_GI                = BIT(7),
+};
+
+
+/* there are 40 bytes if you don't need the rateset to be kept */
+#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE 40
 
-#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE \
-       (sizeof(((struct sk_buff *)0)->cb) - 8)
-#define IEEE80211_TX_INFO_DRIVER_DATA_PTRS \
-       (IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *))
+/* if you do need the rateset, then you have less space */
+#define IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE 24
 
-/* maximum number of alternate rate retry stages */
-#define IEEE80211_TX_MAX_ALTRATE       3
+/* maximum number of rate stages */
+#define IEEE80211_TX_MAX_RATES 5
 
 /**
- * struct ieee80211_tx_altrate - alternate rate selection/status
+ * struct ieee80211_tx_rate - rate selection/status
  *
- * @rate_idx: rate index to attempt to send with
+ * @idx: rate index to attempt to send with
+ * @flags: rate control flags (&enum mac80211_rate_control_flags)
  * @limit: number of retries before fallback
+ *
+ * A value of -1 for @idx indicates an invalid rate and, if used
+ * in an array of retry rates, that no more rates should be tried.
+ *
+ * When used for transmit status reporting, the driver should
+ * always report the rate along with the flags it used.
  */
-struct ieee80211_tx_altrate {
-       s8 rate_idx;
-       u8 limit;
+struct ieee80211_tx_rate {
+       s8 idx;
+       u8 count;
+       u8 flags;
 };
 
 /**
  * it may be NULL.
  *
  * @flags: transmit info flags, defined above
- * @band: TBD
- * @tx_rate_idx: TBD
+ * @band: the band to transmit on (use for checking for races)
  * @antenna_sel_tx: antenna to use, 0 for automatic diversity
  * @control: union for control data
  * @status: union for status data
  * @driver_data: array of driver_data pointers
  * @retry_count: number of retries
- * @excessive_retries: set to 1 if the frame was retried many times
- *     but not acknowledged
  * @ampdu_ack_len: number of aggregated frames.
  *     relevant only if IEEE80211_TX_STATUS_AMPDU was set.
  * @ampdu_ack_map: block ack bit map for the aggregation.
        /* common information */
        u32 flags;
        u8 band;
-       s8 tx_rate_idx;
+
        u8 antenna_sel_tx;
 
-       /* 1 byte hole */
+       /* 2 byte hole */
 
        union {
                struct {
+                       union {
+                               /* rate control */
+                               struct {
+                                       struct ieee80211_tx_rate rates[
+                                               IEEE80211_TX_MAX_RATES];
+                                       s8 rts_cts_rate_idx;
+                               };
+                               /* only needed before rate control */
+                               unsigned long jiffies;
+                       };
                        /* NB: vif can be NULL for injected frames */
                        struct ieee80211_vif *vif;
                        struct ieee80211_key_conf *hw_key;
                        struct ieee80211_sta *sta;
-                       unsigned long jiffies;
-                       s8 rts_cts_rate_idx;
-                       u8 retry_limit;
-                       struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE];
                } control;
                struct {
+                       struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
+                       u8 ampdu_ack_len;
                        u64 ampdu_ack_map;
                        int ack_signal;
-                       struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE + 1];
-                       u8 retry_count;
-                       bool excessive_retries;
-                       u8 ampdu_ack_len;
+                       /* 8 bytes free */
                } status;
-               void *driver_data[IEEE80211_TX_INFO_DRIVER_DATA_PTRS];
+               struct {
+                       struct ieee80211_tx_rate driver_rates[
+                               IEEE80211_TX_MAX_RATES];
+                       void *rate_driver_data[
+                               IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE / sizeof(void *)];
+               };
+               void *driver_data[
+                       IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)];
        };
 };
 
        return (struct ieee80211_tx_info *)skb->cb;
 }
 
+/**
+ * ieee80211_tx_info_clear_status - clear TX status
+ *
+ * @info: The &struct ieee80211_tx_info to be cleared.
+ *
+ * When the driver passes an skb back to mac80211, it must report
+ * a number of things in TX status. This function clears everything
+ * in the TX status but the rate control information (it does clear
+ * the count since you need to fill that in anyway).
+ *
+ * NOTE: You can only use this function if you do NOT use
+ *      info->driver_data! Use info->rate_driver_data
+ *      instead if you need only the less space that allows.
+ */
+static inline void
+ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
+{
+       int i;
+
+       BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) !=
+                    offsetof(struct ieee80211_tx_info, control.rates));
+       BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) !=
+                    offsetof(struct ieee80211_tx_info, driver_rates));
+       BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != 8);
+       /* clear the rate counts */
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++)
+               info->status.rates[i].count = 0;
+
+       BUILD_BUG_ON(
+           offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23);
+       memset(&info->status.ampdu_ack_len, 0,
+              sizeof(struct ieee80211_tx_info) -
+              offsetof(struct ieee80211_tx_info, status.ampdu_ack_len));
+}
+
 
 /**
  * enum mac80211_rx_flags - receive flags
  * @sta_data_size: size (in bytes) of the drv_priv data area
  *     within &struct ieee80211_sta.
  *
- * @max_altrates: maximum number of alternate rate retry stages
- * @max_altrate_tries: maximum number of tries for each stage
+ * @max_rates: maximum number of alternate rate retry stages
+ * @max_rate_tries: maximum number of tries for each stage
  */
 struct ieee80211_hw {
        struct ieee80211_conf conf;
        u16 ampdu_queues;
        u16 max_listen_interval;
        s8 max_signal;
-       u8 max_altrates;
-       u8 max_altrate_tries;
+       u8 max_rates;
+       u8 max_rate_tries;
 };
 
 /**
 ieee80211_get_tx_rate(const struct ieee80211_hw *hw,
                      const struct ieee80211_tx_info *c)
 {
-       if (WARN_ON(c->tx_rate_idx < 0))
+       if (WARN_ON(c->control.rates[0].idx < 0))
                return NULL;
-       return &hw->wiphy->bands[c->band]->bitrates[c->tx_rate_idx];
+       return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[0].idx];
 }
 
 static inline struct ieee80211_rate *
 ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
                             const struct ieee80211_tx_info *c, int idx)
 {
-       if (c->control.retries[idx].rate_idx < 0)
+       if (c->control.rates[idx + 1].idx < 0)
                return NULL;
-       return &hw->wiphy->bands[c->band]->bitrates[c->control.retries[idx].rate_idx];
+       return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[idx + 1].idx];
 }
 
 /**
 
 
 /* Rate control API */
+
 /**
- * struct rate_selection - rate information for/from rate control algorithms
- *
- * @rate_idx: selected transmission rate index
- * @nonerp_idx: Non-ERP rate to use instead if ERP cannot be used
- * @probe_idx: rate for probing (or -1)
- * @max_rate_idx: maximum rate index that can be used, this is
- *     input to the algorithm and will be enforced
- */
-struct rate_selection {
-       s8 rate_idx, nonerp_idx, probe_idx, max_rate_idx;
+ * struct ieee80211_tx_rate_control - rate control information for/from RC algo
+ *
+ * @hw: The hardware the algorithm is invoked for.
+ * @sband: The band this frame is being transmitted on.
+ * @bss_conf: the current BSS configuration
+ * @reported_rate: The rate control algorithm can fill this in to indicate
+ *     which rate should be reported to userspace as the current rate and
+ *     used for rate calculations in the mesh network.
+ * @rts: whether RTS will be used for this frame because it is longer than the
+ *     RTS threshold
+ * @short_preamble: whether mac80211 will request short-preamble transmission
+ *     if the selected rate supports it
+ * @max_rate_idx: user-requested maximum rate (not MCS for now)
+ */
+struct ieee80211_tx_rate_control {
+       struct ieee80211_hw *hw;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_bss_conf *bss_conf;
+       struct sk_buff *skb;
+       struct ieee80211_tx_rate reported_rate;
+       bool rts, short_preamble;
+       u8 max_rate_idx;
 };
 
 struct rate_control_ops {
        void (*tx_status)(void *priv, struct ieee80211_supported_band *sband,
                          struct ieee80211_sta *sta, void *priv_sta,
                          struct sk_buff *skb);
-       void (*get_rate)(void *priv, struct ieee80211_supported_band *sband,
-                        struct ieee80211_sta *sta, void *priv_sta,
-                        struct sk_buff *skb,
-                        struct rate_selection *sel);
+       void (*get_rate)(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+                        struct ieee80211_tx_rate_control *txrc);
 
        void (*add_sta_debugfs)(void *priv, void *priv_sta,
                                struct dentry *dir);
 
 #define IEEE80211_TX_FRAGMENTED                BIT(0)
 #define IEEE80211_TX_UNICAST           BIT(1)
 #define IEEE80211_TX_PS_BUFFERED       BIT(2)
-#define IEEE80211_TX_PROBE_LAST_FRAG   BIT(3)
 
 struct ieee80211_tx_data {
        struct sk_buff *skb;
        struct ieee80211_key *key;
 
        struct ieee80211_channel *channel;
-       s8 rate_idx;
-       /* use this rate (if set) for last fragment; rate can
-        * be set to lower rate for the first fragments, e.g.,
-        * when using CTS protection with IEEE 802.11g. */
-       s8 last_frag_rate_idx;
 
        /* Extra fragments (in addition to the first fragment
         * in skb) */
 struct ieee80211_tx_stored_packet {
        struct sk_buff *skb;
        struct sk_buff **extra_frag;
-       s8 last_frag_rate_idx;
        int num_extra_frag;
-       bool last_frag_rate_ctrl_probe;
 };
 
 struct beacon_data {
 
  */
 struct ieee80211_tx_status_rtap_hdr {
        struct ieee80211_radiotap_header hdr;
+       u8 rate;
+       u8 padding_for_rate;
        __le16 tx_flags;
        u8 data_retries;
 } __attribute__ ((packed));
        struct ieee80211_sub_if_data *sdata;
        struct net_device *prev_dev = NULL;
        struct sta_info *sta;
+       int retry_count = -1, i;
+
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               /* the HW cannot have attempted that rate */
+               if (i >= hw->max_rates) {
+                       info->status.rates[i].idx = -1;
+                       info->status.rates[i].count = 0;
+               }
+
+               retry_count += info->status.rates[i].count;
+       }
+       if (retry_count < 0)
+               retry_count = 0;
 
        rcu_read_lock();
 
+       sband = local->hw.wiphy->bands[info->band];
+
        sta = sta_info_get(local, hdr->addr1);
 
        if (sta) {
-               if (info->status.excessive_retries &&
+               if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
                    test_sta_flags(sta, WLAN_STA_PS)) {
                        /*
                         * The STA is in power save mode, so assume
                        rcu_read_unlock();
                        return;
                } else {
-                       if (info->status.excessive_retries)
+                       if (!(info->flags & IEEE80211_TX_STAT_ACK))
                                sta->tx_retry_failed++;
-                       sta->tx_retry_count += info->status.retry_count;
+                       sta->tx_retry_count += retry_count;
                }
 
-               sband = local->hw.wiphy->bands[info->band];
                rate_control_tx_status(local, sband, sta, skb);
        }
 
                        local->dot11TransmittedFrameCount++;
                        if (is_multicast_ether_addr(hdr->addr1))
                                local->dot11MulticastTransmittedFrameCount++;
-                       if (info->status.retry_count > 0)
+                       if (retry_count > 0)
                                local->dot11RetryCount++;
-                       if (info->status.retry_count > 1)
+                       if (retry_count > 1)
                                local->dot11MultipleRetryCount++;
                }
 
        rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
        rthdr->hdr.it_present =
                cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
-                           (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
+                           (1 << IEEE80211_RADIOTAP_DATA_RETRIES) |
+                           (1 << IEEE80211_RADIOTAP_RATE));
 
        if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
            !is_multicast_ether_addr(hdr->addr1))
                rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
 
-       if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) &&
-           (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
+       /*
+        * XXX: Once radiotap gets the bitmap reset thing the vendor
+        *      extensions proposal contains, we can actually report
+        *      the whole set of tries we did.
+        */
+       if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||
+           (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))
                rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
-       else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+       else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
                rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
+       if (info->status.rates[0].idx >= 0 &&
+           !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS))
+               rthdr->rate = sband->bitrates[
+                               info->status.rates[0].idx].bitrate / 5;
 
-       rthdr->data_retries = info->status.retry_count;
+       /* for now report the total retry_count */
+       rthdr->data_retries = retry_count;
 
        /* XXX: is this sufficient for BPF? */
        skb_set_mac_header(skb, 0);
        BUG_ON(!ops->configure_filter);
        local->ops = ops;
 
-       local->hw.queues = 1; /* default */
-
+       /* set up some defaults */
+       local->hw.queues = 1;
+       local->hw.max_rates = 1;
        local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
        local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
        local->hw.conf.long_frame_max_tx_count = 4;
 
 
        if (sta->fail_avg >= 100)
                return MAX_METRIC;
+
+       if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)
+               return MAX_METRIC;
+
        err = (sta->fail_avg << ARITH_SHIFT) / 100;
 
        /* bitrate is in units of 100 Kbps, while we need rate in units of
         * 1Mbps. This will be corrected on tx_time computation.
         */
-       rate = sband->bitrates[sta->last_txrate_idx].bitrate;
+       rate = sband->bitrates[sta->last_tx_rate.idx].bitrate;
        tx_time = (device_constant + 10 * test_frame_len / rate);
        estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err));
        result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ;
 
 }
 
 void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
-                          struct ieee80211_supported_band *sband,
-                          struct sta_info *sta, struct sk_buff *skb,
-                          struct rate_selection *sel)
+                          struct sta_info *sta,
+                          struct ieee80211_tx_rate_control *txrc)
 {
        struct rate_control_ref *ref = sdata->local->rate_ctrl;
        void *priv_sta = NULL;
        struct ieee80211_sta *ista = NULL;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
        int i;
 
-       sel->rate_idx = -1;
-       sel->nonerp_idx = -1;
-       sel->probe_idx = -1;
-       sel->max_rate_idx = sdata->max_ratectrl_rateidx;
-
        if (sta) {
                ista = &sta->sta;
                priv_sta = sta->rate_ctrl_priv;
        }
 
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               info->control.rates[i].idx = -1;
+               info->control.rates[i].flags = 0;
+               info->control.rates[i].count = 1;
+       }
+
        if (sta && sdata->force_unicast_rateidx > -1)
-               sel->rate_idx = sdata->force_unicast_rateidx;
+               info->control.rates[0].idx = sdata->force_unicast_rateidx;
        else
-               ref->ops->get_rate(ref->priv, sband, ista, priv_sta, skb, sel);
-
-       if (sdata->max_ratectrl_rateidx > -1 &&
-           sel->rate_idx > sdata->max_ratectrl_rateidx)
-               sel->rate_idx = sdata->max_ratectrl_rateidx;
-
-       BUG_ON(sel->rate_idx < 0);
-
-       /* Select a non-ERP backup rate. */
-       if (sel->nonerp_idx < 0) {
-               for (i = 0; i < sband->n_bitrates; i++) {
-                       struct ieee80211_rate *rate = &sband->bitrates[i];
-                       if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate)
-                               break;
-
-                       if (rate_supported(ista, sband->band, i) &&
-                           !(rate->flags & IEEE80211_RATE_ERP_G))
-                               sel->nonerp_idx = i;
-               }
+               ref->ops->get_rate(ref->priv, ista, priv_sta, txrc);
+
+       /*
+        * try to enforce the maximum rate the user wanted
+        */
+       if (sdata->max_ratectrl_rateidx > -1)
+               for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+                       if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS)
+                               continue;
+                       info->control.rates[i].idx =
+                               min_t(s8, info->control.rates[i].idx,
+                                     sdata->max_ratectrl_rateidx);
        }
+
+       BUG_ON(info->control.rates[0].idx < 0);
 }
 
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
 
 struct rate_control_ref *rate_control_alloc(const char *name,
                                            struct ieee80211_local *local);
 void rate_control_get_rate(struct ieee80211_sub_if_data *sdata,
-                          struct ieee80211_supported_band *sband,
-                          struct sta_info *sta, struct sk_buff *skb,
-                          struct rate_selection *sel);
+                          struct sta_info *sta,
+                          struct ieee80211_tx_rate_control *txrc);
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
 void rate_control_put(struct rate_control_ref *ref);
 
 
 {
        struct minstrel_sta_info *mi = priv_sta;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct ieee80211_tx_altrate *ar = info->status.retries;
-       struct minstrel_priv *mp = priv;
-       int i, ndx, tries;
-       int success = 0;
+       struct ieee80211_tx_rate *ar = info->status.rates;
+       int i, ndx;
+       int success;
 
-       if (!info->status.excessive_retries)
-               success = 1;
+       success = !!(info->flags & IEEE80211_TX_STAT_ACK);
 
-       if (!mp->has_mrr || (ar[0].rate_idx < 0)) {
-               ndx = rix_to_ndx(mi, info->tx_rate_idx);
-               tries = info->status.retry_count + 1;
-               mi->r[ndx].success += success;
-               mi->r[ndx].attempts += tries;
-               return;
-       }
-
-       for (i = 0; i < 4; i++) {
-               if (ar[i].rate_idx < 0)
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               if (ar[i].idx < 0)
                        break;
 
-               ndx = rix_to_ndx(mi, ar[i].rate_idx);
-               mi->r[ndx].attempts += ar[i].limit + 1;
+               ndx = rix_to_ndx(mi, ar[i].idx);
+               mi->r[ndx].attempts += ar[i].count;
 
-               if ((i != 3) && (ar[i + 1].rate_idx < 0))
+               if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0))
                        mi->r[ndx].success += success;
        }
 
 {
        unsigned int retry = mr->adjusted_retry_count;
 
-       if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
                retry = max(2U, min(mr->retry_count_rtscts, retry));
-       else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)
+       else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
                retry = max(2U, min(mr->retry_count_cts, retry));
        return retry;
 }
 }
 
 void
-minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband,
-                  struct ieee80211_sta *sta, void *priv_sta,
-                  struct sk_buff *skb, struct rate_selection *sel)
+minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
+                 void *priv_sta, struct ieee80211_tx_rate_control *txrc)
 {
+       struct sk_buff *skb = txrc->skb;
+       struct ieee80211_supported_band *sband = txrc->sband;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct minstrel_sta_info *mi = priv_sta;
        struct minstrel_priv *mp = priv;
-       struct ieee80211_tx_altrate *ar = info->control.retries;
+       struct ieee80211_tx_rate *ar = info->control.rates;
        unsigned int ndx, sample_ndx = 0;
        bool mrr;
        bool sample_slower = false;
        int sample_rate;
 
        if (!sta || !mi || use_low_rate(skb)) {
-               sel->rate_idx = rate_lowest_index(sband, sta);
+               ar[0].idx = rate_lowest_index(sband, sta);
+               ar[0].count = mp->max_retry;
                return;
        }
 
-       mrr = mp->has_mrr;
-
-       /* mac80211 does not allow mrr for RTS/CTS */
-       if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
-           (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
-               mrr = false;
+       mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot;
 
        if (time_after(jiffies, mi->stats_update + (mp->update_interval *
                        HZ) / 1000))
                        mi->sample_deferred++;
                }
        }
-       sel->rate_idx = mi->r[ndx].rix;
-       info->control.retry_limit = minstrel_get_retry_count(&mi->r[ndx], info);
+       ar[0].idx = mi->r[ndx].rix;
+       ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info);
 
        if (!mrr) {
-               ar[0].rate_idx = mi->lowest_rix;
-               ar[0].limit = mp->max_retry;
-               ar[1].rate_idx = -1;
+               ar[1].idx = mi->lowest_rix;
+               ar[1].count = mp->max_retry;
                return;
        }
 
        }
        mrr_ndx[1] = mi->max_prob_rate;
        mrr_ndx[2] = 0;
-       for (i = 0; i < 3; i++) {
-               ar[i].rate_idx = mi->r[mrr_ndx[i]].rix;
-               ar[i].limit = mi->r[mrr_ndx[i]].adjusted_retry_count;
+       for (i = 1; i < 4; i++) {
+               ar[i].idx = mi->r[mrr_ndx[i - 1]].rix;
+               ar[i].count = mi->r[mrr_ndx[i - 1]].adjusted_retry_count;
        }
 }
 
        /* maximum time that the hw is allowed to stay in one MRR segment */
        mp->segment_size = 6000;
 
-       if (hw->max_altrate_tries > 0)
-               mp->max_retry = hw->max_altrate_tries;
+       if (hw->max_rate_tries > 0)
+               mp->max_retry = hw->max_rate_tries;
        else
                /* safe default, does not necessarily have to match hw properties */
                mp->max_retry = 7;
 
-       if (hw->max_altrates >= 3)
+       if (hw->max_rates >= 4)
                mp->has_mrr = true;
 
        mp->hw = hw;
 
 union rc_pid_event_data {
        /* RC_PID_EVENT_TX_STATUS */
        struct {
+               u32 flags;
                struct ieee80211_tx_info tx_status;
        };
        /* RC_PID_EVENT_TYPE_RATE_CHANGE */
 
 
        /* Ignore all frames that were sent with a different rate than the rate
         * we currently advise mac80211 to use. */
-       if (info->tx_rate_idx != spinfo->txrate_idx)
+       if (info->status.rates[0].idx != spinfo->txrate_idx)
                return;
 
        spinfo->tx_num_xmit++;
        /* We count frames that totally failed to be transmitted as two bad
         * frames, those that made it out but had some retries as one good and
         * one bad frame. */
-       if (info->status.excessive_retries) {
+       if (!(info->flags & IEEE80211_TX_STAT_ACK)) {
                spinfo->tx_num_failed += 2;
                spinfo->tx_num_xmit++;
-       } else if (info->status.retry_count) {
+       } else if (info->status.rates[0].count) {
                spinfo->tx_num_failed++;
                spinfo->tx_num_xmit++;
        }
 }
 
 static void
-rate_control_pid_get_rate(void *priv, struct ieee80211_supported_band *sband,
-                         struct ieee80211_sta *sta, void *priv_sta,
-                         struct sk_buff *skb,
-                         struct rate_selection *sel)
+rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta,
+                         void *priv_sta,
+                         struct ieee80211_tx_rate_control *txrc)
 {
+       struct sk_buff *skb = txrc->skb;
+       struct ieee80211_supported_band *sband = txrc->sband;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct rc_pid_sta_info *spinfo = priv_sta;
        int rateidx;
        u16 fc;
 
+       if (txrc->rts)
+               info->control.rates[0].count =
+                       txrc->hw->conf.long_frame_max_tx_count;
+       else
+               info->control.rates[0].count =
+                       txrc->hw->conf.short_frame_max_tx_count;
+
        /* Send management frames and broadcast/multicast data using lowest
         * rate. */
        fc = le16_to_cpu(hdr->frame_control);
        if (!sta || !spinfo ||
            (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
            is_multicast_ether_addr(hdr->addr1)) {
-               sel->rate_idx = rate_lowest_index(sband, sta);
+               info->control.rates[0].idx = rate_lowest_index(sband, sta);
                return;
        }
 
        if (rateidx >= sband->n_bitrates)
                rateidx = sband->n_bitrates - 1;
 
-       sel->rate_idx = rateidx;
+       info->control.rates[0].idx = rateidx;
 
 #ifdef CONFIG_MAC80211_DEBUGFS
        rate_control_pid_event_tx_rate(&spinfo->events,
 
 {
        union rc_pid_event_data evd;
 
+       evd.flags = stat->flags;
        memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info));
        rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd);
 }
        switch (ev->type) {
        case RC_PID_EVENT_TYPE_TX_STATUS:
                p += snprintf(pb + p, length - p, "tx_status %u %u",
-                             ev->data.tx_status.status.excessive_retries,
-                             ev->data.tx_status.status.retry_count);
+                             !(ev->data.flags & IEEE80211_TX_STAT_ACK),
+                             ev->data.tx_status.status.rates[0].idx);
                break;
        case RC_PID_EVENT_TYPE_RATE_CHANGE:
                p += snprintf(pb + p, length - p, "rate_change %d %d",
 
  * @tx_packets: number of RX/TX MSDUs
  * @tx_bytes: TBD
  * @tx_fragments: number of transmitted MPDUs
- * @last_txrate_idx: Index of the last used transmit rate
+ * @last_txrate: description of the last used transmit rate
  * @tid_seq: TBD
  * @ampdu_mlme: TBD
  * @timer_to_tid: identity mapping to ID timers
        unsigned long tx_packets;
        unsigned long tx_bytes;
        unsigned long tx_fragments;
-       unsigned int last_txrate_idx;
+       struct ieee80211_tx_rate last_tx_rate;
        u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
 
        /*
 
        struct ieee80211_local *local = tx->local;
        struct ieee80211_supported_band *sband;
        struct ieee80211_hdr *hdr;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
+       /* assume HW handles this */
+       if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
+               return 0;
+
+       /* uh huh? */
+       if (WARN_ON_ONCE(info->control.rates[0].idx < 0))
+               return 0;
 
        sband = local->hw.wiphy->bands[tx->channel->band];
-       txrate = &sband->bitrates[tx->rate_idx];
+       txrate = &sband->bitrates[info->control.rates[0].idx];
 
-       erp = 0;
-       if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
-               erp = txrate->flags & IEEE80211_RATE_ERP_G;
+       erp = txrate->flags & IEEE80211_RATE_ERP_G;
 
        /*
         * data and mgmt (except PS Poll):
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
 {
-       struct rate_selection rsel;
-       struct ieee80211_supported_band *sband;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+       struct ieee80211_hdr *hdr = (void *)tx->skb->data;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_rate *rate;
+       int i, len;
+       bool inval = false, rts = false, short_preamble = false;
+       struct ieee80211_tx_rate_control txrc;
 
-       sband = tx->local->hw.wiphy->bands[tx->channel->band];
+       memset(&txrc, 0, sizeof(txrc));
 
-       if (likely(tx->rate_idx < 0)) {
-               rate_control_get_rate(tx->sdata, sband, tx->sta,
-                                     tx->skb, &rsel);
-               if (tx->sta)
-                       tx->sta->last_txrate_idx = rsel.rate_idx;
-               tx->rate_idx = rsel.rate_idx;
-               if (unlikely(rsel.probe_idx >= 0)) {
-                       info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
-                       tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
-                       info->control.retries[0].rate_idx = tx->rate_idx;
-                       info->control.retries[0].limit = tx->local->hw.max_altrate_tries;
-                       tx->rate_idx = rsel.probe_idx;
-               } else if (info->control.retries[0].limit == 0)
-                       info->control.retries[0].rate_idx = -1;
-
-               if (unlikely(tx->rate_idx < 0))
-                       return TX_DROP;
-       } else
-               info->control.retries[0].rate_idx = -1;
+       sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
-       if (tx->sdata->vif.bss_conf.use_cts_prot &&
-           (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) {
-               tx->last_frag_rate_idx = tx->rate_idx;
-               if (rsel.probe_idx >= 0)
-                       tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG;
-               else
-                       tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG;
-               tx->rate_idx = rsel.nonerp_idx;
-               info->tx_rate_idx = rsel.nonerp_idx;
-               info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
-       } else {
-               tx->last_frag_rate_idx = tx->rate_idx;
-               info->tx_rate_idx = tx->rate_idx;
+       len = min_t(int, tx->skb->len + FCS_LEN,
+                        tx->local->fragmentation_threshold);
+
+       /* set up the tx rate control struct we give the RC algo */
+       txrc.hw = local_to_hw(tx->local);
+       txrc.sband = sband;
+       txrc.bss_conf = &tx->sdata->vif.bss_conf;
+       txrc.skb = tx->skb;
+       txrc.reported_rate.idx = -1;
+       txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx;
+
+       /* set up RTS protection if desired */
+       if (tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD &&
+           len > tx->local->rts_threshold) {
+               txrc.rts = rts = true;
        }
-       info->tx_rate_idx = tx->rate_idx;
 
-       return TX_CONTINUE;
-}
+       /*
+        * Use short preamble if the BSS can handle it, but not for
+        * management frames unless we know the receiver can handle
+        * that -- the management frame might be to a station that
+        * just wants a probe response.
+        */
+       if (tx->sdata->vif.bss_conf.use_short_preamble &&
+           (ieee80211_is_data(hdr->frame_control) ||
+            (tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
+               txrc.short_preamble = short_preamble = true;
 
-static ieee80211_tx_result debug_noinline
-ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
-       struct ieee80211_supported_band *sband;
 
-       sband = tx->local->hw.wiphy->bands[tx->channel->band];
+       rate_control_get_rate(tx->sdata, tx->sta, &txrc);
+
+       if (unlikely(info->control.rates[0].idx < 0))
+               return TX_DROP;
+
+       if (txrc.reported_rate.idx < 0)
+               txrc.reported_rate = info->control.rates[0];
 
        if (tx->sta)
-               info->control.sta = &tx->sta->sta;
+               tx->sta->last_tx_rate = txrc.reported_rate;
 
-       if (!info->control.retry_limit) {
-               if (!is_multicast_ether_addr(hdr->addr1)) {
-                       int len = min_t(int, tx->skb->len + FCS_LEN,
-                                       tx->local->fragmentation_threshold);
-                       if (len > tx->local->rts_threshold
-                           && tx->local->rts_threshold <
-                                               IEEE80211_MAX_RTS_THRESHOLD) {
-                               info->flags |= IEEE80211_TX_CTL_USE_RTS_CTS;
-                               info->flags |=
-                                       IEEE80211_TX_CTL_LONG_RETRY_LIMIT;
-                               info->control.retry_limit =
-                                       tx->local->hw.conf.long_frame_max_tx_count - 1;
-                       } else {
-                               info->control.retry_limit =
-                                       tx->local->hw.conf.short_frame_max_tx_count - 1;
-                       }
-               } else {
-                       info->control.retry_limit = 1;
-               }
-       }
+       if (unlikely(!info->control.rates[0].count))
+               info->control.rates[0].count = 1;
 
-       if (tx->flags & IEEE80211_TX_FRAGMENTED) {
-               /* Do not use multiple retry rates when sending fragmented
-                * frames.
-                * TODO: The last fragment could still use multiple retry
-                * rates. */
-               info->control.retries[0].rate_idx = -1;
+       if (is_multicast_ether_addr(hdr->addr1)) {
+               /*
+                * XXX: verify the rate is in the basic rateset
+                */
+               return TX_CONTINUE;
        }
 
-       /* Use CTS protection for unicast frames sent using extended rates if
-        * there are associated non-ERP stations and RTS/CTS is not configured
-        * for the frame. */
-       if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) &&
-           (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) &&
-           (tx->flags & IEEE80211_TX_UNICAST) &&
-           tx->sdata->vif.bss_conf.use_cts_prot &&
-           !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS))
-               info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT;
-
-       /* Transmit data frames using short preambles if the driver supports
-        * short preambles at the selected rate and short preambles are
-        * available on the network at the current point in time. */
-       if (ieee80211_is_data(hdr->frame_control) &&
-           (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) &&
-           tx->sdata->vif.bss_conf.use_short_preamble &&
-           (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) {
-               info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
+       /*
+        * set up the RTS/CTS rate as the fastest basic rate
+        * that is not faster than the data rate
+        *
+        * XXX: Should this check all retry rates?
+        */
+       if (!(info->control.rates[0].flags & IEEE80211_TX_RC_MCS)) {
+               s8 baserate = 0;
+
+               rate = &sband->bitrates[info->control.rates[0].idx];
+
+               for (i = 0; i < sband->n_bitrates; i++) {
+                       /* must be a basic rate */
+                       if (!(tx->sdata->vif.bss_conf.basic_rates & BIT(i)))
+                               continue;
+                       /* must not be faster than the data rate */
+                       if (sband->bitrates[i].bitrate > rate->bitrate)
+                               continue;
+                       /* maximum */
+                       if (sband->bitrates[baserate].bitrate <
+                            sband->bitrates[i].bitrate)
+                               baserate = i;
+               }
+
+               info->control.rts_cts_rate_idx = baserate;
        }
 
-       if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) ||
-           (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) {
-               struct ieee80211_rate *rate;
-               s8 baserate = -1;
-               int idx;
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               /*
+                * make sure there's no valid rate following
+                * an invalid one, just in case drivers don't
+                * take the API seriously to stop at -1.
+                */
+               if (inval) {
+                       info->control.rates[i].idx = -1;
+                       continue;
+               }
+               if (info->control.rates[i].idx < 0) {
+                       inval = true;
+                       continue;
+               }
 
-               /* Do not use multiple retry rates when using RTS/CTS */
-               info->control.retries[0].rate_idx = -1;
+               /*
+                * For now assume MCS is already set up correctly, this
+                * needs to be fixed.
+                */
+               if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) {
+                       WARN_ON(info->control.rates[i].idx > 76);
+                       continue;
+               }
 
-               /* Use min(data rate, max base rate) as CTS/RTS rate */
-               rate = &sband->bitrates[tx->rate_idx];
+               /* set up RTS protection if desired */
+               if (rts)
+                       info->control.rates[i].flags |=
+                               IEEE80211_TX_RC_USE_RTS_CTS;
 
-               for (idx = 0; idx < sband->n_bitrates; idx++) {
-                       if (sband->bitrates[idx].bitrate > rate->bitrate)
-                               continue;
-                       if (tx->sdata->vif.bss_conf.basic_rates & BIT(idx) &&
-                           (baserate < 0 ||
-                            (sband->bitrates[baserate].bitrate
-                             < sband->bitrates[idx].bitrate)))
-                               baserate = idx;
+               /* RC is busted */
+               if (WARN_ON(info->control.rates[i].idx >=
+                           sband->n_bitrates)) {
+                       info->control.rates[i].idx = -1;
+                       continue;
                }
 
-               if (baserate >= 0)
-                       info->control.rts_cts_rate_idx = baserate;
-               else
-                       info->control.rts_cts_rate_idx = 0;
+               rate = &sband->bitrates[info->control.rates[i].idx];
+
+               /* set up short preamble */
+               if (short_preamble &&
+                   rate->flags & IEEE80211_RATE_SHORT_PREAMBLE)
+                       info->control.rates[i].flags |=
+                               IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
+
+               /* set up G protection */
+               if (!rts && tx->sdata->vif.bss_conf.use_cts_prot &&
+                   rate->flags & IEEE80211_RATE_ERP_G)
+                       info->control.rates[i].flags |=
+                               IEEE80211_TX_RC_USE_CTS_PROTECT;
        }
 
+       return TX_CONTINUE;
+}
+
+static ieee80211_tx_result debug_noinline
+ieee80211_tx_h_misc(struct ieee80211_tx_data *tx)
+{
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+
        if (tx->sta)
                info->control.sta = &tx->sta->sta;
 
        left = payload_len - per_fragm;
        for (i = 0; i < num_fragm - 1; i++) {
                struct ieee80211_hdr *fhdr;
+               struct ieee80211_tx_info *info;
                size_t copylen;
 
                if (left <= 0)
                                      IEEE80211_ENCRYPT_TAILROOM);
                if (!frag)
                        goto fail;
+
                /* Make sure that all fragments use the same priority so
                 * that they end up using the same TX queue */
                frag->priority = first->priority;
+
                skb_reserve(frag, tx->local->tx_headroom +
                                  IEEE80211_ENCRYPT_HEADROOM);
+
+               /* copy TX information */
+               info = IEEE80211_SKB_CB(frag);
+               memcpy(info, first->cb, sizeof(frag->cb));
+
+               /* copy/fill in 802.11 header */
                fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen);
                memcpy(fhdr, first->data, hdrlen);
-               if (i == num_fragm - 2)
-                       fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
                fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
+
+               if (i == num_fragm - 2) {
+                       /* clear MOREFRAGS bit for the last fragment */
+                       fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
+               } else {
+                       /*
+                        * No multi-rate retries for fragmented frames, that
+                        * would completely throw off the NAV at other STAs.
+                        */
+                       info->control.rates[1].idx = -1;
+                       info->control.rates[2].idx = -1;
+                       info->control.rates[3].idx = -1;
+                       info->control.rates[4].idx = -1;
+                       BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5);
+                       info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+               }
+
+               /* copy data */
                copylen = left > per_fragm ? per_fragm : left;
                memcpy(skb_put(frag, copylen), pos, copylen);
-               memcpy(frag->cb, first->cb, sizeof(frag->cb));
+
                skb_copy_queue_mapping(frag, first);
+
                frag->do_not_encrypt = first->do_not_encrypt;
 
                pos += copylen;
                                              tx->extra_frag[0]->len);
 
        for (i = 0; i < tx->num_extra_frag; i++) {
-               if (i + 1 < tx->num_extra_frag) {
+               if (i + 1 < tx->num_extra_frag)
                        next_len = tx->extra_frag[i + 1]->len;
-               } else {
+               else
                        next_len = 0;
-                       tx->rate_idx = tx->last_frag_rate_idx;
-               }
 
                hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data;
                hdr->duration_id = ieee80211_duration(tx, 0, next_len);
                (struct ieee80211_radiotap_header *) skb->data;
        struct ieee80211_supported_band *sband;
        int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        sband = tx->local->hw.wiphy->bands[tx->channel->band];
 
         */
 
        while (!ret) {
-               int i, target_rate;
-
                ret = ieee80211_radiotap_iterator_next(&iterator);
 
                if (ret)
                 * get_unaligned((type *)iterator.this_arg) to dereference
                 * iterator.this_arg for type "type" safely on all arches.
                */
-               case IEEE80211_RADIOTAP_RATE:
-                       /*
-                        * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps
-                        * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps
-                        */
-                       target_rate = (*iterator.this_arg) * 5;
-                       for (i = 0; i < sband->n_bitrates; i++) {
-                               struct ieee80211_rate *r;
-
-                               r = &sband->bitrates[i];
-
-                               if (r->bitrate == target_rate) {
-                                       tx->rate_idx = i;
-                                       break;
-                               }
-                       }
-                       break;
-
-               case IEEE80211_RADIOTAP_ANTENNA:
-                       /*
-                        * radiotap uses 0 for 1st ant, mac80211 is 1 for
-                        * 1st ant
-                        */
-                       info->antenna_sel_tx = (*iterator.this_arg) + 1;
-                       break;
-
-#if 0
-               case IEEE80211_RADIOTAP_DBM_TX_POWER:
-                       control->power_level = *iterator.this_arg;
-                       break;
-#endif
-
                case IEEE80211_RADIOTAP_FLAGS:
                        if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
                                /*
        tx->local = local;
        tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        tx->channel = local->hw.conf.channel;
-       tx->rate_idx = -1;
-       tx->last_frag_rate_idx = -1;
        /*
         * Set this flag (used below to indicate "automatic fragmentation"),
         * it will be cleared/left by radiotap as desired.
                        if (!tx->extra_frag[i])
                                continue;
                        info = IEEE80211_SKB_CB(tx->extra_frag[i]);
-                       info->flags &= ~(IEEE80211_TX_CTL_USE_RTS_CTS |
-                                        IEEE80211_TX_CTL_USE_CTS_PROTECT |
-                                        IEEE80211_TX_CTL_CLEAR_PS_FILT |
+                       info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
                                         IEEE80211_TX_CTL_FIRST_FRAGMENT);
                        if (netif_subqueue_stopped(local->mdev,
                                                   tx->extra_frag[i]))
                                return IEEE80211_TX_FRAG_AGAIN;
-                       if (i == tx->num_extra_frag) {
-                               info->tx_rate_idx = tx->last_frag_rate_idx;
-
-                               if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG)
-                                       info->flags |=
-                                               IEEE80211_TX_CTL_RATE_CTRL_PROBE;
-                               else
-                                       info->flags &=
-                                               ~IEEE80211_TX_CTL_RATE_CTRL_PROBE;
-                       }
 
                        ret = local->ops->tx(local_to_hw(local),
                                            tx->extra_frag[i]);
                store->skb = skb;
                store->extra_frag = tx.extra_frag;
                store->num_extra_frag = tx.num_extra_frag;
-               store->last_frag_rate_idx = tx.last_frag_rate_idx;
-               store->last_frag_rate_ctrl_probe =
-                       !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG);
        }
  out:
        rcu_read_unlock();
                store = &local->pending_packet[i];
                tx.extra_frag = store->extra_frag;
                tx.num_extra_frag = store->num_extra_frag;
-               tx.last_frag_rate_idx = store->last_frag_rate_idx;
                tx.flags = 0;
-               if (store->last_frag_rate_ctrl_probe)
-                       tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG;
                ret = __ieee80211_tx(local, store->skb, &tx);
                if (ret) {
                        if (ret == IEEE80211_TX_FRAG_AGAIN)
        struct ieee80211_sub_if_data *sdata = NULL;
        struct ieee80211_if_ap *ap = NULL;
        struct ieee80211_if_sta *ifsta = NULL;
-       struct rate_selection rsel;
        struct beacon_data *beacon;
        struct ieee80211_supported_band *sband;
        enum ieee80211_band band = local->hw.conf.channel->band;
        skb->do_not_encrypt = 1;
 
        info->band = band;
-       rate_control_get_rate(sdata, sband, NULL, skb, &rsel);
-
-       if (unlikely(rsel.rate_idx < 0)) {
-               if (net_ratelimit()) {
-                       printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
-                              "no rate found\n",
-                              wiphy_name(local->hw.wiphy));
-               }
-               dev_kfree_skb_any(skb);
-               skb = NULL;
-               goto out;
-       }
+       /*
+        * XXX: For now, always use the lowest rate
+        */
+       info->control.rates[0].idx = 0;
+       info->control.rates[0].count = 1;
+       info->control.rates[1].idx = -1;
+       info->control.rates[2].idx = -1;
+       info->control.rates[3].idx = -1;
+       info->control.rates[4].idx = -1;
+       BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5);
 
        info->control.vif = vif;
-       info->tx_rate_idx = rsel.rate_idx;
 
        info->flags |= IEEE80211_TX_CTL_NO_ACK;
        info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
        info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
-       if (sdata->vif.bss_conf.use_short_preamble &&
-           sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE)
-               info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE;
-
-       info->control.retry_limit = 1;
-
-out:
+ out:
        rcu_read_unlock();
        return skb;
 }
 
 
        sta = sta_info_get(local, sdata->u.sta.bssid);
 
-       if (sta && sta->last_txrate_idx < sband->n_bitrates)
-               rate->value = sband->bitrates[sta->last_txrate_idx].bitrate;
+       if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS))
+               rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate;
        else
                rate->value = 0;