diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/chan.c | 51 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 11 | ||||
-rw-r--r-- | net/wireless/reg.c | 15 | ||||
-rw-r--r-- | net/wireless/scan.c | 12 |
4 files changed, 74 insertions, 15 deletions
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index d0c92dddb26b..d8f443b70b08 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -44,6 +44,36 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | |||
44 | return chan; | 44 | return chan; |
45 | } | 45 | } |
46 | 46 | ||
47 | static bool can_beacon_sec_chan(struct wiphy *wiphy, | ||
48 | struct ieee80211_channel *chan, | ||
49 | enum nl80211_channel_type channel_type) | ||
50 | { | ||
51 | struct ieee80211_channel *sec_chan; | ||
52 | int diff; | ||
53 | |||
54 | switch (channel_type) { | ||
55 | case NL80211_CHAN_HT40PLUS: | ||
56 | diff = 20; | ||
57 | case NL80211_CHAN_HT40MINUS: | ||
58 | diff = -20; | ||
59 | default: | ||
60 | return false; | ||
61 | } | ||
62 | |||
63 | sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff); | ||
64 | if (!sec_chan) | ||
65 | return false; | ||
66 | |||
67 | /* we'll need a DFS capability later */ | ||
68 | if (sec_chan->flags & (IEEE80211_CHAN_DISABLED | | ||
69 | IEEE80211_CHAN_PASSIVE_SCAN | | ||
70 | IEEE80211_CHAN_NO_IBSS | | ||
71 | IEEE80211_CHAN_RADAR)) | ||
72 | return false; | ||
73 | |||
74 | return true; | ||
75 | } | ||
76 | |||
47 | int cfg80211_set_freq(struct cfg80211_registered_device *rdev, | 77 | int cfg80211_set_freq(struct cfg80211_registered_device *rdev, |
48 | struct wireless_dev *wdev, int freq, | 78 | struct wireless_dev *wdev, int freq, |
49 | enum nl80211_channel_type channel_type) | 79 | enum nl80211_channel_type channel_type) |
@@ -68,6 +98,27 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev, | |||
68 | if (!chan) | 98 | if (!chan) |
69 | return -EINVAL; | 99 | return -EINVAL; |
70 | 100 | ||
101 | /* Both channels should be able to initiate communication */ | ||
102 | if (wdev && (wdev->iftype == NL80211_IFTYPE_ADHOC || | ||
103 | wdev->iftype == NL80211_IFTYPE_AP || | ||
104 | wdev->iftype == NL80211_IFTYPE_AP_VLAN || | ||
105 | wdev->iftype == NL80211_IFTYPE_MESH_POINT)) { | ||
106 | switch (channel_type) { | ||
107 | case NL80211_CHAN_HT40PLUS: | ||
108 | case NL80211_CHAN_HT40MINUS: | ||
109 | if (!can_beacon_sec_chan(&rdev->wiphy, chan, | ||
110 | channel_type)) { | ||
111 | printk(KERN_DEBUG | ||
112 | "cfg80211: Secondary channel not " | ||
113 | "allowed to initiate communication\n"); | ||
114 | return -EINVAL; | ||
115 | } | ||
116 | break; | ||
117 | default: | ||
118 | break; | ||
119 | } | ||
120 | } | ||
121 | |||
71 | result = rdev->ops->set_channel(&rdev->wiphy, | 122 | result = rdev->ops->set_channel(&rdev->wiphy, |
72 | wdev ? wdev->netdev : NULL, | 123 | wdev ? wdev->netdev : NULL, |
73 | chan, channel_type); | 124 | chan, channel_type); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 37902a54e9c1..9a8cde999955 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -761,11 +761,13 @@ static int nl80211_set_channel(struct sk_buff *skb, struct genl_info *info) | |||
761 | 761 | ||
762 | result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev); | 762 | result = get_rdev_dev_by_info_ifindex(info, &rdev, &netdev); |
763 | if (result) | 763 | if (result) |
764 | goto unlock; | 764 | goto unlock_rtnl; |
765 | 765 | ||
766 | result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); | 766 | result = __nl80211_set_channel(rdev, netdev->ieee80211_ptr, info); |
767 | 767 | ||
768 | unlock: | 768 | dev_put(netdev); |
769 | cfg80211_unlock_rdev(rdev); | ||
770 | unlock_rtnl: | ||
769 | rtnl_unlock(); | 771 | rtnl_unlock(); |
770 | 772 | ||
771 | return result; | 773 | return result; |
@@ -4996,7 +4998,7 @@ static int nl80211_set_cqm_rssi(struct genl_info *info, | |||
4996 | 4998 | ||
4997 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | 4999 | err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); |
4998 | if (err) | 5000 | if (err) |
4999 | goto unlock_rdev; | 5001 | goto unlock_rtnl; |
5000 | 5002 | ||
5001 | wdev = dev->ieee80211_ptr; | 5003 | wdev = dev->ieee80211_ptr; |
5002 | 5004 | ||
@@ -5013,9 +5015,10 @@ static int nl80211_set_cqm_rssi(struct genl_info *info, | |||
5013 | err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, | 5015 | err = rdev->ops->set_cqm_rssi_config(wdev->wiphy, dev, |
5014 | threshold, hysteresis); | 5016 | threshold, hysteresis); |
5015 | 5017 | ||
5016 | unlock_rdev: | 5018 | unlock_rdev: |
5017 | cfg80211_unlock_rdev(rdev); | 5019 | cfg80211_unlock_rdev(rdev); |
5018 | dev_put(dev); | 5020 | dev_put(dev); |
5021 | unlock_rtnl: | ||
5019 | rtnl_unlock(); | 5022 | rtnl_unlock(); |
5020 | 5023 | ||
5021 | return err; | 5024 | return err; |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index f180db0de66c..edccc093e71b 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -723,7 +723,9 @@ EXPORT_SYMBOL(freq_reg_info); | |||
723 | * on the wiphy with the target_bw specified. Then we can simply use | 723 | * on the wiphy with the target_bw specified. Then we can simply use |
724 | * that below for the desired_bw_khz below. | 724 | * that below for the desired_bw_khz below. |
725 | */ | 725 | */ |
726 | static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | 726 | static void handle_channel(struct wiphy *wiphy, |
727 | enum nl80211_reg_initiator initiator, | ||
728 | enum ieee80211_band band, | ||
727 | unsigned int chan_idx) | 729 | unsigned int chan_idx) |
728 | { | 730 | { |
729 | int r; | 731 | int r; |
@@ -787,7 +789,9 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, | |||
787 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); | 789 | chan->max_power = (int) MBM_TO_DBM(power_rule->max_eirp); |
788 | } | 790 | } |
789 | 791 | ||
790 | static void handle_band(struct wiphy *wiphy, enum ieee80211_band band) | 792 | static void handle_band(struct wiphy *wiphy, |
793 | enum ieee80211_band band, | ||
794 | enum nl80211_reg_initiator initiator) | ||
791 | { | 795 | { |
792 | unsigned int i; | 796 | unsigned int i; |
793 | struct ieee80211_supported_band *sband; | 797 | struct ieee80211_supported_band *sband; |
@@ -796,7 +800,7 @@ static void handle_band(struct wiphy *wiphy, enum ieee80211_band band) | |||
796 | sband = wiphy->bands[band]; | 800 | sband = wiphy->bands[band]; |
797 | 801 | ||
798 | for (i = 0; i < sband->n_channels; i++) | 802 | for (i = 0; i < sband->n_channels; i++) |
799 | handle_channel(wiphy, band, i); | 803 | handle_channel(wiphy, initiator, band, i); |
800 | } | 804 | } |
801 | 805 | ||
802 | static bool ignore_reg_update(struct wiphy *wiphy, | 806 | static bool ignore_reg_update(struct wiphy *wiphy, |
@@ -812,6 +816,7 @@ static bool ignore_reg_update(struct wiphy *wiphy, | |||
812 | * desired regulatory domain set | 816 | * desired regulatory domain set |
813 | */ | 817 | */ |
814 | if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && | 818 | if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && |
819 | initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && | ||
815 | !is_world_regdom(last_request->alpha2)) | 820 | !is_world_regdom(last_request->alpha2)) |
816 | return true; | 821 | return true; |
817 | return false; | 822 | return false; |
@@ -1033,7 +1038,7 @@ void wiphy_update_regulatory(struct wiphy *wiphy, | |||
1033 | goto out; | 1038 | goto out; |
1034 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 1039 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
1035 | if (wiphy->bands[band]) | 1040 | if (wiphy->bands[band]) |
1036 | handle_band(wiphy, band); | 1041 | handle_band(wiphy, band, initiator); |
1037 | } | 1042 | } |
1038 | out: | 1043 | out: |
1039 | reg_process_beacons(wiphy); | 1044 | reg_process_beacons(wiphy); |
@@ -1170,7 +1175,7 @@ static int ignore_request(struct wiphy *wiphy, | |||
1170 | return 0; | 1175 | return 0; |
1171 | return -EALREADY; | 1176 | return -EALREADY; |
1172 | } | 1177 | } |
1173 | return REG_INTERSECT; | 1178 | return 0; |
1174 | case NL80211_REGDOM_SET_BY_DRIVER: | 1179 | case NL80211_REGDOM_SET_BY_DRIVER: |
1175 | if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) { | 1180 | if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) { |
1176 | if (regdom_changes(pending_request->alpha2)) | 1181 | if (regdom_changes(pending_request->alpha2)) |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 5ca8c7180141..503ebb86ba18 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -650,14 +650,14 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub) | |||
650 | bss = container_of(pub, struct cfg80211_internal_bss, pub); | 650 | bss = container_of(pub, struct cfg80211_internal_bss, pub); |
651 | 651 | ||
652 | spin_lock_bh(&dev->bss_lock); | 652 | spin_lock_bh(&dev->bss_lock); |
653 | if (!list_empty(&bss->list)) { | ||
654 | list_del_init(&bss->list); | ||
655 | dev->bss_generation++; | ||
656 | rb_erase(&bss->rbn, &dev->bss_tree); | ||
653 | 657 | ||
654 | list_del(&bss->list); | 658 | kref_put(&bss->ref, bss_release); |
655 | dev->bss_generation++; | 659 | } |
656 | rb_erase(&bss->rbn, &dev->bss_tree); | ||
657 | |||
658 | spin_unlock_bh(&dev->bss_lock); | 660 | spin_unlock_bh(&dev->bss_lock); |
659 | |||
660 | kref_put(&bss->ref, bss_release); | ||
661 | } | 661 | } |
662 | EXPORT_SYMBOL(cfg80211_unlink_bss); | 662 | EXPORT_SYMBOL(cfg80211_unlink_bss); |
663 | 663 | ||