aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h21
-rw-r--r--net/wireless/chan.c92
-rw-r--r--net/wireless/core.h6
-rw-r--r--net/wireless/nl80211.c38
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
61struct 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 */
396bool 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 */
404bool 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 */
1049struct 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}
45EXPORT_SYMBOL(cfg80211_chandef_create); 45EXPORT_SYMBOL(cfg80211_chandef_create);
46 46
47bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef) 47bool 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}
108EXPORT_SYMBOL(cfg80211_chandef_valid);
108 109
109static void chandef_primary_freqs(const struct cfg80211_chan_def *c, 110static 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}
188EXPORT_SYMBOL(cfg80211_chandef_compatible); 189EXPORT_SYMBOL(cfg80211_chandef_compatible);
189 190
190bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, 191static 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
208static bool cfg80211_check_beacon_chans(struct wiphy *wiphy, 209bool 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
218bool 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}
277EXPORT_SYMBOL(cfg80211_chandef_usable);
278
279bool 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,
483void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, 483void 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
486bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef);
487
488bool 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)
1841static int nl80211_send_chandef(struct sk_buff *msg, 1811static 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))