]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/mac80211/mlme.c
mac80211: select and adjust bitrates according to channel mode
[karo-tx-linux.git] / net / mac80211 / mlme.c
index ae31968d42d3b855eebe05dcf0e660b4d367ff8f..f7552c2b74ebe0b35840595b277d1e5d0165b2d6 100644 (file)
@@ -478,27 +478,6 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
 
 /* frame sending functions */
 
-static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
-                                     struct ieee80211_supported_band *sband,
-                                     u32 *rates)
-{
-       int i, j, count;
-       *rates = 0;
-       count = 0;
-       for (i = 0; i < supp_rates_len; i++) {
-               int rate = (supp_rates[i] & 0x7F) * 5;
-
-               for (j = 0; j < sband->n_bitrates; j++)
-                       if (sband->bitrates[j].bitrate == rate) {
-                               *rates |= BIT(j);
-                               count++;
-                               break;
-                       }
-       }
-
-       return count;
-}
-
 static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
                                struct sk_buff *skb, u8 ap_ht_param,
                                struct ieee80211_supported_band *sband,
@@ -617,12 +596,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_mgmt *mgmt;
        u8 *pos, qos_info;
        size_t offset = 0, noffset;
-       int i, count, rates_len, supp_rates_len;
+       int i, count, rates_len, supp_rates_len, shift;
        u16 capab;
        struct ieee80211_supported_band *sband;
        struct ieee80211_chanctx_conf *chanctx_conf;
        struct ieee80211_channel *chan;
-       u32 rates = 0;
+       u32 rate_flags, rates = 0;
 
        sdata_assert_lock(sdata);
 
@@ -633,8 +612,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                return;
        }
        chan = chanctx_conf->def.chan;
+       rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
        rcu_read_unlock();
        sband = local->hw.wiphy->bands[chan->band];
+       shift = ieee80211_vif_get_shift(&sdata->vif);
 
        if (assoc_data->supp_rates_len) {
                /*
@@ -643,17 +624,24 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                 * in the association request (e.g. D-Link DAP 1353 in
                 * b-only mode)...
                 */
-               rates_len = ieee80211_compatible_rates(assoc_data->supp_rates,
-                                                      assoc_data->supp_rates_len,
-                                                      sband, &rates);
+               rates_len = ieee80211_parse_bitrates(&chanctx_conf->def, sband,
+                                                    assoc_data->supp_rates,
+                                                    assoc_data->supp_rates_len,
+                                                    &rates);
        } else {
                /*
                 * In case AP not provide any supported rates information
                 * before association, we send information element(s) with
                 * all rates that we support.
                 */
-               rates = ~0;
-               rates_len = sband->n_bitrates;
+               rates_len = 0;
+               for (i = 0; i < sband->n_bitrates; i++) {
+                       if ((rate_flags & sband->bitrates[i].flags)
+                           != rate_flags)
+                               continue;
+                       rates |= BIT(i);
+                       rates_len++;
+               }
        }
 
        skb = alloc_skb(local->hw.extra_tx_headroom +
@@ -730,8 +718,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
        count = 0;
        for (i = 0; i < sband->n_bitrates; i++) {
                if (BIT(i) & rates) {
-                       int rate = sband->bitrates[i].bitrate;
-                       *pos++ = (u8) (rate / 5);
+                       int rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
+                                               5 * (1 << shift));
+                       *pos++ = (u8) rate;
                        if (++count == 8)
                                break;
                }
@@ -744,8 +733,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 
                for (i++; i < sband->n_bitrates; i++) {
                        if (BIT(i) & rates) {
-                               int rate = sband->bitrates[i].bitrate;
-                               *pos++ = (u8) (rate / 5);
+                               int rate;
+                               rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
+                                                   5 * (1 << shift));
+                               *pos++ = (u8) rate;
                        }
                }
        }
@@ -2432,15 +2423,16 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
                                u8 *supp_rates, unsigned int supp_rates_len,
                                u32 *rates, u32 *basic_rates,
                                bool *have_higher_than_11mbit,
-                               int *min_rate, int *min_rate_index)
+                               int *min_rate, int *min_rate_index,
+                               int shift, u32 rate_flags)
 {
        int i, j;
 
        for (i = 0; i < supp_rates_len; i++) {
-               int rate = (supp_rates[i] & 0x7f) * 5;
+               int rate = supp_rates[i] & 0x7f;
                bool is_basic = !!(supp_rates[i] & 0x80);
 
-               if (rate > 110)
+               if ((rate * 5 * (1 << shift)) > 110)
                        *have_higher_than_11mbit = true;
 
                /*
@@ -2456,12 +2448,20 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
                        continue;
 
                for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].bitrate == rate) {
+                       struct ieee80211_rate *br;
+                       int brate;
+
+                       br = &sband->bitrates[j];
+                       if ((rate_flags & br->flags) != rate_flags)
+                               continue;
+
+                       brate = DIV_ROUND_UP(br->bitrate, (1 << shift) * 5);
+                       if (brate == rate) {
                                *rates |= BIT(j);
                                if (is_basic)
                                        *basic_rates |= BIT(j);
-                               if (rate < *min_rate) {
-                                       *min_rate = rate;
+                               if ((rate * 5) < *min_rate) {
+                                       *min_rate = rate * 5;
                                        *min_rate_index = j;
                                }
                                break;
@@ -3884,27 +3884,40 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
                if (!new_sta)
                        return -ENOMEM;
        }
-
        if (new_sta) {
                u32 rates = 0, basic_rates = 0;
                bool have_higher_than_11mbit;
                int min_rate = INT_MAX, min_rate_index = -1;
+               struct ieee80211_chanctx_conf *chanctx_conf;
                struct ieee80211_supported_band *sband;
                const struct cfg80211_bss_ies *ies;
+               int shift;
+               u32 rate_flags;
 
                sband = local->hw.wiphy->bands[cbss->channel->band];
 
                err = ieee80211_prep_channel(sdata, cbss);
                if (err) {
                        sta_info_free(local, new_sta);
-                       return err;
+                       return -EINVAL;
                }
+               shift = ieee80211_vif_get_shift(&sdata->vif);
+
+               rcu_read_lock();
+               chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+               if (WARN_ON(!chanctx_conf)) {
+                       rcu_read_unlock();
+                       return -EINVAL;
+               }
+               rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
+               rcu_read_unlock();
 
                ieee80211_get_rates(sband, bss->supp_rates,
                                    bss->supp_rates_len,
                                    &rates, &basic_rates,
                                    &have_higher_than_11mbit,
-                                   &min_rate, &min_rate_index);
+                                   &min_rate, &min_rate_index,
+                                   shift, rate_flags);
 
                /*
                 * This used to be a workaround for basic rates missing