aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
authorIlan Peer <ilan.peer@intel.com>2014-02-23 02:13:01 -0500
committerJohannes Berg <johannes.berg@intel.com>2014-04-09 04:55:34 -0400
commit174e0cd28af0fe3c6c634c3e4d9e042c683bd7f7 (patch)
tree047a3e0b02e6e5bb41324cd4571ef6251cd5fa79 /net/wireless
parent94fc661f68c881eaa3a5904c12a2269372aa94d9 (diff)
cfg80211: Enable GO operation on additional channels
Allow GO operation on a channel marked with IEEE80211_CHAN_GO_CONCURRENT iff there is an active station interface that is associated to an AP operating on the same channel in the 2 GHz band or the same UNII band (in the 5 GHz band). This relaxation is not allowed if the channel is marked with IEEE80211_CHAN_RADAR. Note that this is a permissive approach to the FCC definitions, that require a clear assessment that the device operating the AP is an authorized master, i.e., with radar detection and DFS capabilities. It is assumed that such restrictions are enforced by user space. Furthermore, it is assumed, that if the conditions that allowed for the operation of the GO on such a channel change, i.e., the station interface disconnected from the AP, it is the responsibility of user space to evacuate the GO from the channel. Signed-off-by: Ilan Peer <ilan.peer@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/wireless')
-rw-r--r--net/wireless/Kconfig24
-rw-r--r--net/wireless/chan.c76
-rw-r--r--net/wireless/mesh.c3
-rw-r--r--net/wireless/nl80211.c11
-rw-r--r--net/wireless/reg.c29
-rw-r--r--net/wireless/reg.h12
-rw-r--r--net/wireless/trace.h11
7 files changed, 154 insertions, 12 deletions
diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig
index 2a891bc6315c..405f3c4cf70c 100644
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -108,6 +108,30 @@ config CFG80211_REG_CELLULAR_HINTS
108 feature if you have tested and validated this feature on your 108 feature if you have tested and validated this feature on your
109 systems. 109 systems.
110 110
111config CFG80211_REG_RELAX_NO_IR
112 bool "cfg80211 support for NO_IR relaxation"
113 depends on CFG80211_CERTIFICATION_ONUS
114 ---help---
115 This option enables support for relaxation of the NO_IR flag for
116 situations that certain regulatory bodies have provided clarifications
117 on how relaxation can occur. This feature has an inherent dependency on
118 userspace features which must have been properly tested and as such is
119 not enabled by default.
120
121 A relaxation feature example is allowing the operation of a P2P group
122 owner (GO) on channels marked with NO_IR if there is an additional BSS
123 interface which associated to an AP which userspace assumes or confirms
124 to be an authorized master, i.e., with radar detection support and DFS
125 capabilities. However, note that in order to not create daisy chain
126 scenarios, this relaxation is not allowed in cases that the BSS client
127 is associated to P2P GO and in addition the P2P GO instantiated on
128 a channel due to this relaxation should not allow connection from
129 non P2P clients.
130
131 The regulatory core will apply these relaxations only for drivers that
132 support this feature by declaring the appropriate channel flags and
133 capabilities in their registration flow.
134
111config CFG80211_DEFAULT_PS 135config CFG80211_DEFAULT_PS
112 bool "enable powersave by default" 136 bool "enable powersave by default"
113 depends on CFG80211 137 depends on CFG80211
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 9c9501a35fb5..50202af7fba3 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -661,15 +661,85 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
661} 661}
662EXPORT_SYMBOL(cfg80211_chandef_usable); 662EXPORT_SYMBOL(cfg80211_chandef_usable);
663 663
664/*
665 * For GO only, check if the channel can be used under permissive conditions
666 * mandated by the some regulatory bodies, i.e., the channel is marked with
667 * IEEE80211_CHAN_GO_CONCURRENT and there is an additional station interface
668 * associated to an AP on the same channel or on the same UNII band
669 * (assuming that the AP is an authorized master).
670 */
671static bool cfg80211_go_permissive_chan(struct cfg80211_registered_device *rdev,
672 struct ieee80211_channel *chan)
673{
674 struct wireless_dev *wdev_iter;
675 struct wiphy *wiphy = wiphy_idx_to_wiphy(rdev->wiphy_idx);
676
677 ASSERT_RTNL();
678
679 if (!config_enabled(CONFIG_CFG80211_REG_RELAX_NO_IR) ||
680 !(wiphy->regulatory_flags & REGULATORY_ENABLE_RELAX_NO_IR) ||
681 !(chan->flags & IEEE80211_CHAN_GO_CONCURRENT))
682 return false;
683
684 /*
685 * Generally, it is possible to rely on another device/driver to allow
686 * the GO concurrent relaxation, however, since the device can further
687 * enforce the relaxation (by doing a similar verifications as this),
688 * and thus fail the GO instantiation, consider only the interfaces of
689 * the current registered device.
690 */
691 list_for_each_entry(wdev_iter, &rdev->wdev_list, list) {
692 struct ieee80211_channel *other_chan = NULL;
693 int r1, r2;
694
695 if (wdev_iter->iftype != NL80211_IFTYPE_STATION ||
696 !netif_running(wdev_iter->netdev))
697 continue;
698
699 wdev_lock(wdev_iter);
700 if (wdev_iter->current_bss)
701 other_chan = wdev_iter->current_bss->pub.channel;
702 wdev_unlock(wdev_iter);
703
704 if (!other_chan)
705 continue;
706
707 if (chan == other_chan)
708 return true;
709
710 if (chan->band != IEEE80211_BAND_5GHZ)
711 continue;
712
713 r1 = cfg80211_get_unii(chan->center_freq);
714 r2 = cfg80211_get_unii(other_chan->center_freq);
715
716 if (r1 != -EINVAL && r1 == r2)
717 return true;
718 }
719
720 return false;
721}
722
664bool cfg80211_reg_can_beacon(struct wiphy *wiphy, 723bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
665 struct cfg80211_chan_def *chandef) 724 struct cfg80211_chan_def *chandef,
725 enum nl80211_iftype iftype)
666{ 726{
727 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
667 bool res; 728 bool res;
668 u32 prohibited_flags = IEEE80211_CHAN_DISABLED | 729 u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
669 IEEE80211_CHAN_NO_IR |
670 IEEE80211_CHAN_RADAR; 730 IEEE80211_CHAN_RADAR;
671 731
672 trace_cfg80211_reg_can_beacon(wiphy, chandef); 732 trace_cfg80211_reg_can_beacon(wiphy, chandef, iftype);
733
734 /*
735 * Under certain conditions suggested by the some regulatory bodies
736 * a GO can operate on channels marked with IEEE80211_NO_IR
737 * so set this flag only if such relaxations are not enabled and
738 * the conditions are not met.
739 */
740 if (iftype != NL80211_IFTYPE_P2P_GO ||
741 !cfg80211_go_permissive_chan(rdev, chandef->chan))
742 prohibited_flags |= IEEE80211_CHAN_NO_IR;
673 743
674 if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 && 744 if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 &&
675 cfg80211_chandef_dfs_available(wiphy, chandef)) { 745 cfg80211_chandef_dfs_available(wiphy, chandef)) {
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 5af5cc6b2c4c..7031ee0afad8 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -175,7 +175,8 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
175 scan_width); 175 scan_width);
176 } 176 }
177 177
178 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef)) 178 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef,
179 NL80211_IFTYPE_MESH_POINT))
179 return -EINVAL; 180 return -EINVAL;
180 181
181 err = cfg80211_chandef_dfs_required(wdev->wiphy, &setup->chandef); 182 err = cfg80211_chandef_dfs_required(wdev->wiphy, &setup->chandef);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c5ead18ad3ab..b8d81e41b0f7 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1939,7 +1939,7 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
1939 result = -EBUSY; 1939 result = -EBUSY;
1940 break; 1940 break;
1941 } 1941 }
1942 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef)) { 1942 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef, iftype)) {
1943 result = -EINVAL; 1943 result = -EINVAL;
1944 break; 1944 break;
1945 } 1945 }
@@ -3271,7 +3271,8 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
3271 } else if (!nl80211_get_ap_channel(rdev, &params)) 3271 } else if (!nl80211_get_ap_channel(rdev, &params))
3272 return -EINVAL; 3272 return -EINVAL;
3273 3273
3274 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef)) 3274 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
3275 wdev->iftype))
3275 return -EINVAL; 3276 return -EINVAL;
3276 3277
3277 err = cfg80211_chandef_dfs_required(wdev->wiphy, &params.chandef); 3278 err = cfg80211_chandef_dfs_required(wdev->wiphy, &params.chandef);
@@ -5941,7 +5942,8 @@ skip_beacons:
5941 if (err) 5942 if (err)
5942 return err; 5943 return err;
5943 5944
5944 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef)) 5945 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef,
5946 wdev->iftype))
5945 return -EINVAL; 5947 return -EINVAL;
5946 5948
5947 switch (dev->ieee80211_ptr->iftype) { 5949 switch (dev->ieee80211_ptr->iftype) {
@@ -6717,7 +6719,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
6717 if (err) 6719 if (err)
6718 return err; 6720 return err;
6719 6721
6720 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef)) 6722 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
6723 NL80211_IFTYPE_ADHOC))
6721 return -EINVAL; 6724 return -EINVAL;
6722 6725
6723 switch (ibss.chandef.width) { 6726 switch (ibss.chandef.width) {
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 2b8c1000c1be..58f48b8f42ae 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2616,6 +2616,35 @@ static void reg_timeout_work(struct work_struct *work)
2616 rtnl_unlock(); 2616 rtnl_unlock();
2617} 2617}
2618 2618
2619/*
2620 * See http://www.fcc.gov/document/5-ghz-unlicensed-spectrum-unii, for
2621 * UNII band definitions
2622 */
2623int cfg80211_get_unii(int freq)
2624{
2625 /* UNII-1 */
2626 if (freq >= 5150 && freq <= 5250)
2627 return 0;
2628
2629 /* UNII-2A */
2630 if (freq > 5250 && freq <= 5350)
2631 return 1;
2632
2633 /* UNII-2B */
2634 if (freq > 5350 && freq <= 5470)
2635 return 2;
2636
2637 /* UNII-2C */
2638 if (freq > 5470 && freq <= 5725)
2639 return 3;
2640
2641 /* UNII-3 */
2642 if (freq > 5725 && freq <= 5825)
2643 return 4;
2644
2645 return -EINVAL;
2646}
2647
2619int __init regulatory_init(void) 2648int __init regulatory_init(void)
2620{ 2649{
2621 int err = 0; 2650 int err = 0;
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index 37c180df34b7..334a53af0fc8 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -104,4 +104,16 @@ void regulatory_hint_country_ie(struct wiphy *wiphy,
104 */ 104 */
105void regulatory_hint_disconnect(void); 105void regulatory_hint_disconnect(void);
106 106
107/**
108 * cfg80211_get_unii - get the U-NII band for the frequency
109 * @freq: the frequency for which we want to get the UNII band.
110
111 * Get a value specifying the U-NII band frequency belongs to.
112 * U-NII bands are defined by the FCC in C.F.R 47 part 15.
113 *
114 * Returns -EINVAL if freq is invalid, 0 for UNII-1, 1 for UNII-2A,
115 * 2 for UNII-2B, 3 for UNII-2C and 4 for UNII-3.
116 */
117int cfg80211_get_unii(int freq);
118
107#endif /* __NET_WIRELESS_REG_H */ 119#endif /* __NET_WIRELESS_REG_H */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index aabccf13e07b..47b499f8f54d 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2193,18 +2193,21 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
2193); 2193);
2194 2194
2195TRACE_EVENT(cfg80211_reg_can_beacon, 2195TRACE_EVENT(cfg80211_reg_can_beacon,
2196 TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), 2196 TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
2197 TP_ARGS(wiphy, chandef), 2197 enum nl80211_iftype iftype),
2198 TP_ARGS(wiphy, chandef, iftype),
2198 TP_STRUCT__entry( 2199 TP_STRUCT__entry(
2199 WIPHY_ENTRY 2200 WIPHY_ENTRY
2200 CHAN_DEF_ENTRY 2201 CHAN_DEF_ENTRY
2202 __field(enum nl80211_iftype, iftype)
2201 ), 2203 ),
2202 TP_fast_assign( 2204 TP_fast_assign(
2203 WIPHY_ASSIGN; 2205 WIPHY_ASSIGN;
2204 CHAN_DEF_ASSIGN(chandef); 2206 CHAN_DEF_ASSIGN(chandef);
2207 __entry->iftype = iftype;
2205 ), 2208 ),
2206 TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, 2209 TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", iftype=%d",
2207 WIPHY_PR_ARG, CHAN_DEF_PR_ARG) 2210 WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->iftype)
2208); 2211);
2209 2212
2210TRACE_EVENT(cfg80211_chandef_dfs_required, 2213TRACE_EVENT(cfg80211_chandef_dfs_required,