aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-03-01 07:07:48 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-03-06 10:36:03 -0500
commit55d942f4246c79a8f3f17f92c224e641c5c26125 (patch)
treeef369cf92b496330e9aa44729897ed46cbe005f4
parentc07270b605f49039327c35224e27d1d3e802f8a4 (diff)
mac80211: restrict peer's VHT capabilities to own
Implement restricting peer VHT capabilities to the device's own capabilities. This is useful when a single driver supports more than one device and the devices have different capabilities (often they will differ in the number of spatial streams), but in particular is also necessary for VHT capability overrides to work correctly -- otherwise it'd be possible to e.g. advertise, due to overrides, that TX-STBC is not supported, but then still use it to TX to the AP because it supports RX-STBC. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/linux/ieee80211.h3
-rw-r--r--include/net/mac80211.h5
-rw-r--r--net/mac80211/vht.c114
3 files changed, 117 insertions, 5 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 35c1f96d9365..4cf0c9e4dd99 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1333,10 +1333,11 @@ struct ieee80211_vht_operation {
1333#define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200 1333#define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200
1334#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300 1334#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300
1335#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400 1335#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400
1336#define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700
1336#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800 1337#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800
1337#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000 1338#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000
1338#define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX 0x00006000 1339#define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX 0x00006000
1339#define IEEE80211_VHT_CAP_SOUNDING_DIMENTION_MAX 0x00030000 1340#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX 0x00030000
1340#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000 1341#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000
1341#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000 1342#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000
1342#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000 1343#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 421c3ac8c521..cdd7cea1fd4c 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1228,9 +1228,8 @@ enum ieee80211_sta_rx_bandwidth {
1228 * @addr: MAC address 1228 * @addr: MAC address
1229 * @aid: AID we assigned to the station if we're an AP 1229 * @aid: AID we assigned to the station if we're an AP
1230 * @supp_rates: Bitmap of supported rates (per band) 1230 * @supp_rates: Bitmap of supported rates (per band)
1231 * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities 1231 * @ht_cap: HT capabilities of this STA; restricted to our own capabilities
1232 * @vht_cap: VHT capabilities of this STA; Not restricting any capabilities 1232 * @vht_cap: VHT capabilities of this STA; restricted to our own capabilities
1233 * of remote STA. Taking as is.
1234 * @wme: indicates whether the STA supports WME. Only valid during AP-mode. 1233 * @wme: indicates whether the STA supports WME. Only valid during AP-mode.
1235 * @drv_priv: data area for driver use, will always be aligned to 1234 * @drv_priv: data area for driver use, will always be aligned to
1236 * sizeof(void *), size is determined in hw information. 1235 * sizeof(void *), size is determined in hw information.
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index cacc1c74556a..171344d4eb7c 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -118,6 +118,8 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
118 struct sta_info *sta) 118 struct sta_info *sta)
119{ 119{
120 struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap; 120 struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap;
121 struct ieee80211_sta_vht_cap own_cap;
122 u32 cap_info, i;
121 123
122 memset(vht_cap, 0, sizeof(*vht_cap)); 124 memset(vht_cap, 0, sizeof(*vht_cap));
123 125
@@ -133,12 +135,122 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
133 135
134 vht_cap->vht_supported = true; 136 vht_cap->vht_supported = true;
135 137
136 vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info); 138 own_cap = sband->vht_cap;
139 /*
140 * If user has specified capability overrides, take care
141 * of that if the station we're setting up is the AP that
142 * we advertised a restricted capability set to. Override
143 * our own capabilities and then use those below.
144 */
145 if (sdata->vif.type == NL80211_IFTYPE_STATION &&
146 !test_sta_flag(sta, WLAN_STA_TDLS_PEER))
147 ieee80211_apply_vhtcap_overrides(sdata, &own_cap);
148
149 /* take some capabilities as-is */
150 cap_info = le32_to_cpu(vht_cap_ie->vht_cap_info);
151 vht_cap->cap = cap_info;
152 vht_cap->cap &= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 |
153 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
154 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
155 IEEE80211_VHT_CAP_RXLDPC |
156 IEEE80211_VHT_CAP_VHT_TXOP_PS |
157 IEEE80211_VHT_CAP_HTC_VHT |
158 IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
159 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB |
160 IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB |
161 IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN |
162 IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN;
163
164 /* and some based on our own capabilities */
165 switch (own_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
166 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
167 vht_cap->cap |= cap_info &
168 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
169 break;
170 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
171 vht_cap->cap |= cap_info &
172 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
173 break;
174 default:
175 /* nothing */
176 break;
177 }
178
179 /* symmetric capabilities */
180 vht_cap->cap |= cap_info & own_cap.cap &
181 (IEEE80211_VHT_CAP_SHORT_GI_80 |
182 IEEE80211_VHT_CAP_SHORT_GI_160);
183
184 /* remaining ones */
185 if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) {
186 vht_cap->cap |= cap_info &
187 (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
188 IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX |
189 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX);
190 }
191
192 if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)
193 vht_cap->cap |= cap_info &
194 IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
195
196 if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)
197 vht_cap->cap |= cap_info &
198 IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
199
200 if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)
201 vht_cap->cap |= cap_info &
202 IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE;
203
204 if (own_cap.cap & IEEE80211_VHT_CAP_TXSTBC)
205 vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_RXSTBC_MASK;
206
207 if (own_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK)
208 vht_cap->cap |= cap_info & IEEE80211_VHT_CAP_TXSTBC;
137 209
138 /* Copy peer MCS info, the driver might need them. */ 210 /* Copy peer MCS info, the driver might need them. */
139 memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, 211 memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs,
140 sizeof(struct ieee80211_vht_mcs_info)); 212 sizeof(struct ieee80211_vht_mcs_info));
141 213
214 /* but also restrict MCSes */
215 for (i = 0; i < 8; i++) {
216 u16 own_rx, own_tx, peer_rx, peer_tx;
217
218 own_rx = le16_to_cpu(own_cap.vht_mcs.rx_mcs_map);
219 own_rx = (own_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
220
221 own_tx = le16_to_cpu(own_cap.vht_mcs.tx_mcs_map);
222 own_tx = (own_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
223
224 peer_rx = le16_to_cpu(vht_cap->vht_mcs.rx_mcs_map);
225 peer_rx = (peer_rx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
226
227 peer_tx = le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
228 peer_tx = (peer_tx >> i * 2) & IEEE80211_VHT_MCS_NOT_SUPPORTED;
229
230 if (peer_tx != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
231 if (own_rx == IEEE80211_VHT_MCS_NOT_SUPPORTED)
232 peer_tx = IEEE80211_VHT_MCS_NOT_SUPPORTED;
233 else if (own_rx < peer_tx)
234 peer_tx = own_rx;
235 }
236
237 if (peer_rx != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
238 if (own_tx == IEEE80211_VHT_MCS_NOT_SUPPORTED)
239 peer_rx = IEEE80211_VHT_MCS_NOT_SUPPORTED;
240 else if (own_tx < peer_rx)
241 peer_rx = own_tx;
242 }
243
244 vht_cap->vht_mcs.rx_mcs_map &=
245 ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2);
246 vht_cap->vht_mcs.rx_mcs_map |= cpu_to_le16(peer_rx << i * 2);
247
248 vht_cap->vht_mcs.tx_mcs_map &=
249 ~cpu_to_le16(IEEE80211_VHT_MCS_NOT_SUPPORTED << i * 2);
250 vht_cap->vht_mcs.tx_mcs_map |= cpu_to_le16(peer_tx << i * 2);
251 }
252
253 /* finally set up the bandwidth */
142 switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { 254 switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
143 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: 255 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
144 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: 256 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: