aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/chan.c51
-rw-r--r--net/wireless/nl80211.c11
-rw-r--r--net/wireless/reg.c15
-rw-r--r--net/wireless/scan.c12
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
47static 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
47int cfg80211_set_freq(struct cfg80211_registered_device *rdev, 77int 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
5016unlock_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 */
726static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band, 726static 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
790static void handle_band(struct wiphy *wiphy, enum ieee80211_band band) 792static 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
802static bool ignore_reg_update(struct wiphy *wiphy, 806static 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 }
1038out: 1043out:
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}
662EXPORT_SYMBOL(cfg80211_unlink_bss); 662EXPORT_SYMBOL(cfg80211_unlink_bss);
663 663