diff options
-rw-r--r-- | include/net/cfg80211.h | 21 | ||||
-rw-r--r-- | net/wireless/chan.c | 92 | ||||
-rw-r--r-- | net/wireless/core.h | 6 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 38 |
4 files changed, 85 insertions, 72 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e78db2cf3d1b..a238f41e55c2 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -58,6 +58,8 @@ | |||
58 | * structures here describe these capabilities in detail. | 58 | * structures here describe these capabilities in detail. |
59 | */ | 59 | */ |
60 | 60 | ||
61 | struct wiphy; | ||
62 | |||
61 | /* | 63 | /* |
62 | * wireless hardware capability structures | 64 | * wireless hardware capability structures |
63 | */ | 65 | */ |
@@ -388,6 +390,22 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1, | |||
388 | const struct cfg80211_chan_def *chandef2); | 390 | const struct cfg80211_chan_def *chandef2); |
389 | 391 | ||
390 | /** | 392 | /** |
393 | * cfg80211_chandef_valid - check if a channel definition is valid | ||
394 | * @chandef: the channel definition to check | ||
395 | */ | ||
396 | bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef); | ||
397 | |||
398 | /** | ||
399 | * cfg80211_chandef_usable - check if secondary channels can be used | ||
400 | * @wiphy: the wiphy to validate against | ||
401 | * @chandef: the channel definition to check | ||
402 | * @prohibited_flags: the regulatory chanenl flags that must not be set | ||
403 | */ | ||
404 | bool cfg80211_chandef_usable(struct wiphy *wiphy, | ||
405 | const struct cfg80211_chan_def *chandef, | ||
406 | u32 prohibited_flags); | ||
407 | |||
408 | /** | ||
391 | * enum survey_info_flags - survey information flags | 409 | * enum survey_info_flags - survey information flags |
392 | * | 410 | * |
393 | * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in | 411 | * @SURVEY_INFO_NOISE_DBM: noise (in dBm) was filled in |
@@ -1045,9 +1063,6 @@ struct ieee80211_txq_params { | |||
1045 | u8 aifs; | 1063 | u8 aifs; |
1046 | }; | 1064 | }; |
1047 | 1065 | ||
1048 | /* from net/wireless.h */ | ||
1049 | struct wiphy; | ||
1050 | |||
1051 | /** | 1066 | /** |
1052 | * DOC: Scanning and BSS list handling | 1067 | * DOC: Scanning and BSS list handling |
1053 | * | 1068 | * |
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index bf2dfd54ff3b..b5f69831e318 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -44,7 +44,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef, | |||
44 | } | 44 | } |
45 | EXPORT_SYMBOL(cfg80211_chandef_create); | 45 | EXPORT_SYMBOL(cfg80211_chandef_create); |
46 | 46 | ||
47 | bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef) | 47 | bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) |
48 | { | 48 | { |
49 | u32 control_freq; | 49 | u32 control_freq; |
50 | 50 | ||
@@ -105,6 +105,7 @@ bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef) | |||
105 | 105 | ||
106 | return true; | 106 | return true; |
107 | } | 107 | } |
108 | EXPORT_SYMBOL(cfg80211_chandef_valid); | ||
108 | 109 | ||
109 | static void chandef_primary_freqs(const struct cfg80211_chan_def *c, | 110 | static void chandef_primary_freqs(const struct cfg80211_chan_def *c, |
110 | int *pri40, int *pri80) | 111 | int *pri40, int *pri80) |
@@ -187,9 +188,9 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, | |||
187 | } | 188 | } |
188 | EXPORT_SYMBOL(cfg80211_chandef_compatible); | 189 | EXPORT_SYMBOL(cfg80211_chandef_compatible); |
189 | 190 | ||
190 | bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | 191 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, |
191 | u32 center_freq, u32 bandwidth, | 192 | u32 center_freq, u32 bandwidth, |
192 | u32 prohibited_flags) | 193 | u32 prohibited_flags) |
193 | { | 194 | { |
194 | struct ieee80211_channel *c; | 195 | struct ieee80211_channel *c; |
195 | u32 freq; | 196 | u32 freq; |
@@ -205,55 +206,88 @@ bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | |||
205 | return true; | 206 | return true; |
206 | } | 207 | } |
207 | 208 | ||
208 | static bool cfg80211_check_beacon_chans(struct wiphy *wiphy, | 209 | bool cfg80211_chandef_usable(struct wiphy *wiphy, |
209 | u32 center_freq, u32 bw) | 210 | const struct cfg80211_chan_def *chandef, |
211 | u32 prohibited_flags) | ||
210 | { | 212 | { |
211 | return cfg80211_secondary_chans_ok(wiphy, center_freq, bw, | 213 | struct ieee80211_sta_ht_cap *ht_cap; |
212 | IEEE80211_CHAN_DISABLED | | 214 | struct ieee80211_sta_vht_cap *vht_cap; |
213 | IEEE80211_CHAN_PASSIVE_SCAN | | 215 | u32 width, control_freq; |
214 | IEEE80211_CHAN_NO_IBSS | | ||
215 | IEEE80211_CHAN_RADAR); | ||
216 | } | ||
217 | 216 | ||
218 | bool cfg80211_reg_can_beacon(struct wiphy *wiphy, | 217 | if (WARN_ON(!cfg80211_chandef_valid(chandef))) |
219 | struct cfg80211_chan_def *chandef) | 218 | return false; |
220 | { | ||
221 | u32 width; | ||
222 | bool res; | ||
223 | 219 | ||
224 | trace_cfg80211_reg_can_beacon(wiphy, chandef); | 220 | ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap; |
221 | vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap; | ||
225 | 222 | ||
226 | if (WARN_ON(!cfg80211_chan_def_valid(chandef))) { | 223 | control_freq = chandef->chan->center_freq; |
227 | trace_cfg80211_return_bool(false); | ||
228 | return false; | ||
229 | } | ||
230 | 224 | ||
231 | switch (chandef->width) { | 225 | switch (chandef->width) { |
232 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
233 | case NL80211_CHAN_WIDTH_20: | 226 | case NL80211_CHAN_WIDTH_20: |
227 | if (!ht_cap->ht_supported) | ||
228 | return false; | ||
229 | case NL80211_CHAN_WIDTH_20_NOHT: | ||
234 | width = 20; | 230 | width = 20; |
235 | break; | 231 | break; |
236 | case NL80211_CHAN_WIDTH_40: | 232 | case NL80211_CHAN_WIDTH_40: |
237 | width = 40; | 233 | width = 40; |
234 | if (!ht_cap->ht_supported) | ||
235 | return false; | ||
236 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | ||
237 | ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) | ||
238 | return false; | ||
239 | if (chandef->center_freq1 < control_freq && | ||
240 | chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | ||
241 | return false; | ||
242 | if (chandef->center_freq1 > control_freq && | ||
243 | chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
244 | return false; | ||
238 | break; | 245 | break; |
239 | case NL80211_CHAN_WIDTH_80: | ||
240 | case NL80211_CHAN_WIDTH_80P80: | 246 | case NL80211_CHAN_WIDTH_80P80: |
247 | if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) | ||
248 | return false; | ||
249 | case NL80211_CHAN_WIDTH_80: | ||
250 | if (!vht_cap->vht_supported) | ||
251 | return false; | ||
241 | width = 80; | 252 | width = 80; |
242 | break; | 253 | break; |
243 | case NL80211_CHAN_WIDTH_160: | 254 | case NL80211_CHAN_WIDTH_160: |
255 | if (!vht_cap->vht_supported) | ||
256 | return false; | ||
257 | if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)) | ||
258 | return false; | ||
244 | width = 160; | 259 | width = 160; |
245 | break; | 260 | break; |
246 | default: | 261 | default: |
247 | WARN_ON_ONCE(1); | 262 | WARN_ON_ONCE(1); |
248 | trace_cfg80211_return_bool(false); | ||
249 | return false; | 263 | return false; |
250 | } | 264 | } |
251 | 265 | ||
252 | res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq1, width); | 266 | /* TODO: missing regulatory check on 80/160 bandwidth */ |
267 | |||
268 | if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1, | ||
269 | width, prohibited_flags)) | ||
270 | return false; | ||
271 | |||
272 | if (!chandef->center_freq2) | ||
273 | return true; | ||
274 | return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2, | ||
275 | width, prohibited_flags); | ||
276 | } | ||
277 | EXPORT_SYMBOL(cfg80211_chandef_usable); | ||
278 | |||
279 | bool cfg80211_reg_can_beacon(struct wiphy *wiphy, | ||
280 | struct cfg80211_chan_def *chandef) | ||
281 | { | ||
282 | bool res; | ||
283 | |||
284 | trace_cfg80211_reg_can_beacon(wiphy, chandef); | ||
253 | 285 | ||
254 | if (res && chandef->center_freq2) | 286 | res = cfg80211_chandef_usable(wiphy, chandef, |
255 | res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq2, | 287 | IEEE80211_CHAN_DISABLED | |
256 | width); | 288 | IEEE80211_CHAN_PASSIVE_SCAN | |
289 | IEEE80211_CHAN_NO_IBSS | | ||
290 | IEEE80211_CHAN_RADAR); | ||
257 | 291 | ||
258 | trace_cfg80211_return_bool(res); | 292 | trace_cfg80211_return_bool(res); |
259 | return res; | 293 | return res; |
diff --git a/net/wireless/core.h b/net/wireless/core.h index a0c8decf6a47..6183a0d25b8b 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -483,12 +483,6 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, | |||
483 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, | 483 | void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, |
484 | enum nl80211_iftype iftype, int num); | 484 | enum nl80211_iftype iftype, int num); |
485 | 485 | ||
486 | bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef); | ||
487 | |||
488 | bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | ||
489 | u32 center_freq, u32 bandwidth, | ||
490 | u32 prohibited_flags); | ||
491 | |||
492 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 | 486 | #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 |
493 | 487 | ||
494 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS | 488 | #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index d038fa45ecd1..eb0aa71a02b3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -1420,63 +1420,33 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, | |||
1420 | ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap; | 1420 | ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap; |
1421 | vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap; | 1421 | vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap; |
1422 | 1422 | ||
1423 | if (!cfg80211_chan_def_valid(chandef)) | 1423 | if (!cfg80211_chandef_valid(chandef)) |
1424 | return -EINVAL; | 1424 | return -EINVAL; |
1425 | 1425 | ||
1426 | switch (chandef->width) { | 1426 | switch (chandef->width) { |
1427 | case NL80211_CHAN_WIDTH_20: | 1427 | case NL80211_CHAN_WIDTH_20: |
1428 | if (!ht_cap->ht_supported) | ||
1429 | return -EINVAL; | ||
1430 | case NL80211_CHAN_WIDTH_20_NOHT: | 1428 | case NL80211_CHAN_WIDTH_20_NOHT: |
1431 | width = 20; | 1429 | width = 20; |
1432 | break; | 1430 | break; |
1433 | case NL80211_CHAN_WIDTH_40: | 1431 | case NL80211_CHAN_WIDTH_40: |
1434 | width = 40; | 1432 | width = 40; |
1435 | /* quick early regulatory check */ | ||
1436 | if (chandef->center_freq1 < control_freq && | ||
1437 | chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | ||
1438 | return -EINVAL; | ||
1439 | if (chandef->center_freq1 > control_freq && | ||
1440 | chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||
1441 | return -EINVAL; | ||
1442 | if (!ht_cap->ht_supported) | ||
1443 | return -EINVAL; | ||
1444 | if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | ||
1445 | ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) | ||
1446 | return -EINVAL; | ||
1447 | break; | 1433 | break; |
1448 | case NL80211_CHAN_WIDTH_80: | 1434 | case NL80211_CHAN_WIDTH_80: |
1449 | width = 80; | 1435 | width = 80; |
1450 | if (!vht_cap->vht_supported) | ||
1451 | return -EINVAL; | ||
1452 | break; | 1436 | break; |
1453 | case NL80211_CHAN_WIDTH_80P80: | 1437 | case NL80211_CHAN_WIDTH_80P80: |
1454 | width = 80; | 1438 | width = 80; |
1455 | if (!vht_cap->vht_supported) | ||
1456 | return -EINVAL; | ||
1457 | if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) | ||
1458 | return -EINVAL; | ||
1459 | break; | 1439 | break; |
1460 | case NL80211_CHAN_WIDTH_160: | 1440 | case NL80211_CHAN_WIDTH_160: |
1461 | width = 160; | 1441 | width = 160; |
1462 | if (!vht_cap->vht_supported) | ||
1463 | return -EINVAL; | ||
1464 | if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ)) | ||
1465 | return -EINVAL; | ||
1466 | break; | 1442 | break; |
1467 | default: | 1443 | default: |
1468 | return -EINVAL; | 1444 | return -EINVAL; |
1469 | } | 1445 | } |
1470 | 1446 | ||
1471 | if (!cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq1, | 1447 | if (!cfg80211_chandef_usable(&rdev->wiphy, chandef, |
1472 | width, IEEE80211_CHAN_DISABLED)) | 1448 | IEEE80211_CHAN_DISABLED)) |
1473 | return -EINVAL; | 1449 | return -EINVAL; |
1474 | if (chandef->center_freq2 && | ||
1475 | !cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq2, | ||
1476 | width, IEEE80211_CHAN_DISABLED)) | ||
1477 | return -EINVAL; | ||
1478 | |||
1479 | /* TODO: missing regulatory check on bandwidth */ | ||
1480 | 1450 | ||
1481 | return 0; | 1451 | return 0; |
1482 | } | 1452 | } |
@@ -1841,7 +1811,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev) | |||
1841 | static int nl80211_send_chandef(struct sk_buff *msg, | 1811 | static int nl80211_send_chandef(struct sk_buff *msg, |
1842 | struct cfg80211_chan_def *chandef) | 1812 | struct cfg80211_chan_def *chandef) |
1843 | { | 1813 | { |
1844 | WARN_ON(!cfg80211_chan_def_valid(chandef)); | 1814 | WARN_ON(!cfg80211_chandef_valid(chandef)); |
1845 | 1815 | ||
1846 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, | 1816 | if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, |
1847 | chandef->chan->center_freq)) | 1817 | chandef->chan->center_freq)) |