mac80211: clean up rate selection
authorMattias Nissler <mattias.nissler@gmx.de>
Thu, 20 Dec 2007 12:50:07 +0000 (13:50 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 22:59:17 +0000 (14:59 -0800)
Move some code out of rc80211_simple since it's probably needed for all rate
selection algorithms, and fix iwlwifi accordingly. While at it, clean up the
rate_control_get_rate() interface.

Signed-off-by: Stefano Brivio <stefano.brivio@polimi.it>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/wireless/iwlwifi/iwl-3945-rs.c
drivers/net/wireless/iwlwifi/iwl-4965-rs.c
net/mac80211/ieee80211.c
net/mac80211/ieee80211_rate.c
net/mac80211/ieee80211_rate.h
net/mac80211/ieee80211_sta.c
net/mac80211/rc80211_simple.c
net/mac80211/tx.c

index c48b1b537d2b412fa5ccbc8cf1f156e911d44908..ea7f459e961ba574a010f2a03d7f3e221bb94ec4 100644 (file)
@@ -562,22 +562,6 @@ static void rs_tx_status(void *priv_rate,
        return;
 }
 
-static struct ieee80211_rate *iwl_get_lowest_rate(struct ieee80211_local
-                                                 *local)
-{
-       struct ieee80211_hw_mode *mode = local->oper_hw_mode;
-       int i;
-
-       for (i = 0; i < mode->num_rates; i++) {
-               struct ieee80211_rate *rate = &mode->rates[i];
-
-               if (rate->flags & IEEE80211_RATE_SUPPORTED)
-                       return rate;
-       }
-
-       return &mode->rates[0];
-}
-
 static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
                                 u8 index, u16 rate_mask, int phymode)
 {
@@ -656,10 +640,9 @@ static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
  * rate table and must reference the driver allocated rate table
  *
  */
-static struct ieee80211_rate *rs_get_rate(void *priv_rate,
-                                         struct net_device *dev,
-                                         struct sk_buff *skb,
-                                         struct rate_control_extra *extra)
+static void rs_get_rate(void *priv_rate, struct net_device *dev,
+                       struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+                       struct rate_selection *sel)
 {
        u8 low = IWL_RATE_INVALID;
        u8 high = IWL_RATE_INVALID;
@@ -676,32 +659,19 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct sta_info *sta;
-       u16 fc, rate_mask;
+       u16 rate_mask;
        struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
        DECLARE_MAC_BUF(mac);
 
        IWL_DEBUG_RATE("enter\n");
 
-       memset(extra, 0, sizeof(*extra));
-
-       fc = le16_to_cpu(hdr->frame_control);
-       if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
-           (is_multicast_ether_addr(hdr->addr1))) {
-               /* Send management frames and broadcast/multicast data using
-                * lowest rate. */
-               /* TODO: this could probably be improved.. */
-               IWL_DEBUG_RATE("leave: lowest rate (not data or is "
-                              "multicast)\n");
-
-               return iwl_get_lowest_rate(local);
-       }
-
        sta = sta_info_get(local, hdr->addr1);
        if (!sta || !sta->rate_ctrl_priv) {
                IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
+               sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
                if (sta)
                        sta_info_put(sta);
-               return NULL;
+               return;
        }
 
        rate_mask = sta->supp_rates;
@@ -846,7 +816,7 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
 
        IWL_DEBUG_RATE("leave: %d\n", index);
 
-       return &priv->ieee_rates[index];
+       sel->rate = &priv->ieee_rates[index];
 }
 
 static struct rate_control_ops rs_ops = {
index 8dc78c0bf1ff26d5cff33c31e8e66399930ce225..62a3b52b327041d96e47cbce4354c20ec8769ff9 100644 (file)
@@ -1693,55 +1693,27 @@ static void rs_initialize_lq(struct iwl_priv *priv,
        return;
 }
 
-static struct ieee80211_rate *rs_get_lowest_rate(struct ieee80211_local
-                                                *local)
-{
-       struct ieee80211_hw_mode *mode = local->oper_hw_mode;
-       int i;
-
-       for (i = 0; i < mode->num_rates; i++) {
-               struct ieee80211_rate *rate = &mode->rates[i];
-
-               if (rate->flags & IEEE80211_RATE_SUPPORTED)
-                       return rate;
-       }
-
-       return &mode->rates[0];
-}
-
-static struct ieee80211_rate *rs_get_rate(void *priv_rate,
-                                              struct net_device *dev,
-                                              struct sk_buff *skb,
-                                              struct rate_control_extra
-                                              *extra)
+static void rs_get_rate(void *priv_rate, struct net_device *dev,
+                       struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+                       struct rate_selection *sel)
 {
 
        int i;
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct sta_info *sta;
-       u16 fc;
        struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
        struct iwl_rate_scale_priv *lq;
 
        IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
 
-       memset(extra, 0, sizeof(*extra));
-
-       fc = le16_to_cpu(hdr->frame_control);
-       if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
-               /* Send management frames and broadcast/multicast data using
-                * lowest rate. */
-               /* TODO: this could probably be improved.. */
-               return rs_get_lowest_rate(local);
-       }
-
        sta = sta_info_get(local, hdr->addr1);
 
        if (!sta || !sta->rate_ctrl_priv) {
+               sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
                if (sta)
                        sta_info_put(sta);
-               return rs_get_lowest_rate(local);
+               return;
        }
 
        lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
@@ -1768,11 +1740,13 @@ static struct ieee80211_rate *rs_get_rate(void *priv_rate,
        }
 
  done:
+       if ((i < 0) || (i > IWL_RATE_COUNT)) {
+               sel->rate = rate_lowest(local, local->oper_hw_mode, sta);
+               return;
+       }
        sta_info_put(sta);
-       if ((i < 0) || (i > IWL_RATE_COUNT))
-               return rs_get_lowest_rate(local);
 
-       return &priv->ieee_rates[i];
+       sel->rate = &priv->ieee_rates[i];
 }
 
 static void *rs_alloc_sta(void *priv, gfp_t gfp)
index d6a97a68a62ea518b4d0f584ca27ddac15c96c2b..5bf7a5bebfc9eb1846ea69b6d15b92d555b29048 100644 (file)
@@ -859,10 +859,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
                        sta_info_put(sta);
                        return;
                }
-       } else {
-               /* FIXME: STUPID to call this with both local and local->mdev */
-               rate_control_tx_status(local, local->mdev, skb, status);
-       }
+       } else
+               rate_control_tx_status(local->mdev, skb, status);
 
        ieee80211_led_tx(local, 0);
 
index c3f2783937419a8c0afae47b302657288d647184..e495b0998b4dfc67bbc4801e883ef05d4ab96a76 100644 (file)
@@ -147,6 +147,53 @@ static void rate_control_release(struct kref *kref)
        kfree(ctrl_ref);
 }
 
+void rate_control_get_rate(struct net_device *dev,
+                          struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+                          struct rate_selection *sel)
+{
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+       struct rate_control_ref *ref = local->rate_ctrl;
+       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct sta_info *sta = sta_info_get(local, hdr->addr1);
+       int i;
+       u16 fc;
+
+       memset(sel, 0, sizeof(struct rate_selection));
+
+       /* Send management frames and broadcast/multicast data using lowest
+        * rate. */
+       fc = le16_to_cpu(hdr->frame_control);
+       if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
+           is_multicast_ether_addr(hdr->addr1))
+               sel->rate = rate_lowest(local, mode, sta);
+
+       /* If a forced rate is in effect, select it. */
+       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
+               sel->rate = &mode->rates[sdata->bss->force_unicast_rateidx];
+
+       /* If we haven't found the rate yet, ask the rate control algo. */
+       if (!sel->rate)
+               ref->ops->get_rate(ref->priv, dev, mode, skb, sel);
+
+       /* Select a non-ERP backup rate. */
+       if (!sel->nonerp) {
+               for (i = 0; i < mode->num_rates - 1; i++) {
+                       struct ieee80211_rate *rate = &mode->rates[i];
+                       if (sel->rate->rate < rate->rate)
+                               break;
+
+                       if (rate_supported(sta, mode, i) &&
+                           !(rate->flags & IEEE80211_RATE_ERP))
+                               sel->nonerp = rate;
+               }
+       }
+
+       if (sta)
+               sta_info_put(sta);
+}
+
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
 {
        kref_get(&ref->kref);
index 23688139ffb3ea399292ce2b6842f55c91371d34..787134bd6abfda751ae6f57d961c6bd597c6a116 100644 (file)
 #include "ieee80211_i.h"
 #include "sta_info.h"
 
-#define RATE_CONTROL_NUM_DOWN 20
-#define RATE_CONTROL_NUM_UP   15
-
-
-struct rate_control_extra {
-       /* values from rate_control_get_rate() to the caller: */
-       struct ieee80211_rate *probe; /* probe with this rate, or NULL for no
-                                      * probing */
+struct rate_selection {
+       /* Selected transmission rate */
+       struct ieee80211_rate *rate;
+       /* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */
        struct ieee80211_rate *nonerp;
-
-       /* parameters from the caller to rate_control_get_rate(): */
-       struct ieee80211_hw_mode *mode;
-       u16 ethertype;
+       /* probe with this rate, or NULL for no probing */
+       struct ieee80211_rate *probe;
 };
 
-
 struct rate_control_ops {
        struct module *module;
        const char *name;
        void (*tx_status)(void *priv, struct net_device *dev,
                          struct sk_buff *skb,
                          struct ieee80211_tx_status *status);
-       struct ieee80211_rate *(*get_rate)(void *priv, struct net_device *dev,
-                                          struct sk_buff *skb,
-                                          struct rate_control_extra *extra);
+       void (*get_rate)(void *priv, struct net_device *dev,
+                        struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+                        struct rate_selection *sel);
        void (*rate_init)(void *priv, void *priv_sta,
                          struct ieee80211_local *local, struct sta_info *sta);
        void (*clear)(void *priv);
@@ -75,25 +68,20 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
  * first available algorithm. */
 struct rate_control_ref *rate_control_alloc(const char *name,
                                            struct ieee80211_local *local);
+void rate_control_get_rate(struct net_device *dev,
+                          struct ieee80211_hw_mode *mode, struct sk_buff *skb,
+                          struct rate_selection *sel);
 struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
 void rate_control_put(struct rate_control_ref *ref);
 
-static inline void rate_control_tx_status(struct ieee80211_local *local,
-                                         struct net_device *dev,
+static inline void rate_control_tx_status(struct net_device *dev,
                                          struct sk_buff *skb,
                                          struct ieee80211_tx_status *status)
 {
+       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
        struct rate_control_ref *ref = local->rate_ctrl;
-       ref->ops->tx_status(ref->priv, dev, skb, status);
-}
 
-
-static inline struct ieee80211_rate *
-rate_control_get_rate(struct ieee80211_local *local, struct net_device *dev,
-                     struct sk_buff *skb, struct rate_control_extra *extra)
-{
-       struct rate_control_ref *ref = local->rate_ctrl;
-       return ref->ops->get_rate(ref->priv, dev, skb, extra);
+       ref->ops->tx_status(ref->priv, dev, skb, status);
 }
 
 
@@ -142,6 +130,37 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
 #endif
 }
 
+static inline int
+rate_supported(struct sta_info *sta, struct ieee80211_hw_mode *mode, int index)
+{
+       return (sta == NULL || sta->supp_rates & BIT(index)) &&
+              (mode->rates[index].flags & IEEE80211_RATE_SUPPORTED);
+}
+
+static inline int
+rate_lowest_index(struct ieee80211_local *local, struct ieee80211_hw_mode *mode,
+                 struct sta_info *sta)
+{
+       int i;
+
+       for (i = 0; i < mode->num_rates; i++) {
+               if (rate_supported(sta, mode, i))
+                       return i;
+       }
+
+       /* warn when we cannot find a rate. */
+       WARN_ON(1);
+
+       return 0;
+}
+
+static inline struct ieee80211_rate *
+rate_lowest(struct ieee80211_local *local, struct ieee80211_hw_mode *mode,
+           struct sta_info *sta)
+{
+       return &mode->rates[rate_lowest_index(local, mode, sta)];
+}
+
 
 /* functions for rate control related to a device */
 int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
index 3c552fed2af51afd53752d9f5565a70d6e5a65d9..3978ad606b5cc437e18b3c4e85f7e2a49b6ae3e9 100644 (file)
@@ -2463,9 +2463,8 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
        struct ieee80211_tx_control control;
-       struct ieee80211_rate *rate;
        struct ieee80211_hw_mode *mode;
-       struct rate_control_extra extra;
+       struct rate_selection ratesel;
        u8 *pos;
        struct ieee80211_sub_if_data *sdata;
 
@@ -2550,18 +2549,16 @@ static int ieee80211_sta_join_ibss(struct net_device *dev,
                }
 
                memset(&control, 0, sizeof(control));
-               memset(&extra, 0, sizeof(extra));
-               extra.mode = local->oper_hw_mode;
-               rate = rate_control_get_rate(local, dev, skb, &extra);
-               if (!rate) {
+               rate_control_get_rate(dev, local->oper_hw_mode, skb, &ratesel);
+               if (!ratesel.rate) {
                        printk(KERN_DEBUG "%s: Failed to determine TX rate "
                               "for IBSS beacon\n", dev->name);
                        break;
                }
                control.tx_rate =
                        ((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) &&
-                       (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-                       rate->val2 : rate->val;
+                       (ratesel.rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
+                       ratesel.rate->val2 : ratesel.rate->val;
                control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
                control.power_level = local->hw.conf.power_level;
                control.flags |= IEEE80211_TXCTL_NO_ACK;
index da72737364e42bb5d8fc68255603befad39bd535..c1c8b76a56af38c9f59960de2b6aa75b4b25f599 100644 (file)
@@ -23,6 +23,8 @@
 /* This is a minimal implementation of TX rate controlling that can be used
  * as the default when no improved mechanisms are available. */
 
+#define RATE_CONTROL_NUM_DOWN 20
+#define RATE_CONTROL_NUM_UP   15
 
 #define RATE_CONTROL_EMERG_DEC 2
 #define RATE_CONTROL_INTERVAL (HZ / 20)
@@ -87,26 +89,6 @@ static void rate_control_rate_dec(struct ieee80211_local *local,
        }
 }
 
-
-static struct ieee80211_rate *
-rate_control_lowest_rate(struct ieee80211_local *local,
-                        struct ieee80211_hw_mode *mode)
-{
-       int i;
-
-       for (i = 0; i < mode->num_rates; i++) {
-               struct ieee80211_rate *rate = &mode->rates[i];
-
-               if (rate->flags & IEEE80211_RATE_SUPPORTED)
-                       return rate;
-       }
-
-       printk(KERN_DEBUG "rate_control_lowest_rate - no supported rates "
-              "found\n");
-       return &mode->rates[0];
-}
-
-
 struct global_rate_control {
        int dummy;
 };
@@ -216,56 +198,32 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
 }
 
 
-static struct ieee80211_rate *
+static void
 rate_control_simple_get_rate(void *priv, struct net_device *dev,
+                            struct ieee80211_hw_mode *mode,
                             struct sk_buff *skb,
-                            struct rate_control_extra *extra)
+                            struct rate_selection *sel)
 {
        struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct ieee80211_sub_if_data *sdata;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct ieee80211_hw_mode *mode = extra->mode;
        struct sta_info *sta;
-       int rateidx, nonerp_idx;
-       u16 fc;
-
-       memset(extra, 0, sizeof(*extra));
-
-       fc = le16_to_cpu(hdr->frame_control);
-       if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
-           (hdr->addr1[0] & 0x01)) {
-               /* Send management frames and broadcast/multicast data using
-                * lowest rate. */
-               /* TODO: this could probably be improved.. */
-               return rate_control_lowest_rate(local, mode);
-       }
+       int rateidx;
 
        sta = sta_info_get(local, hdr->addr1);
 
-       if (!sta)
-               return rate_control_lowest_rate(local, mode);
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
-               sta->txrate = sdata->bss->force_unicast_rateidx;
+       if (!sta) {
+               sel->rate = rate_lowest(local, mode, NULL);
+               return;
+       }
 
        rateidx = sta->txrate;
 
        if (rateidx >= mode->num_rates)
                rateidx = mode->num_rates - 1;
 
-       sta->last_txrate = rateidx;
-       nonerp_idx = rateidx;
-       while (nonerp_idx > 0 &&
-              ((mode->rates[nonerp_idx].flags & IEEE80211_RATE_ERP) ||
-               !(mode->rates[nonerp_idx].flags & IEEE80211_RATE_SUPPORTED) ||
-               !(sta->supp_rates & BIT(nonerp_idx))))
-               nonerp_idx--;
-       extra->nonerp = &mode->rates[nonerp_idx];
-
        sta_info_put(sta);
 
-       return &mode->rates[rateidx];
+       sel->rate = &mode->rates[rateidx];
 }
 
 
index 12c15588af6868f82132ff2bb5918d6f75ca6694..4655e303865842c47dab78c1a4408fdc8fa395b1 100644 (file)
@@ -569,21 +569,17 @@ ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx)
 static ieee80211_txrx_result
 ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx)
 {
-       struct rate_control_extra extra;
+       struct rate_selection rsel;
 
        if (likely(!tx->u.tx.rate)) {
-               memset(&extra, 0, sizeof(extra));
-               extra.mode = tx->u.tx.mode;
-               extra.ethertype = tx->ethertype;
-
-               tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev,
-                                                     tx->skb, &extra);
-               if (unlikely(extra.probe != NULL)) {
+               rate_control_get_rate(tx->dev, tx->u.tx.mode, tx->skb, &rsel);
+               tx->u.tx.rate = rsel.rate;
+               if (unlikely(rsel.probe != NULL)) {
                        tx->u.tx.control->flags |=
                                IEEE80211_TXCTL_RATE_CTRL_PROBE;
                        tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
                        tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val;
-                       tx->u.tx.rate = extra.probe;
+                       tx->u.tx.rate = rsel.probe;
                } else
                        tx->u.tx.control->alt_retry_rate = -1;
 
@@ -594,14 +590,14 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx)
 
        if (tx->u.tx.mode->mode == MODE_IEEE80211G &&
            (tx->sdata->flags & IEEE80211_SDATA_USE_PROTECTION) &&
-           (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && extra.nonerp) {
+           (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && rsel.nonerp) {
                tx->u.tx.last_frag_rate = tx->u.tx.rate;
-               if (extra.probe)
+               if (rsel.probe)
                        tx->flags &= ~IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
                else
                        tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG;
-               tx->u.tx.rate = extra.nonerp;
-               tx->u.tx.control->rate = extra.nonerp;
+               tx->u.tx.rate = rsel.nonerp;
+               tx->u.tx.control->rate = rsel.nonerp;
                tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
        } else {
                tx->u.tx.last_frag_rate = tx->u.tx.rate;
@@ -1667,8 +1663,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
        struct net_device *bdev;
        struct ieee80211_sub_if_data *sdata = NULL;
        struct ieee80211_if_ap *ap = NULL;
-       struct ieee80211_rate *rate;
-       struct rate_control_extra extra;
+       struct rate_selection rsel;
        u8 *b_head, *b_tail;
        int bh_len, bt_len;
 
@@ -1712,14 +1707,13 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
        }
 
        if (control) {
-               memset(&extra, 0, sizeof(extra));
-               extra.mode = local->oper_hw_mode;
-
-               rate = rate_control_get_rate(local, local->mdev, skb, &extra);
-               if (!rate) {
+               rate_control_get_rate(local->mdev, local->oper_hw_mode, skb,
+                                     &rsel);
+               if (!rsel.rate) {
                        if (net_ratelimit()) {
-                               printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate "
-                                      "found\n", wiphy_name(local->hw.wiphy));
+                               printk(KERN_DEBUG "%s: ieee80211_beacon_get: "
+                                      "no rate found\n",
+                                      wiphy_name(local->hw.wiphy));
                        }
                        dev_kfree_skb(skb);
                        return NULL;
@@ -1727,8 +1721,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
 
                control->tx_rate =
                        ((sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE) &&
-                       (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-                       rate->val2 : rate->val;
+                       (rsel.rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
+                       rsel.rate->val2 : rsel.rate->val;
                control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
                control->power_level = local->hw.conf.power_level;
                control->flags |= IEEE80211_TXCTL_NO_ACK;