aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvri Altman <avri.altman@intel.com>2015-08-18 09:52:07 -0400
committerJohannes Berg <johannes.berg@intel.com>2015-09-04 08:25:46 -0400
commit22f66895e60cfc55b92f6fa93f05bb3fbdbd0bed (patch)
treea76a60a63d227291e39e7b9d46579f435292d2f3
parent98a1f8282b8c37378c1b947d661a58942331ca90 (diff)
mac80211: protect non-HT BSS when HT TDLS traffic exists
HT TDLS traffic should be protected in a non-HT BSS to avoid collisions. Therefore, when TDLS peers join/leave, check if protection is (now) needed and set the ht_operation_mode of the virtual interface according to the HT capabilities of the TDLS peer(s). This works because a non-HT BSS connection never sets (or otherwise uses) the ht_operation_mode; it just means that drivers must be aware that this field applies to all HT traffic for this virtual interface, not just the traffic within the BSS. Document that. Signed-off-by: Avri Altman <avri.altman@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/net/mac80211.h4
-rw-r--r--net/mac80211/tdls.c70
2 files changed, 70 insertions, 4 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index e3314e516681..bfc569498bfa 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -477,7 +477,9 @@ struct ieee80211_event {
477 * @chandef: Channel definition for this BSS -- the hardware might be 477 * @chandef: Channel definition for this BSS -- the hardware might be
478 * configured a higher bandwidth than this BSS uses, for example. 478 * configured a higher bandwidth than this BSS uses, for example.
479 * @ht_operation_mode: HT operation mode like in &struct ieee80211_ht_operation. 479 * @ht_operation_mode: HT operation mode like in &struct ieee80211_ht_operation.
480 * This field is only valid when the channel type is one of the HT types. 480 * This field is only valid when the channel is a wide HT/VHT channel.
481 * Note that with TDLS this can be the case (channel is HT, protection must
482 * be used from this field) even when the BSS association isn't using HT.
481 * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value 483 * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
482 * implies disabled 484 * implies disabled
483 * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis 485 * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index aee701a5649e..4e202d0679b2 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -1249,6 +1249,58 @@ static void iee80211_tdls_recalc_chanctx(struct ieee80211_sub_if_data *sdata)
1249 mutex_unlock(&local->chanctx_mtx); 1249 mutex_unlock(&local->chanctx_mtx);
1250} 1250}
1251 1251
1252static int iee80211_tdls_have_ht_peers(struct ieee80211_sub_if_data *sdata)
1253{
1254 struct sta_info *sta;
1255 bool result = false;
1256
1257 rcu_read_lock();
1258 list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {
1259 if (!sta->sta.tdls || sta->sdata != sdata || !sta->uploaded ||
1260 !test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
1261 !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH) ||
1262 !sta->sta.ht_cap.ht_supported)
1263 continue;
1264 result = true;
1265 break;
1266 }
1267 rcu_read_unlock();
1268
1269 return result;
1270}
1271
1272static void
1273iee80211_tdls_recalc_ht_protection(struct ieee80211_sub_if_data *sdata,
1274 struct sta_info *sta)
1275{
1276 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1277 bool tdls_ht;
1278 u16 protection = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED |
1279 IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT |
1280 IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT;
1281 u16 opmode;
1282
1283 /* Nothing to do if the BSS connection uses HT */
1284 if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
1285 return;
1286
1287 tdls_ht = (sta && sta->sta.ht_cap.ht_supported) ||
1288 iee80211_tdls_have_ht_peers(sdata);
1289
1290 opmode = sdata->vif.bss_conf.ht_operation_mode;
1291
1292 if (tdls_ht)
1293 opmode |= protection;
1294 else
1295 opmode &= ~protection;
1296
1297 if (opmode == sdata->vif.bss_conf.ht_operation_mode)
1298 return;
1299
1300 sdata->vif.bss_conf.ht_operation_mode = opmode;
1301 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
1302}
1303
1252int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, 1304int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
1253 const u8 *peer, enum nl80211_tdls_operation oper) 1305 const u8 *peer, enum nl80211_tdls_operation oper)
1254{ 1306{
@@ -1274,6 +1326,10 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
1274 return -ENOTSUPP; 1326 return -ENOTSUPP;
1275 } 1327 }
1276 1328
1329 /* protect possible bss_conf changes and avoid concurrency in
1330 * ieee80211_bss_info_change_notify()
1331 */
1332 sdata_lock(sdata);
1277 mutex_lock(&local->mtx); 1333 mutex_lock(&local->mtx);
1278 tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer); 1334 tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
1279 1335
@@ -1287,16 +1343,18 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
1287 1343
1288 iee80211_tdls_recalc_chanctx(sdata); 1344 iee80211_tdls_recalc_chanctx(sdata);
1289 1345
1290 rcu_read_lock(); 1346 mutex_lock(&local->sta_mtx);
1291 sta = sta_info_get(sdata, peer); 1347 sta = sta_info_get(sdata, peer);
1292 if (!sta) { 1348 if (!sta) {
1293 rcu_read_unlock(); 1349 mutex_unlock(&local->sta_mtx);
1294 ret = -ENOLINK; 1350 ret = -ENOLINK;
1295 break; 1351 break;
1296 } 1352 }
1297 1353
1354 iee80211_tdls_recalc_ht_protection(sdata, sta);
1355
1298 set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); 1356 set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH);
1299 rcu_read_unlock(); 1357 mutex_unlock(&local->sta_mtx);
1300 1358
1301 WARN_ON_ONCE(is_zero_ether_addr(sdata->u.mgd.tdls_peer) || 1359 WARN_ON_ONCE(is_zero_ether_addr(sdata->u.mgd.tdls_peer) ||
1302 !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)); 1360 !ether_addr_equal(sdata->u.mgd.tdls_peer, peer));
@@ -1318,6 +1376,11 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
1318 ieee80211_flush_queues(local, sdata, false); 1376 ieee80211_flush_queues(local, sdata, false);
1319 1377
1320 ret = sta_info_destroy_addr(sdata, peer); 1378 ret = sta_info_destroy_addr(sdata, peer);
1379
1380 mutex_lock(&local->sta_mtx);
1381 iee80211_tdls_recalc_ht_protection(sdata, NULL);
1382 mutex_unlock(&local->sta_mtx);
1383
1321 iee80211_tdls_recalc_chanctx(sdata); 1384 iee80211_tdls_recalc_chanctx(sdata);
1322 break; 1385 break;
1323 default: 1386 default:
@@ -1335,6 +1398,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
1335 &sdata->u.mgd.request_smps_work); 1398 &sdata->u.mgd.request_smps_work);
1336 1399
1337 mutex_unlock(&local->mtx); 1400 mutex_unlock(&local->mtx);
1401 sdata_unlock(sdata);
1338 return ret; 1402 return ret;
1339} 1403}
1340 1404