]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - net/mac80211/mlme.c
Merge tag 'nfs-for-3.12-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[mirror_ubuntu-artful-kernel.git] / net / mac80211 / mlme.c
index cc9e02d79b550106ee07b6aca48ffa9e18081a45..86e4ad56b573df27779831e17dce835f67396836 100644 (file)
@@ -489,27 +489,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,
@@ -628,12 +607,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);
 
@@ -644,8 +623,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) {
                /*
@@ -654,17 +635,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 +
@@ -741,8 +729,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;
                }
@@ -755,8 +744,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;
                        }
                }
        }
@@ -767,7 +758,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                *pos++ = WLAN_EID_PWR_CAPABILITY;
                *pos++ = 2;
                *pos++ = 0; /* min tx power */
-               *pos++ = chan->max_power; /* max tx power */
+                /* max tx power */
+               *pos++ = ieee80211_chandef_max_power(&chanctx_conf->def);
 
                /* 2. supported channels */
                /* TODO: get this in reg domain format */
@@ -1121,6 +1113,15 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        case -1:
                cfg80211_chandef_create(&new_chandef, new_chan,
                                        NL80211_CHAN_NO_HT);
+               /* keep width for 5/10 MHz channels */
+               switch (sdata->vif.bss_conf.chandef.width) {
+               case NL80211_CHAN_WIDTH_5:
+               case NL80211_CHAN_WIDTH_10:
+                       new_chandef.width = sdata->vif.bss_conf.chandef.width;
+                       break;
+               default:
+                       break;
+               }
                break;
        }
 
@@ -2443,15 +2444,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;
 
                /*
@@ -2467,12 +2469,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;
@@ -2851,14 +2861,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                ieee80211_rx_bss_put(local, bss);
                sdata->vif.bss_conf.beacon_rate = bss->beacon_rate;
        }
-
-       if (!sdata->u.mgd.associated ||
-           !ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid))
-               return;
-
-       ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
-                                        elems, true);
-
 }
 
 
@@ -3147,6 +3149,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
 
+       ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
+                                        &elems, true);
+
        if (ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
                                     elems.wmm_param_len))
                changed |= BSS_CHANGED_QOS;
@@ -3902,27 +3907,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