diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 95 |
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 | ||
481 | static 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 | |||
502 | static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, | 481 | static 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 |