aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2015-03-18 02:46:08 -0400
committerJohannes Berg <johannes.berg@intel.com>2015-03-30 04:26:36 -0400
commita38700dd486f3def34cef47d00e2d360a04a7bc8 (patch)
tree8f2deebf8c3c4b9079f844249f3c5201e989ae74
parent3a323d4e17dd5a84f6ad036e6f985d263ca973ed (diff)
cfg/mac80211: add regulatory classes IE during TDLS setup
Seems Broadcom TDLS peers (Nexus 5, Xperia Z3) refuse to allow TDLS connection when channel-switching is supported but the regulatory classes IE is missing from the setup request. Add a chandef to reg-class translation function to cfg80211 and use it to add the required IE during setup. For now add only the current regulatory class as supported - it is enough to resolve the compatibility issue. Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/net/cfg80211.h11
-rw-r--r--net/mac80211/tdls.c21
-rw-r--r--net/wireless/util.c129
3 files changed, 161 insertions, 0 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 12a6121ea76e..c4d873b8f32d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4903,6 +4903,17 @@ void cfg80211_ch_switch_started_notify(struct net_device *dev,
4903bool ieee80211_operating_class_to_band(u8 operating_class, 4903bool ieee80211_operating_class_to_band(u8 operating_class,
4904 enum ieee80211_band *band); 4904 enum ieee80211_band *band);
4905 4905
4906/**
4907 * ieee80211_chandef_to_operating_class - convert chandef to operation class
4908 *
4909 * @chandef: the chandef to convert
4910 * @op_class: a pointer to the resulting operating class
4911 *
4912 * Returns %true if the conversion was successful, %false otherwise.
4913 */
4914bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
4915 u8 *op_class);
4916
4906/* 4917/*
4907 * cfg80211_tdls_oper_request - request userspace to perform TDLS operation 4918 * cfg80211_tdls_oper_request - request userspace to perform TDLS operation
4908 * @dev: the device on which the operation is requested 4919 * @dev: the device on which the operation is requested
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index bc7e4049896f..79ed59acf0d4 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -136,6 +136,24 @@ ieee80211_tdls_add_supp_channels(struct ieee80211_sub_if_data *sdata,
136 *pos = 2 * subband_cnt; 136 *pos = 2 * subband_cnt;
137} 137}
138 138
139static void ieee80211_tdls_add_oper_classes(struct ieee80211_sub_if_data *sdata,
140 struct sk_buff *skb)
141{
142 u8 *pos;
143 u8 op_class;
144
145 if (!ieee80211_chandef_to_operating_class(&sdata->vif.bss_conf.chandef,
146 &op_class))
147 return;
148
149 pos = skb_put(skb, 4);
150 *pos++ = WLAN_EID_SUPPORTED_REGULATORY_CLASSES;
151 *pos++ = 2; /* len */
152
153 *pos++ = op_class;
154 *pos++ = op_class; /* give current operating class as alternate too */
155}
156
139static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb) 157static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb)
140{ 158{
141 u8 *pos = (void *)skb_put(skb, 3); 159 u8 *pos = (void *)skb_put(skb, 3);
@@ -350,6 +368,8 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata,
350 } 368 }
351 } 369 }
352 370
371 ieee80211_tdls_add_oper_classes(sdata, skb);
372
353 /* 373 /*
354 * with TDLS we can switch channels, and HT-caps are not necessarily 374 * with TDLS we can switch channels, and HT-caps are not necessarily
355 * the same on all bands. The specification limits the setup to a 375 * the same on all bands. The specification limits the setup to a
@@ -786,6 +806,7 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata,
786 50 + /* supported channels */ 806 50 + /* supported channels */
787 3 + /* 40/20 BSS coex */ 807 3 + /* 40/20 BSS coex */
788 4 + /* AID */ 808 4 + /* AID */
809 4 + /* oper classes */
789 extra_ies_len + 810 extra_ies_len +
790 sizeof(struct ieee80211_tdls_lnkie)); 811 sizeof(struct ieee80211_tdls_lnkie));
791 if (!skb) 812 if (!skb)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index f7b35980af69..f218b151530a 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1314,6 +1314,135 @@ bool ieee80211_operating_class_to_band(u8 operating_class,
1314} 1314}
1315EXPORT_SYMBOL(ieee80211_operating_class_to_band); 1315EXPORT_SYMBOL(ieee80211_operating_class_to_band);
1316 1316
1317bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
1318 u8 *op_class)
1319{
1320 u8 vht_opclass;
1321 u16 freq = chandef->center_freq1;
1322
1323 if (freq >= 2412 && freq <= 2472) {
1324 if (chandef->width > NL80211_CHAN_WIDTH_40)
1325 return false;
1326
1327 /* 2.407 GHz, channels 1..13 */
1328 if (chandef->width == NL80211_CHAN_WIDTH_40) {
1329 if (freq > chandef->chan->center_freq)
1330 *op_class = 83; /* HT40+ */
1331 else
1332 *op_class = 84; /* HT40- */
1333 } else {
1334 *op_class = 81;
1335 }
1336
1337 return true;
1338 }
1339
1340 if (freq == 2484) {
1341 if (chandef->width > NL80211_CHAN_WIDTH_40)
1342 return false;
1343
1344 *op_class = 82; /* channel 14 */
1345 return true;
1346 }
1347
1348 switch (chandef->width) {
1349 case NL80211_CHAN_WIDTH_80:
1350 vht_opclass = 128;
1351 break;
1352 case NL80211_CHAN_WIDTH_160:
1353 vht_opclass = 129;
1354 break;
1355 case NL80211_CHAN_WIDTH_80P80:
1356 vht_opclass = 130;
1357 break;
1358 case NL80211_CHAN_WIDTH_10:
1359 case NL80211_CHAN_WIDTH_5:
1360 return false; /* unsupported for now */
1361 default:
1362 vht_opclass = 0;
1363 break;
1364 }
1365
1366 /* 5 GHz, channels 36..48 */
1367 if (freq >= 5180 && freq <= 5240) {
1368 if (vht_opclass) {
1369 *op_class = vht_opclass;
1370 } else if (chandef->width == NL80211_CHAN_WIDTH_40) {
1371 if (freq > chandef->chan->center_freq)
1372 *op_class = 116;
1373 else
1374 *op_class = 117;
1375 } else {
1376 *op_class = 115;
1377 }
1378
1379 return true;
1380 }
1381
1382 /* 5 GHz, channels 52..64 */
1383 if (freq >= 5260 && freq <= 5320) {
1384 if (vht_opclass) {
1385 *op_class = vht_opclass;
1386 } else if (chandef->width == NL80211_CHAN_WIDTH_40) {
1387 if (freq > chandef->chan->center_freq)
1388 *op_class = 119;
1389 else
1390 *op_class = 120;
1391 } else {
1392 *op_class = 118;
1393 }
1394
1395 return true;
1396 }
1397
1398 /* 5 GHz, channels 100..144 */
1399 if (freq >= 5500 && freq <= 5720) {
1400 if (vht_opclass) {
1401 *op_class = vht_opclass;
1402 } else if (chandef->width == NL80211_CHAN_WIDTH_40) {
1403 if (freq > chandef->chan->center_freq)
1404 *op_class = 122;
1405 else
1406 *op_class = 123;
1407 } else {
1408 *op_class = 121;
1409 }
1410
1411 return true;
1412 }
1413
1414 /* 5 GHz, channels 149..169 */
1415 if (freq >= 5745 && freq <= 5845) {
1416 if (vht_opclass) {
1417 *op_class = vht_opclass;
1418 } else if (chandef->width == NL80211_CHAN_WIDTH_40) {
1419 if (freq > chandef->chan->center_freq)
1420 *op_class = 126;
1421 else
1422 *op_class = 127;
1423 } else if (freq <= 5805) {
1424 *op_class = 124;
1425 } else {
1426 *op_class = 125;
1427 }
1428
1429 return true;
1430 }
1431
1432 /* 56.16 GHz, channel 1..4 */
1433 if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
1434 if (chandef->width >= NL80211_CHAN_WIDTH_40)
1435 return false;
1436
1437 *op_class = 180;
1438 return true;
1439 }
1440
1441 /* not supported yet */
1442 return false;
1443}
1444EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
1445
1317int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, 1446int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
1318 u32 beacon_int) 1447 u32 beacon_int)
1319{ 1448{