diff options
author | Arik Nemtsov <arik@wizery.com> | 2015-03-18 02:46:08 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2015-03-30 04:26:36 -0400 |
commit | a38700dd486f3def34cef47d00e2d360a04a7bc8 (patch) | |
tree | 8f2deebf8c3c4b9079f844249f3c5201e989ae74 | |
parent | 3a323d4e17dd5a84f6ad036e6f985d263ca973ed (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.h | 11 | ||||
-rw-r--r-- | net/mac80211/tdls.c | 21 | ||||
-rw-r--r-- | net/wireless/util.c | 129 |
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, | |||
4903 | bool ieee80211_operating_class_to_band(u8 operating_class, | 4903 | bool 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 | */ | ||
4914 | bool 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 | ||
139 | static 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 | |||
139 | static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb) | 157 | static 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 | } |
1315 | EXPORT_SYMBOL(ieee80211_operating_class_to_band); | 1315 | EXPORT_SYMBOL(ieee80211_operating_class_to_band); |
1316 | 1316 | ||
1317 | bool 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 | } | ||
1444 | EXPORT_SYMBOL(ieee80211_chandef_to_operating_class); | ||
1445 | |||
1317 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | 1446 | int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, |
1318 | u32 beacon_int) | 1447 | u32 beacon_int) |
1319 | { | 1448 | { |