aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-10-14 10:58:37 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-10-31 19:00:16 -0400
commitae5eb02641233a4e9d1b92d22090f1b1afa14466 (patch)
tree117b7cb5efa3ff1cf714218098fc6db3820ed4e0 /net
parentbda3933a8aceedd03e0dd410844bd310033ca756 (diff)
mac80211: rewrite HT handling
The HT handling has the following deficiencies, which I've (partially) fixed: * it always uses the AP info even if there is no AP, hence has no chance of working as an AP * it pretends to be HW config, but really is per-BSS * channel sanity checking is left to the drivers * it generally lets the driver control too much HT enabling is still wrong with this patch if you have more than one virtual STA mode interface, but that never happens currently. Once WDS, IBSS or AP/VLAN gets HT capabilities, it will also be wrong, see the comment in ieee80211_enable_ht(). Additionally, this fixes a number of bugs: * mac80211: ieee80211_set_disassoc doesn't notify the driver any more since the refactoring * iwl-agn-rs: always uses the HT capabilities from the wrong stuff mac80211 gives it rather than the actual peer STA * ath9k: a number of bugs resulting from the broken HT API I'm not entirely happy with putting the HT capabilities into struct ieee80211_sta as restricted to our own HT TX capabilities, but I see no cleaner solution for now. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c6
-rw-r--r--net/mac80211/ht.c181
-rw-r--r--net/mac80211/ieee80211_i.h12
-rw-r--r--net/mac80211/mlme.c88
4 files changed, 134 insertions, 153 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 28382b5c7c25..55e3a26510ed 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -582,6 +582,8 @@ static void sta_apply_parameters(struct ieee80211_local *local,
582 struct ieee80211_supported_band *sband; 582 struct ieee80211_supported_band *sband;
583 struct ieee80211_sub_if_data *sdata = sta->sdata; 583 struct ieee80211_sub_if_data *sdata = sta->sdata;
584 584
585 sband = local->hw.wiphy->bands[local->oper_channel->band];
586
585 /* 587 /*
586 * FIXME: updating the flags is racy when this function is 588 * FIXME: updating the flags is racy when this function is
587 * called from ieee80211_change_station(), this will 589 * called from ieee80211_change_station(), this will
@@ -622,7 +624,6 @@ static void sta_apply_parameters(struct ieee80211_local *local,
622 624
623 if (params->supported_rates) { 625 if (params->supported_rates) {
624 rates = 0; 626 rates = 0;
625 sband = local->hw.wiphy->bands[local->oper_channel->band];
626 627
627 for (i = 0; i < params->supported_rates_len; i++) { 628 for (i = 0; i < params->supported_rates_len; i++) {
628 int rate = (params->supported_rates[i] & 0x7f) * 5; 629 int rate = (params->supported_rates[i] & 0x7f) * 5;
@@ -635,7 +636,8 @@ static void sta_apply_parameters(struct ieee80211_local *local,
635 } 636 }
636 637
637 if (params->ht_capa) 638 if (params->ht_capa)
638 ieee80211_ht_cap_ie_to_sta_ht_cap(params->ht_capa, 639 ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
640 params->ht_capa,
639 &sta->sta.ht_cap); 641 &sta->sta.ht_cap);
640 642
641 if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { 643 if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index e2d121bf2745..42c3e590df98 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -20,114 +20,38 @@
20#include "sta_info.h" 20#include "sta_info.h"
21#include "wme.h" 21#include "wme.h"
22 22
23void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_ht_cap *ht_cap_ie, 23void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
24 struct ieee80211_ht_cap *ht_cap_ie,
24 struct ieee80211_sta_ht_cap *ht_cap) 25 struct ieee80211_sta_ht_cap *ht_cap)
25{ 26{
27 u8 ampdu_info, tx_mcs_set_cap;
28 int i, max_tx_streams;
26 29
27 BUG_ON(!ht_cap); 30 BUG_ON(!ht_cap);
28 31
29 memset(ht_cap, 0, sizeof(*ht_cap)); 32 memset(ht_cap, 0, sizeof(*ht_cap));
30 33
31 if (ht_cap_ie) { 34 if (!ht_cap_ie)
32 u8 ampdu_info = ht_cap_ie->ampdu_params_info; 35 return;
33
34 ht_cap->ht_supported = true;
35 ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info);
36 ht_cap->ampdu_factor =
37 ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
38 ht_cap->ampdu_density =
39 (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
40 memcpy(&ht_cap->mcs, &ht_cap_ie->mcs, sizeof(ht_cap->mcs));
41 } else
42 ht_cap->ht_supported = false;
43}
44
45void ieee80211_ht_info_ie_to_ht_bss_info(
46 struct ieee80211_ht_info *ht_add_info_ie,
47 struct ieee80211_ht_bss_info *bss_info)
48{
49 BUG_ON(!bss_info);
50
51 memset(bss_info, 0, sizeof(*bss_info));
52
53 if (ht_add_info_ie) {
54 u16 op_mode;
55 op_mode = le16_to_cpu(ht_add_info_ie->operation_mode);
56
57 bss_info->primary_channel = ht_add_info_ie->control_chan;
58 bss_info->bss_cap = ht_add_info_ie->ht_param;
59 bss_info->bss_op_mode = (u8)(op_mode & 0xff);
60 }
61}
62
63/*
64 * ieee80211_handle_ht should be called only after the operating band
65 * has been determined as ht configuration depends on the hw's
66 * HT abilities for a specific band.
67 */
68u32 ieee80211_handle_ht(struct ieee80211_local *local,
69 struct ieee80211_sta_ht_cap *req_ht_cap,
70 struct ieee80211_ht_bss_info *req_bss_cap)
71{
72 struct ieee80211_conf *conf = &local->hw.conf;
73 struct ieee80211_supported_band *sband;
74 struct ieee80211_sta_ht_cap ht_cap;
75 struct ieee80211_ht_bss_info ht_bss_conf;
76 u32 changed = 0;
77 int i;
78 u8 max_tx_streams;
79 u8 tx_mcs_set_cap;
80 bool enable_ht = true;
81
82 sband = local->hw.wiphy->bands[conf->channel->band];
83
84 memset(&ht_cap, 0, sizeof(ht_cap));
85 memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
86
87 /* HT is not supported */
88 if (!sband->ht_cap.ht_supported)
89 enable_ht = false;
90
91 /* disable HT */
92 if (!enable_ht) {
93 if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
94 changed |= BSS_CHANGED_HT;
95 conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
96 conf->ht_cap.ht_supported = false;
97 return changed;
98 }
99
100
101 if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
102 changed |= BSS_CHANGED_HT;
103
104 conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
105 ht_cap.ht_supported = true;
106 36
107 ht_cap.cap = req_ht_cap->cap & sband->ht_cap.cap; 37 ht_cap->ht_supported = true;
108 ht_cap.cap &= ~IEEE80211_HT_CAP_SM_PS;
109 ht_cap.cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;
110 38
111 ht_bss_conf.primary_channel = req_bss_cap->primary_channel; 39 ht_cap->cap = ht_cap->cap & sband->ht_cap.cap;
112 ht_bss_conf.bss_cap = req_bss_cap->bss_cap; 40 ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS;
113 ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; 41 ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS;
114 42
115 ht_cap.ampdu_factor = req_ht_cap->ampdu_factor; 43 ampdu_info = ht_cap_ie->ampdu_params_info;
116 ht_cap.ampdu_density = req_ht_cap->ampdu_density; 44 ht_cap->ampdu_factor =
45 ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR;
46 ht_cap->ampdu_density =
47 (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
117 48
118 /* own MCS TX capabilities */ 49 /* own MCS TX capabilities */
119 tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; 50 tx_mcs_set_cap = sband->ht_cap.mcs.tx_params;
120 51
121 /*
122 * configure supported Tx MCS according to requested MCS
123 * (based in most cases on Rx capabilities of peer) and self
124 * Tx MCS capabilities (as defined by low level driver HW
125 * Tx capabilities)
126 */
127
128 /* can we TX with MCS rates? */ 52 /* can we TX with MCS rates? */
129 if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) 53 if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED))
130 goto check_changed; 54 return;
131 55
132 /* Counting from 0, therefore +1 */ 56 /* Counting from 0, therefore +1 */
133 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) 57 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF)
@@ -145,29 +69,73 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local,
145 * - remainder are multiple spatial streams using unequal modulation 69 * - remainder are multiple spatial streams using unequal modulation
146 */ 70 */
147 for (i = 0; i < max_tx_streams; i++) 71 for (i = 0; i < max_tx_streams; i++)
148 ht_cap.mcs.rx_mask[i] = 72 ht_cap->mcs.rx_mask[i] =
149 sband->ht_cap.mcs.rx_mask[i] & 73 sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
150 req_ht_cap->mcs.rx_mask[i];
151 74
152 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) 75 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
153 for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; 76 for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
154 i < IEEE80211_HT_MCS_MASK_LEN; i++) 77 i < IEEE80211_HT_MCS_MASK_LEN; i++)
155 ht_cap.mcs.rx_mask[i] = 78 ht_cap->mcs.rx_mask[i] =
156 sband->ht_cap.mcs.rx_mask[i] & 79 sband->ht_cap.mcs.rx_mask[i] &
157 req_ht_cap->mcs.rx_mask[i]; 80 ht_cap_ie->mcs.rx_mask[i];
158 81
159 /* handle MCS rate 32 too */ 82 /* handle MCS rate 32 too */
160 if (sband->ht_cap.mcs.rx_mask[32/8] & 83 if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
161 req_ht_cap->mcs.rx_mask[32/8] & 1) 84 ht_cap->mcs.rx_mask[32/8] |= 1;
162 ht_cap.mcs.rx_mask[32/8] |= 1; 85}
86
87/*
88 * ieee80211_enable_ht should be called only after the operating band
89 * has been determined as ht configuration depends on the hw's
90 * HT abilities for a specific band.
91 */
92u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
93 struct ieee80211_ht_info *hti,
94 u16 ap_ht_cap_flags)
95{
96 struct ieee80211_local *local = sdata->local;
97 struct ieee80211_supported_band *sband;
98 struct ieee80211_bss_ht_conf ht;
99 u32 changed = 0;
100 bool enable_ht = true, ht_changed;
101
102 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
103
104 memset(&ht, 0, sizeof(ht));
105
106 /* HT is not supported */
107 if (!sband->ht_cap.ht_supported)
108 enable_ht = false;
109
110 /* check that channel matches the right operating channel */
111 if (local->hw.conf.channel->center_freq !=
112 ieee80211_channel_to_frequency(hti->control_chan))
113 enable_ht = false;
114
115 /*
116 * XXX: This is totally incorrect when there are multiple virtual
117 * interfaces, needs to be fixed later.
118 */
119 ht_changed = local->hw.conf.ht.enabled != enable_ht;
120 local->hw.conf.ht.enabled = enable_ht;
121 if (ht_changed)
122 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
123
124 /* disable HT */
125 if (!enable_ht)
126 return 0;
127 ht.secondary_channel_offset =
128 hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
129 ht.width_40_ok =
130 !(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
131 (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) &&
132 (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY);
133 ht.operation_mode = le16_to_cpu(hti->operation_mode);
163 134
164 check_changed:
165 /* if bss configuration changed store the new one */ 135 /* if bss configuration changed store the new one */
166 if (memcmp(&conf->ht_cap, &ht_cap, sizeof(ht_cap)) || 136 if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) {
167 memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
168 changed |= BSS_CHANGED_HT; 137 changed |= BSS_CHANGED_HT;
169 memcpy(&conf->ht_cap, &ht_cap, sizeof(ht_cap)); 138 sdata->vif.bss_conf.ht = ht;
170 memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
171 } 139 }
172 140
173 return changed; 141 return changed;
@@ -900,8 +868,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
900 /* sanity check for incoming parameters: 868 /* sanity check for incoming parameters:
901 * check if configuration can support the BA policy 869 * check if configuration can support the BA policy
902 * and if buffer size does not exceeds max value */ 870 * and if buffer size does not exceeds max value */
871 /* XXX: check own ht delayed BA capability?? */
903 if (((ba_policy != 1) 872 if (((ba_policy != 1)
904 && (!(conf->ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) 873 && (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA)))
905 || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { 874 || (buf_size > IEEE80211_MAX_AMPDU_BUF)) {
906 status = WLAN_STATUS_INVALID_QOS_PARAM; 875 status = WLAN_STATUS_INVALID_QOS_PARAM;
907#ifdef CONFIG_MAC80211_HT_DEBUG 876#ifdef CONFIG_MAC80211_HT_DEBUG
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 859b5b001f22..6f8756d26a93 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -955,14 +955,12 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
955int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); 955int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
956 956
957/* HT */ 957/* HT */
958void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_ht_cap *ht_cap_ie, 958void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
959 struct ieee80211_ht_cap *ht_cap_ie,
959 struct ieee80211_sta_ht_cap *ht_cap); 960 struct ieee80211_sta_ht_cap *ht_cap);
960void ieee80211_ht_info_ie_to_ht_bss_info( 961u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
961 struct ieee80211_ht_info *ht_add_info_ie, 962 struct ieee80211_ht_info *hti,
962 struct ieee80211_ht_bss_info *bss_info); 963 u16 ap_ht_cap_flags);
963u32 ieee80211_handle_ht(struct ieee80211_local *local,
964 struct ieee80211_sta_ht_cap *req_ht_cap,
965 struct ieee80211_ht_bss_info *req_bss_cap);
966void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); 964void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn);
967 965
968void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, 966void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 9c5f5c37a49e..39bc9c69893b 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -700,14 +700,15 @@ static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata,
700 700
701 701
702static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, 702static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
703 struct ieee80211_if_sta *ifsta) 703 struct ieee80211_if_sta *ifsta,
704 u32 bss_info_changed)
704{ 705{
705 struct ieee80211_local *local = sdata->local; 706 struct ieee80211_local *local = sdata->local;
706 struct ieee80211_conf *conf = &local_to_hw(local)->conf; 707 struct ieee80211_conf *conf = &local_to_hw(local)->conf;
707 u32 changed = BSS_CHANGED_ASSOC;
708 708
709 struct ieee80211_bss *bss; 709 struct ieee80211_bss *bss;
710 710
711 bss_info_changed |= BSS_CHANGED_ASSOC;
711 ifsta->flags |= IEEE80211_STA_ASSOCIATED; 712 ifsta->flags |= IEEE80211_STA_ASSOCIATED;
712 713
713 if (sdata->vif.type != NL80211_IFTYPE_STATION) 714 if (sdata->vif.type != NL80211_IFTYPE_STATION)
@@ -722,19 +723,12 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
722 sdata->vif.bss_conf.timestamp = bss->timestamp; 723 sdata->vif.bss_conf.timestamp = bss->timestamp;
723 sdata->vif.bss_conf.dtim_period = bss->dtim_period; 724 sdata->vif.bss_conf.dtim_period = bss->dtim_period;
724 725
725 changed |= ieee80211_handle_bss_capability(sdata, 726 bss_info_changed |= ieee80211_handle_bss_capability(sdata,
726 bss->capability, bss->has_erp_value, bss->erp_value); 727 bss->capability, bss->has_erp_value, bss->erp_value);
727 728
728 ieee80211_rx_bss_put(local, bss); 729 ieee80211_rx_bss_put(local, bss);
729 } 730 }
730 731
731 if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
732 changed |= BSS_CHANGED_HT;
733 sdata->vif.bss_conf.assoc_ht = 1;
734 sdata->vif.bss_conf.ht_cap = &conf->ht_cap;
735 sdata->vif.bss_conf.ht_bss_conf = &conf->ht_bss_conf;
736 }
737
738 ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; 732 ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
739 memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); 733 memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
740 ieee80211_sta_send_associnfo(sdata, ifsta); 734 ieee80211_sta_send_associnfo(sdata, ifsta);
@@ -748,8 +742,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
748 * when we have associated, we aren't checking whether it actually 742 * when we have associated, we aren't checking whether it actually
749 * changed or not. 743 * changed or not.
750 */ 744 */
751 changed |= BSS_CHANGED_BASIC_RATES; 745 bss_info_changed |= BSS_CHANGED_BASIC_RATES;
752 ieee80211_bss_info_change_notify(sdata, changed); 746 ieee80211_bss_info_change_notify(sdata, bss_info_changed);
753 747
754 netif_tx_start_all_queues(sdata->dev); 748 netif_tx_start_all_queues(sdata->dev);
755 netif_carrier_on(sdata->dev); 749 netif_carrier_on(sdata->dev);
@@ -813,7 +807,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
813{ 807{
814 struct ieee80211_local *local = sdata->local; 808 struct ieee80211_local *local = sdata->local;
815 struct sta_info *sta; 809 struct sta_info *sta;
816 u32 changed = BSS_CHANGED_ASSOC; 810 u32 changed = 0;
817 811
818 rcu_read_lock(); 812 rcu_read_lock();
819 813
@@ -847,15 +841,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
847 ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; 841 ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
848 changed |= ieee80211_reset_erp_info(sdata); 842 changed |= ieee80211_reset_erp_info(sdata);
849 843
850 if (sdata->vif.bss_conf.assoc_ht)
851 changed |= BSS_CHANGED_HT;
852
853 sdata->vif.bss_conf.assoc_ht = 0;
854 sdata->vif.bss_conf.ht_cap = NULL;
855 sdata->vif.bss_conf.ht_bss_conf = NULL;
856
857 ieee80211_led_assoc(local, 0); 844 ieee80211_led_assoc(local, 0);
858 sdata->vif.bss_conf.assoc = 0; 845 changed |= BSS_CHANGED_ASSOC;
846 sdata->vif.bss_conf.assoc = false;
859 847
860 ieee80211_sta_send_apinfo(sdata, ifsta); 848 ieee80211_sta_send_apinfo(sdata, ifsta);
861 849
@@ -867,6 +855,11 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
867 rcu_read_unlock(); 855 rcu_read_unlock();
868 856
869 sta_info_destroy(sta); 857 sta_info_destroy(sta);
858
859 local->hw.conf.ht.enabled = false;
860 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT);
861
862 ieee80211_bss_info_change_notify(sdata, changed);
870} 863}
871 864
872static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata) 865static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata)
@@ -1184,8 +1177,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
1184 struct ieee802_11_elems elems; 1177 struct ieee802_11_elems elems;
1185 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; 1178 struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
1186 u8 *pos; 1179 u8 *pos;
1180 u32 changed = 0;
1187 int i, j; 1181 int i, j;
1188 bool have_higher_than_11mbit = false; 1182 bool have_higher_than_11mbit = false;
1183 u16 ap_ht_cap_flags;
1189 1184
1190 /* AssocResp and ReassocResp have identical structure, so process both 1185 /* AssocResp and ReassocResp have identical structure, so process both
1191 * of them in this function. */ 1186 * of them in this function. */
@@ -1333,15 +1328,11 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
1333 else 1328 else
1334 sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; 1329 sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
1335 1330
1336 if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && 1331 if (elems.ht_cap_elem)
1337 (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { 1332 ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
1338 struct ieee80211_ht_bss_info bss_info;
1339 ieee80211_ht_cap_ie_to_sta_ht_cap(
1340 elems.ht_cap_elem, &sta->sta.ht_cap); 1333 elems.ht_cap_elem, &sta->sta.ht_cap);
1341 ieee80211_ht_info_ie_to_ht_bss_info( 1334
1342 elems.ht_info_elem, &bss_info); 1335 ap_ht_cap_flags = sta->sta.ht_cap.cap;
1343 ieee80211_handle_ht(local, &sta->sta.ht_cap, &bss_info);
1344 }
1345 1336
1346 rate_control_rate_init(sta); 1337 rate_control_rate_init(sta);
1347 1338
@@ -1353,11 +1344,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
1353 } else 1344 } else
1354 rcu_read_unlock(); 1345 rcu_read_unlock();
1355 1346
1347 if (elems.ht_info_elem && elems.wmm_param &&
1348 (ifsta->flags & IEEE80211_STA_WMM_ENABLED))
1349 changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
1350 ap_ht_cap_flags);
1351
1356 /* set AID and assoc capability, 1352 /* set AID and assoc capability,
1357 * ieee80211_set_associated() will tell the driver */ 1353 * ieee80211_set_associated() will tell the driver */
1358 bss_conf->aid = aid; 1354 bss_conf->aid = aid;
1359 bss_conf->assoc_capability = capab_info; 1355 bss_conf->assoc_capability = capab_info;
1360 ieee80211_set_associated(sdata, ifsta); 1356 ieee80211_set_associated(sdata, ifsta, changed);
1361 1357
1362 ieee80211_associated(sdata, ifsta); 1358 ieee80211_associated(sdata, ifsta);
1363} 1359}
@@ -1657,7 +1653,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
1657 size_t baselen; 1653 size_t baselen;
1658 struct ieee802_11_elems elems; 1654 struct ieee802_11_elems elems;
1659 struct ieee80211_local *local = sdata->local; 1655 struct ieee80211_local *local = sdata->local;
1660 struct ieee80211_conf *conf = &local->hw.conf;
1661 u32 changed = 0; 1656 u32 changed = 0;
1662 bool erp_valid; 1657 bool erp_valid;
1663 u8 erp_value = 0; 1658 u8 erp_value = 0;
@@ -1693,14 +1688,31 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
1693 le16_to_cpu(mgmt->u.beacon.capab_info), 1688 le16_to_cpu(mgmt->u.beacon.capab_info),
1694 erp_valid, erp_value); 1689 erp_valid, erp_value);
1695 1690
1696 if (elems.ht_cap_elem && elems.ht_info_elem &&
1697 elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) {
1698 struct ieee80211_ht_bss_info bss_info;
1699 1691
1700 ieee80211_ht_info_ie_to_ht_bss_info( 1692 if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) {
1701 elems.ht_info_elem, &bss_info); 1693 struct sta_info *sta;
1702 changed |= ieee80211_handle_ht(local, &conf->ht_cap, 1694 struct ieee80211_supported_band *sband;
1703 &bss_info); 1695 u16 ap_ht_cap_flags;
1696
1697 rcu_read_lock();
1698
1699 sta = sta_info_get(local, ifsta->bssid);
1700 if (!sta) {
1701 rcu_read_unlock();
1702 return;
1703 }
1704
1705 sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
1706
1707 ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
1708 elems.ht_cap_elem, &sta->sta.ht_cap);
1709
1710 ap_ht_cap_flags = sta->sta.ht_cap.cap;
1711
1712 rcu_read_unlock();
1713
1714 changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
1715 ap_ht_cap_flags);
1704 } 1716 }
1705 1717
1706 ieee80211_bss_info_change_notify(sdata, changed); 1718 ieee80211_bss_info_change_notify(sdata, changed);