diff options
Diffstat (limited to 'net/wireless/core.c')
-rw-r--r-- | net/wireless/core.c | 106 |
1 files changed, 105 insertions, 1 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c index fe01de29bfe8..c22ef3492ee6 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -46,6 +46,11 @@ static struct dentry *ieee80211_debugfs_dir; | |||
46 | /* for the cleanup, scan and event works */ | 46 | /* for the cleanup, scan and event works */ |
47 | struct workqueue_struct *cfg80211_wq; | 47 | struct workqueue_struct *cfg80211_wq; |
48 | 48 | ||
49 | static bool cfg80211_disable_40mhz_24ghz; | ||
50 | module_param(cfg80211_disable_40mhz_24ghz, bool, 0644); | ||
51 | MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz, | ||
52 | "Disable 40MHz support in the 2.4GHz band"); | ||
53 | |||
49 | /* requires cfg80211_mutex to be held! */ | 54 | /* requires cfg80211_mutex to be held! */ |
50 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) | 55 | struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx) |
51 | { | 56 | { |
@@ -365,7 +370,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
365 | spin_lock_init(&rdev->bss_lock); | 370 | spin_lock_init(&rdev->bss_lock); |
366 | INIT_LIST_HEAD(&rdev->bss_list); | 371 | INIT_LIST_HEAD(&rdev->bss_list); |
367 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); | 372 | INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); |
368 | 373 | INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); | |
369 | #ifdef CONFIG_CFG80211_WEXT | 374 | #ifdef CONFIG_CFG80211_WEXT |
370 | rdev->wiphy.wext = &cfg80211_wext_handler; | 375 | rdev->wiphy.wext = &cfg80211_wext_handler; |
371 | #endif | 376 | #endif |
@@ -411,6 +416,67 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) | |||
411 | } | 416 | } |
412 | EXPORT_SYMBOL(wiphy_new); | 417 | EXPORT_SYMBOL(wiphy_new); |
413 | 418 | ||
419 | static int wiphy_verify_combinations(struct wiphy *wiphy) | ||
420 | { | ||
421 | const struct ieee80211_iface_combination *c; | ||
422 | int i, j; | ||
423 | |||
424 | /* If we have combinations enforce them */ | ||
425 | if (wiphy->n_iface_combinations) | ||
426 | wiphy->flags |= WIPHY_FLAG_ENFORCE_COMBINATIONS; | ||
427 | |||
428 | for (i = 0; i < wiphy->n_iface_combinations; i++) { | ||
429 | u32 cnt = 0; | ||
430 | u16 all_iftypes = 0; | ||
431 | |||
432 | c = &wiphy->iface_combinations[i]; | ||
433 | |||
434 | /* Combinations with just one interface aren't real */ | ||
435 | if (WARN_ON(c->max_interfaces < 2)) | ||
436 | return -EINVAL; | ||
437 | |||
438 | /* Need at least one channel */ | ||
439 | if (WARN_ON(!c->num_different_channels)) | ||
440 | return -EINVAL; | ||
441 | |||
442 | if (WARN_ON(!c->n_limits)) | ||
443 | return -EINVAL; | ||
444 | |||
445 | for (j = 0; j < c->n_limits; j++) { | ||
446 | u16 types = c->limits[j].types; | ||
447 | |||
448 | /* | ||
449 | * interface types shouldn't overlap, this is | ||
450 | * used in cfg80211_can_change_interface() | ||
451 | */ | ||
452 | if (WARN_ON(types & all_iftypes)) | ||
453 | return -EINVAL; | ||
454 | all_iftypes |= types; | ||
455 | |||
456 | if (WARN_ON(!c->limits[j].max)) | ||
457 | return -EINVAL; | ||
458 | |||
459 | /* Shouldn't list software iftypes in combinations! */ | ||
460 | if (WARN_ON(wiphy->software_iftypes & types)) | ||
461 | return -EINVAL; | ||
462 | |||
463 | cnt += c->limits[j].max; | ||
464 | /* | ||
465 | * Don't advertise an unsupported type | ||
466 | * in a combination. | ||
467 | */ | ||
468 | if (WARN_ON((wiphy->interface_modes & types) != types)) | ||
469 | return -EINVAL; | ||
470 | } | ||
471 | |||
472 | /* You can't even choose that many! */ | ||
473 | if (WARN_ON(cnt < c->max_interfaces)) | ||
474 | return -EINVAL; | ||
475 | } | ||
476 | |||
477 | return 0; | ||
478 | } | ||
479 | |||
414 | int wiphy_register(struct wiphy *wiphy) | 480 | int wiphy_register(struct wiphy *wiphy) |
415 | { | 481 | { |
416 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | 482 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
@@ -439,6 +505,10 @@ int wiphy_register(struct wiphy *wiphy) | |||
439 | if (WARN_ON(ifmodes != wiphy->interface_modes)) | 505 | if (WARN_ON(ifmodes != wiphy->interface_modes)) |
440 | wiphy->interface_modes = ifmodes; | 506 | wiphy->interface_modes = ifmodes; |
441 | 507 | ||
508 | res = wiphy_verify_combinations(wiphy); | ||
509 | if (res) | ||
510 | return res; | ||
511 | |||
442 | /* sanity check supported bands/channels */ | 512 | /* sanity check supported bands/channels */ |
443 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 513 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
444 | sband = wiphy->bands[band]; | 514 | sband = wiphy->bands[band]; |
@@ -451,6 +521,18 @@ int wiphy_register(struct wiphy *wiphy) | |||
451 | return -EINVAL; | 521 | return -EINVAL; |
452 | 522 | ||
453 | /* | 523 | /* |
524 | * Since cfg80211_disable_40mhz_24ghz is global, we can | ||
525 | * modify the sband's ht data even if the driver uses a | ||
526 | * global structure for that. | ||
527 | */ | ||
528 | if (cfg80211_disable_40mhz_24ghz && | ||
529 | band == IEEE80211_BAND_2GHZ && | ||
530 | sband->ht_cap.ht_supported) { | ||
531 | sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
532 | sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; | ||
533 | } | ||
534 | |||
535 | /* | ||
454 | * Since we use a u32 for rate bitmaps in | 536 | * Since we use a u32 for rate bitmaps in |
455 | * ieee80211_get_response_rate, we cannot | 537 | * ieee80211_get_response_rate, we cannot |
456 | * have more than 32 legacy rates. | 538 | * have more than 32 legacy rates. |
@@ -476,6 +558,13 @@ int wiphy_register(struct wiphy *wiphy) | |||
476 | return -EINVAL; | 558 | return -EINVAL; |
477 | } | 559 | } |
478 | 560 | ||
561 | if (rdev->wiphy.wowlan.n_patterns) { | ||
562 | if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || | ||
563 | rdev->wiphy.wowlan.pattern_min_len > | ||
564 | rdev->wiphy.wowlan.pattern_max_len)) | ||
565 | return -EINVAL; | ||
566 | } | ||
567 | |||
479 | /* check and set up bitrates */ | 568 | /* check and set up bitrates */ |
480 | ieee80211_set_bitrate_flags(wiphy); | 569 | ieee80211_set_bitrate_flags(wiphy); |
481 | 570 | ||
@@ -614,6 +703,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) | |||
614 | mutex_destroy(&rdev->devlist_mtx); | 703 | mutex_destroy(&rdev->devlist_mtx); |
615 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) | 704 | list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) |
616 | cfg80211_put_bss(&scan->pub); | 705 | cfg80211_put_bss(&scan->pub); |
706 | cfg80211_rdev_free_wowlan(rdev); | ||
617 | kfree(rdev); | 707 | kfree(rdev); |
618 | } | 708 | } |
619 | 709 | ||
@@ -647,6 +737,11 @@ static void wdev_cleanup_work(struct work_struct *work) | |||
647 | ___cfg80211_scan_done(rdev, true); | 737 | ___cfg80211_scan_done(rdev, true); |
648 | } | 738 | } |
649 | 739 | ||
740 | if (WARN_ON(rdev->sched_scan_req && | ||
741 | rdev->sched_scan_req->dev == wdev->netdev)) { | ||
742 | __cfg80211_stop_sched_scan(rdev, false); | ||
743 | } | ||
744 | |||
650 | cfg80211_unlock_rdev(rdev); | 745 | cfg80211_unlock_rdev(rdev); |
651 | 746 | ||
652 | mutex_lock(&rdev->devlist_mtx); | 747 | mutex_lock(&rdev->devlist_mtx); |
@@ -668,6 +763,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
668 | struct net_device *dev = ndev; | 763 | struct net_device *dev = ndev; |
669 | struct wireless_dev *wdev = dev->ieee80211_ptr; | 764 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
670 | struct cfg80211_registered_device *rdev; | 765 | struct cfg80211_registered_device *rdev; |
766 | int ret; | ||
671 | 767 | ||
672 | if (!wdev) | 768 | if (!wdev) |
673 | return NOTIFY_DONE; | 769 | return NOTIFY_DONE; |
@@ -734,6 +830,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
734 | break; | 830 | break; |
735 | case NL80211_IFTYPE_P2P_CLIENT: | 831 | case NL80211_IFTYPE_P2P_CLIENT: |
736 | case NL80211_IFTYPE_STATION: | 832 | case NL80211_IFTYPE_STATION: |
833 | cfg80211_lock_rdev(rdev); | ||
834 | __cfg80211_stop_sched_scan(rdev, false); | ||
835 | cfg80211_unlock_rdev(rdev); | ||
836 | |||
737 | wdev_lock(wdev); | 837 | wdev_lock(wdev); |
738 | #ifdef CONFIG_CFG80211_WEXT | 838 | #ifdef CONFIG_CFG80211_WEXT |
739 | kfree(wdev->wext.ie); | 839 | kfree(wdev->wext.ie); |
@@ -752,6 +852,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
752 | default: | 852 | default: |
753 | break; | 853 | break; |
754 | } | 854 | } |
855 | wdev->beacon_interval = 0; | ||
755 | break; | 856 | break; |
756 | case NETDEV_DOWN: | 857 | case NETDEV_DOWN: |
757 | dev_hold(dev); | 858 | dev_hold(dev); |
@@ -858,6 +959,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
858 | return notifier_from_errno(-EOPNOTSUPP); | 959 | return notifier_from_errno(-EOPNOTSUPP); |
859 | if (rfkill_blocked(rdev->rfkill)) | 960 | if (rfkill_blocked(rdev->rfkill)) |
860 | return notifier_from_errno(-ERFKILL); | 961 | return notifier_from_errno(-ERFKILL); |
962 | ret = cfg80211_can_add_interface(rdev, wdev->iftype); | ||
963 | if (ret) | ||
964 | return notifier_from_errno(ret); | ||
861 | break; | 965 | break; |
862 | } | 966 | } |
863 | 967 | ||