aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorSimon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>2013-07-08 10:55:53 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-07-16 02:58:06 -0400
commit2103dec14792be2c2194a454630b01120d30e5cb (patch)
tree6bc0cd39eb2fe5317f0383ed7c4c238fb98ec114 /net/mac80211/mlme.c
parenta5e70697d0c4836e69c60de92db27eac9ae71e05 (diff)
mac80211: select and adjust bitrates according to channel mode
The various components accessing the bitrates table must use consider the used channel bandwidth to select only available rates or calculate the bitrate correctly. There are some rates in reduced bandwidth modes which can't be represented as multiples of 500kbps, like 2.25 MBit/s in 5 MHz mode. The standard suggests to round up to the next multiple of 500kbps, just do that in mac80211 as well. Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> Signed-off-by: Mathias Kretschmer <mathias.kretschmer@fokus.fraunhofer.de> [make rate unsigned in ieee80211_add_tx_radiotap_header(), squash fix] Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c95
1 files changed, 54 insertions, 41 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index ae31968d42d3..f7552c2b74eb 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -478,27 +478,6 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
478 478
479/* frame sending functions */ 479/* frame sending functions */
480 480
481static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len,
482 struct ieee80211_supported_band *sband,
483 u32 *rates)
484{
485 int i, j, count;
486 *rates = 0;
487 count = 0;
488 for (i = 0; i < supp_rates_len; i++) {
489 int rate = (supp_rates[i] & 0x7F) * 5;
490
491 for (j = 0; j < sband->n_bitrates; j++)
492 if (sband->bitrates[j].bitrate == rate) {
493 *rates |= BIT(j);
494 count++;
495 break;
496 }
497 }
498
499 return count;
500}
501
502static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, 481static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata,
503 struct sk_buff *skb, u8 ap_ht_param, 482 struct sk_buff *skb, u8 ap_ht_param,
504 struct ieee80211_supported_band *sband, 483 struct ieee80211_supported_band *sband,
@@ -617,12 +596,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
617 struct ieee80211_mgmt *mgmt; 596 struct ieee80211_mgmt *mgmt;
618 u8 *pos, qos_info; 597 u8 *pos, qos_info;
619 size_t offset = 0, noffset; 598 size_t offset = 0, noffset;
620 int i, count, rates_len, supp_rates_len; 599 int i, count, rates_len, supp_rates_len, shift;
621 u16 capab; 600 u16 capab;
622 struct ieee80211_supported_band *sband; 601 struct ieee80211_supported_band *sband;
623 struct ieee80211_chanctx_conf *chanctx_conf; 602 struct ieee80211_chanctx_conf *chanctx_conf;
624 struct ieee80211_channel *chan; 603 struct ieee80211_channel *chan;
625 u32 rates = 0; 604 u32 rate_flags, rates = 0;
626 605
627 sdata_assert_lock(sdata); 606 sdata_assert_lock(sdata);
628 607
@@ -633,8 +612,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
633 return; 612 return;
634 } 613 }
635 chan = chanctx_conf->def.chan; 614 chan = chanctx_conf->def.chan;
615 rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
636 rcu_read_unlock(); 616 rcu_read_unlock();
637 sband = local->hw.wiphy->bands[chan->band]; 617 sband = local->hw.wiphy->bands[chan->band];
618 shift = ieee80211_vif_get_shift(&sdata->vif);
638 619
639 if (assoc_data->supp_rates_len) { 620 if (assoc_data->supp_rates_len) {
640 /* 621 /*
@@ -643,17 +624,24 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
643 * in the association request (e.g. D-Link DAP 1353 in 624 * in the association request (e.g. D-Link DAP 1353 in
644 * b-only mode)... 625 * b-only mode)...
645 */ 626 */
646 rates_len = ieee80211_compatible_rates(assoc_data->supp_rates, 627 rates_len = ieee80211_parse_bitrates(&chanctx_conf->def, sband,
647 assoc_data->supp_rates_len, 628 assoc_data->supp_rates,
648 sband, &rates); 629 assoc_data->supp_rates_len,
630 &rates);
649 } else { 631 } else {
650 /* 632 /*
651 * In case AP not provide any supported rates information 633 * In case AP not provide any supported rates information
652 * before association, we send information element(s) with 634 * before association, we send information element(s) with
653 * all rates that we support. 635 * all rates that we support.
654 */ 636 */
655 rates = ~0; 637 rates_len = 0;
656 rates_len = sband->n_bitrates; 638 for (i = 0; i < sband->n_bitrates; i++) {
639 if ((rate_flags & sband->bitrates[i].flags)
640 != rate_flags)
641 continue;
642 rates |= BIT(i);
643 rates_len++;
644 }
657 } 645 }
658 646
659 skb = alloc_skb(local->hw.extra_tx_headroom + 647 skb = alloc_skb(local->hw.extra_tx_headroom +
@@ -730,8 +718,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
730 count = 0; 718 count = 0;
731 for (i = 0; i < sband->n_bitrates; i++) { 719 for (i = 0; i < sband->n_bitrates; i++) {
732 if (BIT(i) & rates) { 720 if (BIT(i) & rates) {
733 int rate = sband->bitrates[i].bitrate; 721 int rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
734 *pos++ = (u8) (rate / 5); 722 5 * (1 << shift));
723 *pos++ = (u8) rate;
735 if (++count == 8) 724 if (++count == 8)
736 break; 725 break;
737 } 726 }
@@ -744,8 +733,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
744 733
745 for (i++; i < sband->n_bitrates; i++) { 734 for (i++; i < sband->n_bitrates; i++) {
746 if (BIT(i) & rates) { 735 if (BIT(i) & rates) {
747 int rate = sband->bitrates[i].bitrate; 736 int rate;
748 *pos++ = (u8) (rate / 5); 737 rate = DIV_ROUND_UP(sband->bitrates[i].bitrate,
738 5 * (1 << shift));
739 *pos++ = (u8) rate;
749 } 740 }
750 } 741 }
751 } 742 }
@@ -2432,15 +2423,16 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
2432 u8 *supp_rates, unsigned int supp_rates_len, 2423 u8 *supp_rates, unsigned int supp_rates_len,
2433 u32 *rates, u32 *basic_rates, 2424 u32 *rates, u32 *basic_rates,
2434 bool *have_higher_than_11mbit, 2425 bool *have_higher_than_11mbit,
2435 int *min_rate, int *min_rate_index) 2426 int *min_rate, int *min_rate_index,
2427 int shift, u32 rate_flags)
2436{ 2428{
2437 int i, j; 2429 int i, j;
2438 2430
2439 for (i = 0; i < supp_rates_len; i++) { 2431 for (i = 0; i < supp_rates_len; i++) {
2440 int rate = (supp_rates[i] & 0x7f) * 5; 2432 int rate = supp_rates[i] & 0x7f;
2441 bool is_basic = !!(supp_rates[i] & 0x80); 2433 bool is_basic = !!(supp_rates[i] & 0x80);
2442 2434
2443 if (rate > 110) 2435 if ((rate * 5 * (1 << shift)) > 110)
2444 *have_higher_than_11mbit = true; 2436 *have_higher_than_11mbit = true;
2445 2437
2446 /* 2438 /*
@@ -2456,12 +2448,20 @@ static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
2456 continue; 2448 continue;
2457 2449
2458 for (j = 0; j < sband->n_bitrates; j++) { 2450 for (j = 0; j < sband->n_bitrates; j++) {
2459 if (sband->bitrates[j].bitrate == rate) { 2451 struct ieee80211_rate *br;
2452 int brate;
2453
2454 br = &sband->bitrates[j];
2455 if ((rate_flags & br->flags) != rate_flags)
2456 continue;
2457
2458 brate = DIV_ROUND_UP(br->bitrate, (1 << shift) * 5);
2459 if (brate == rate) {
2460 *rates |= BIT(j); 2460 *rates |= BIT(j);
2461 if (is_basic) 2461 if (is_basic)
2462 *basic_rates |= BIT(j); 2462 *basic_rates |= BIT(j);
2463 if (rate < *min_rate) { 2463 if ((rate * 5) < *min_rate) {
2464 *min_rate = rate; 2464 *min_rate = rate * 5;
2465 *min_rate_index = j; 2465 *min_rate_index = j;
2466 } 2466 }
2467 break; 2467 break;
@@ -3884,27 +3884,40 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
3884 if (!new_sta) 3884 if (!new_sta)
3885 return -ENOMEM; 3885 return -ENOMEM;
3886 } 3886 }
3887
3888 if (new_sta) { 3887 if (new_sta) {
3889 u32 rates = 0, basic_rates = 0; 3888 u32 rates = 0, basic_rates = 0;
3890 bool have_higher_than_11mbit; 3889 bool have_higher_than_11mbit;
3891 int min_rate = INT_MAX, min_rate_index = -1; 3890 int min_rate = INT_MAX, min_rate_index = -1;
3891 struct ieee80211_chanctx_conf *chanctx_conf;
3892 struct ieee80211_supported_band *sband; 3892 struct ieee80211_supported_band *sband;
3893 const struct cfg80211_bss_ies *ies; 3893 const struct cfg80211_bss_ies *ies;
3894 int shift;
3895 u32 rate_flags;
3894 3896
3895 sband = local->hw.wiphy->bands[cbss->channel->band]; 3897 sband = local->hw.wiphy->bands[cbss->channel->band];
3896 3898
3897 err = ieee80211_prep_channel(sdata, cbss); 3899 err = ieee80211_prep_channel(sdata, cbss);
3898 if (err) { 3900 if (err) {
3899 sta_info_free(local, new_sta); 3901 sta_info_free(local, new_sta);
3900 return err; 3902 return -EINVAL;
3901 } 3903 }
3904 shift = ieee80211_vif_get_shift(&sdata->vif);
3905
3906 rcu_read_lock();
3907 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
3908 if (WARN_ON(!chanctx_conf)) {
3909 rcu_read_unlock();
3910 return -EINVAL;
3911 }
3912 rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
3913 rcu_read_unlock();
3902 3914
3903 ieee80211_get_rates(sband, bss->supp_rates, 3915 ieee80211_get_rates(sband, bss->supp_rates,
3904 bss->supp_rates_len, 3916 bss->supp_rates_len,
3905 &rates, &basic_rates, 3917 &rates, &basic_rates,
3906 &have_higher_than_11mbit, 3918 &have_higher_than_11mbit,
3907 &min_rate, &min_rate_index); 3919 &min_rate, &min_rate_index,
3920 shift, rate_flags);
3908 3921
3909 /* 3922 /*
3910 * This used to be a workaround for basic rates missing 3923 * This used to be a workaround for basic rates missing