aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-03-01 05:54:43 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-03-06 10:36:02 -0500
commitc07270b605f49039327c35224e27d1d3e802f8a4 (patch)
tree5c6b79b0fd7b357804ffdabdc000e97f62435e0d /net/mac80211
parent4f4b9357e45c121e3b350b938adc33781d6834fd (diff)
mac80211: fix HT capability overrides for AP station
HT capabilites are asymmetric -- e.g. beamforming is both an RX and TX capability. If, for example, we support RX but not TX, the RX capability of the AP station is masked out (if it supports it). This works correctly if it's really the driver capability. If, on the other hand, the reason for not supporting TX BF is that it was removed by HT capability overrides then the wrong thing happens: the AP's TX capability will be removed rather than its RX capability, because the override function works on own capabilities, not remote ones, and doesn't take the asymmetry into account. To fix this make a copy of our own capabilities, apply the overrides to them (where needed) and then use that to set up the peer's capabilities. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ht.c48
1 files changed, 25 insertions, 23 deletions
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 4515fc33abff..af8cee06e4f3 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -90,7 +90,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
90 const struct ieee80211_ht_cap *ht_cap_ie, 90 const struct ieee80211_ht_cap *ht_cap_ie,
91 struct sta_info *sta) 91 struct sta_info *sta)
92{ 92{
93 struct ieee80211_sta_ht_cap ht_cap; 93 struct ieee80211_sta_ht_cap ht_cap, own_cap;
94 u8 ampdu_info, tx_mcs_set_cap; 94 u8 ampdu_info, tx_mcs_set_cap;
95 int i, max_tx_streams; 95 int i, max_tx_streams;
96 bool changed; 96 bool changed;
@@ -104,6 +104,18 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
104 104
105 ht_cap.ht_supported = true; 105 ht_cap.ht_supported = true;
106 106
107 own_cap = sband->ht_cap;
108
109 /*
110 * If user has specified capability over-rides, take care
111 * of that if the station we're setting up is the AP that
112 * we advertised a restricted capability set to. Override
113 * our own capabilities and then use those below.
114 */
115 if (sdata->vif.type == NL80211_IFTYPE_STATION &&
116 !test_sta_flag(sta, WLAN_STA_TDLS_PEER))
117 ieee80211_apply_htcap_overrides(sdata, &own_cap);
118
107 /* 119 /*
108 * The bits listed in this expression should be 120 * The bits listed in this expression should be
109 * the same for the peer and us, if the station 121 * the same for the peer and us, if the station
@@ -111,21 +123,20 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
111 * we mask them out. 123 * we mask them out.
112 */ 124 */
113 ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) & 125 ht_cap.cap = le16_to_cpu(ht_cap_ie->cap_info) &
114 (sband->ht_cap.cap | 126 (own_cap.cap | ~(IEEE80211_HT_CAP_LDPC_CODING |
115 ~(IEEE80211_HT_CAP_LDPC_CODING | 127 IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
116 IEEE80211_HT_CAP_SUP_WIDTH_20_40 | 128 IEEE80211_HT_CAP_GRN_FLD |
117 IEEE80211_HT_CAP_GRN_FLD | 129 IEEE80211_HT_CAP_SGI_20 |
118 IEEE80211_HT_CAP_SGI_20 | 130 IEEE80211_HT_CAP_SGI_40 |
119 IEEE80211_HT_CAP_SGI_40 | 131 IEEE80211_HT_CAP_DSSSCCK40));
120 IEEE80211_HT_CAP_DSSSCCK40));
121 132
122 /* 133 /*
123 * The STBC bits are asymmetric -- if we don't have 134 * The STBC bits are asymmetric -- if we don't have
124 * TX then mask out the peer's RX and vice versa. 135 * TX then mask out the peer's RX and vice versa.
125 */ 136 */
126 if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)) 137 if (!(own_cap.cap & IEEE80211_HT_CAP_TX_STBC))
127 ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC; 138 ht_cap.cap &= ~IEEE80211_HT_CAP_RX_STBC;
128 if (!(sband->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)) 139 if (!(own_cap.cap & IEEE80211_HT_CAP_RX_STBC))
129 ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC; 140 ht_cap.cap &= ~IEEE80211_HT_CAP_TX_STBC;
130 141
131 ampdu_info = ht_cap_ie->ampdu_params_info; 142 ampdu_info = ht_cap_ie->ampdu_params_info;
@@ -135,7 +146,7 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
135 (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; 146 (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2;
136 147
137 /* own MCS TX capabilities */ 148 /* own MCS TX capabilities */
138 tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; 149 tx_mcs_set_cap = own_cap.mcs.tx_params;
139 150
140 /* Copy peer MCS TX capabilities, the driver might need them. */ 151 /* Copy peer MCS TX capabilities, the driver might need them. */
141 ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params; 152 ht_cap.mcs.tx_params = ht_cap_ie->mcs.tx_params;
@@ -161,29 +172,20 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
161 */ 172 */
162 for (i = 0; i < max_tx_streams; i++) 173 for (i = 0; i < max_tx_streams; i++)
163 ht_cap.mcs.rx_mask[i] = 174 ht_cap.mcs.rx_mask[i] =
164 sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; 175 own_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i];
165 176
166 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) 177 if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION)
167 for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; 178 for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE;
168 i < IEEE80211_HT_MCS_MASK_LEN; i++) 179 i < IEEE80211_HT_MCS_MASK_LEN; i++)
169 ht_cap.mcs.rx_mask[i] = 180 ht_cap.mcs.rx_mask[i] =
170 sband->ht_cap.mcs.rx_mask[i] & 181 own_cap.mcs.rx_mask[i] &
171 ht_cap_ie->mcs.rx_mask[i]; 182 ht_cap_ie->mcs.rx_mask[i];
172 183
173 /* handle MCS rate 32 too */ 184 /* handle MCS rate 32 too */
174 if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) 185 if (own_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1)
175 ht_cap.mcs.rx_mask[32/8] |= 1; 186 ht_cap.mcs.rx_mask[32/8] |= 1;
176 187
177 apply: 188 apply:
178 /*
179 * If user has specified capability over-rides, take care
180 * of that if the station we're setting up is the AP that
181 * we advertised a restricted capability set to.
182 */
183 if (sdata->vif.type == NL80211_IFTYPE_STATION &&
184 !test_sta_flag(sta, WLAN_STA_TDLS_PEER))
185 ieee80211_apply_htcap_overrides(sdata, &ht_cap);
186
187 changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); 189 changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
188 190
189 memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap)); 191 memcpy(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));