aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/chan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless/chan.c')
-rw-r--r--net/wireless/chan.c203
1 files changed, 178 insertions, 25 deletions
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 9b8cc877eb19..78559b5bbd1f 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -277,6 +277,32 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy,
277 width, dfs_state); 277 width, dfs_state);
278} 278}
279 279
280static u32 cfg80211_get_start_freq(u32 center_freq,
281 u32 bandwidth)
282{
283 u32 start_freq;
284
285 if (bandwidth <= 20)
286 start_freq = center_freq;
287 else
288 start_freq = center_freq - bandwidth/2 + 10;
289
290 return start_freq;
291}
292
293static u32 cfg80211_get_end_freq(u32 center_freq,
294 u32 bandwidth)
295{
296 u32 end_freq;
297
298 if (bandwidth <= 20)
299 end_freq = center_freq;
300 else
301 end_freq = center_freq + bandwidth/2 - 10;
302
303 return end_freq;
304}
305
280static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy, 306static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
281 u32 center_freq, 307 u32 center_freq,
282 u32 bandwidth) 308 u32 bandwidth)
@@ -284,13 +310,8 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
284 struct ieee80211_channel *c; 310 struct ieee80211_channel *c;
285 u32 freq, start_freq, end_freq; 311 u32 freq, start_freq, end_freq;
286 312
287 if (bandwidth <= 20) { 313 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
288 start_freq = center_freq; 314 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
289 end_freq = center_freq;
290 } else {
291 start_freq = center_freq - bandwidth/2 + 10;
292 end_freq = center_freq + bandwidth/2 - 10;
293 }
294 315
295 for (freq = start_freq; freq <= end_freq; freq += 20) { 316 for (freq = start_freq; freq <= end_freq; freq += 20) {
296 c = ieee80211_get_channel(wiphy, freq); 317 c = ieee80211_get_channel(wiphy, freq);
@@ -330,33 +351,159 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
330} 351}
331EXPORT_SYMBOL(cfg80211_chandef_dfs_required); 352EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
332 353
333static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, 354static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
334 u32 center_freq, u32 bandwidth, 355 u32 center_freq,
335 u32 prohibited_flags) 356 u32 bandwidth)
336{ 357{
337 struct ieee80211_channel *c; 358 struct ieee80211_channel *c;
338 u32 freq, start_freq, end_freq; 359 u32 freq, start_freq, end_freq;
360 int count = 0;
339 361
340 if (bandwidth <= 20) { 362 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
341 start_freq = center_freq; 363 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
342 end_freq = center_freq; 364
343 } else { 365 /*
344 start_freq = center_freq - bandwidth/2 + 10; 366 * Check entire range of channels for the bandwidth.
345 end_freq = center_freq + bandwidth/2 - 10; 367 * Check all channels are DFS channels (DFS_USABLE or
368 * DFS_AVAILABLE). Return number of usable channels
369 * (require CAC). Allow DFS and non-DFS channel mix.
370 */
371 for (freq = start_freq; freq <= end_freq; freq += 20) {
372 c = ieee80211_get_channel(wiphy, freq);
373 if (!c)
374 return -EINVAL;
375
376 if (c->flags & IEEE80211_CHAN_DISABLED)
377 return -EINVAL;
378
379 if (c->flags & IEEE80211_CHAN_RADAR) {
380 if (c->dfs_state == NL80211_DFS_UNAVAILABLE)
381 return -EINVAL;
382
383 if (c->dfs_state == NL80211_DFS_USABLE)
384 count++;
385 }
346 } 386 }
347 387
388 return count;
389}
390
391bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
392 const struct cfg80211_chan_def *chandef)
393{
394 int width;
395 int r1, r2 = 0;
396
397 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
398 return false;
399
400 width = cfg80211_chandef_get_width(chandef);
401 if (width < 0)
402 return false;
403
404 r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1,
405 width);
406
407 if (r1 < 0)
408 return false;
409
410 switch (chandef->width) {
411 case NL80211_CHAN_WIDTH_80P80:
412 WARN_ON(!chandef->center_freq2);
413 r2 = cfg80211_get_chans_dfs_usable(wiphy,
414 chandef->center_freq2,
415 width);
416 if (r2 < 0)
417 return false;
418 break;
419 default:
420 WARN_ON(chandef->center_freq2);
421 break;
422 }
423
424 return (r1 + r2 > 0);
425}
426
427
428static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
429 u32 center_freq,
430 u32 bandwidth)
431{
432 struct ieee80211_channel *c;
433 u32 freq, start_freq, end_freq;
434
435 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
436 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
437
438 /*
439 * Check entire range of channels for the bandwidth.
440 * If any channel in between is disabled or has not
441 * had gone through CAC return false
442 */
348 for (freq = start_freq; freq <= end_freq; freq += 20) { 443 for (freq = start_freq; freq <= end_freq; freq += 20) {
349 c = ieee80211_get_channel(wiphy, freq); 444 c = ieee80211_get_channel(wiphy, freq);
350 if (!c) 445 if (!c)
351 return false; 446 return false;
352 447
353 /* check for radar flags */ 448 if (c->flags & IEEE80211_CHAN_DISABLED)
354 if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) && 449 return false;
450
451 if ((c->flags & IEEE80211_CHAN_RADAR) &&
355 (c->dfs_state != NL80211_DFS_AVAILABLE)) 452 (c->dfs_state != NL80211_DFS_AVAILABLE))
356 return false; 453 return false;
454 }
455
456 return true;
457}
458
459static bool cfg80211_chandef_dfs_available(struct wiphy *wiphy,
460 const struct cfg80211_chan_def *chandef)
461{
462 int width;
463 int r;
464
465 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
466 return false;
467
468 width = cfg80211_chandef_get_width(chandef);
469 if (width < 0)
470 return false;
471
472 r = cfg80211_get_chans_dfs_available(wiphy, chandef->center_freq1,
473 width);
474
475 /* If any of channels unavailable for cf1 just return */
476 if (!r)
477 return r;
478
479 switch (chandef->width) {
480 case NL80211_CHAN_WIDTH_80P80:
481 WARN_ON(!chandef->center_freq2);
482 r = cfg80211_get_chans_dfs_available(wiphy,
483 chandef->center_freq2,
484 width);
485 default:
486 WARN_ON(chandef->center_freq2);
487 break;
488 }
489
490 return r;
491}
357 492
358 /* check for the other flags */ 493
359 if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR) 494static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
495 u32 center_freq, u32 bandwidth,
496 u32 prohibited_flags)
497{
498 struct ieee80211_channel *c;
499 u32 freq, start_freq, end_freq;
500
501 start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
502 end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
503
504 for (freq = start_freq; freq <= end_freq; freq += 20) {
505 c = ieee80211_get_channel(wiphy, freq);
506 if (!c || c->flags & prohibited_flags)
360 return false; 507 return false;
361 } 508 }
362 509
@@ -462,14 +609,19 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
462 struct cfg80211_chan_def *chandef) 609 struct cfg80211_chan_def *chandef)
463{ 610{
464 bool res; 611 bool res;
612 u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
613 IEEE80211_CHAN_NO_IR |
614 IEEE80211_CHAN_RADAR;
465 615
466 trace_cfg80211_reg_can_beacon(wiphy, chandef); 616 trace_cfg80211_reg_can_beacon(wiphy, chandef);
467 617
468 res = cfg80211_chandef_usable(wiphy, chandef, 618 if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 &&
469 IEEE80211_CHAN_DISABLED | 619 cfg80211_chandef_dfs_available(wiphy, chandef)) {
470 IEEE80211_CHAN_PASSIVE_SCAN | 620 /* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
471 IEEE80211_CHAN_NO_IBSS | 621 prohibited_flags = IEEE80211_CHAN_DISABLED;
472 IEEE80211_CHAN_RADAR); 622 }
623
624 res = cfg80211_chandef_usable(wiphy, chandef, prohibited_flags);
473 625
474 trace_cfg80211_return_bool(res); 626 trace_cfg80211_return_bool(res);
475 return res; 627 return res;
@@ -510,6 +662,7 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
510 : CHAN_MODE_EXCLUSIVE; 662 : CHAN_MODE_EXCLUSIVE;
511 return; 663 return;
512 } 664 }
665 break;
513 case NL80211_IFTYPE_STATION: 666 case NL80211_IFTYPE_STATION:
514 case NL80211_IFTYPE_P2P_CLIENT: 667 case NL80211_IFTYPE_P2P_CLIENT:
515 if (wdev->current_bss) { 668 if (wdev->current_bss) {