aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h4
-rw-r--r--include/net/regulatory.h6
-rw-r--r--net/mac80211/ibss.c9
-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
10 files changed, 169 insertions, 16 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 14d8d3417735..5640dc028bfa 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4539,12 +4539,14 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
4539 * cfg80211_reg_can_beacon - check if beaconing is allowed 4539 * cfg80211_reg_can_beacon - check if beaconing is allowed
4540 * @wiphy: the wiphy 4540 * @wiphy: the wiphy
4541 * @chandef: the channel definition 4541 * @chandef: the channel definition
4542 * @iftype: interface type
4542 * 4543 *
4543 * Return: %true if there is no secondary channel or the secondary channel(s) 4544 * Return: %true if there is no secondary channel or the secondary channel(s)
4544 * can be used for beaconing (i.e. is not a radar channel etc.) 4545 * can be used for beaconing (i.e. is not a radar channel etc.)
4545 */ 4546 */
4546bool cfg80211_reg_can_beacon(struct wiphy *wiphy, 4547bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
4547 struct cfg80211_chan_def *chandef); 4548 struct cfg80211_chan_def *chandef,
4549 enum nl80211_iftype iftype);
4548 4550
4549/* 4551/*
4550 * cfg80211_ch_switch_notify - update wdev channel and notify userspace 4552 * cfg80211_ch_switch_notify - update wdev channel and notify userspace
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index 75fc1f5a948d..259992444e80 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -131,6 +131,11 @@ struct regulatory_request {
131 * all country IE information processed by the regulatory core. This will 131 * all country IE information processed by the regulatory core. This will
132 * override %REGULATORY_COUNTRY_IE_FOLLOW_POWER as all country IEs will 132 * override %REGULATORY_COUNTRY_IE_FOLLOW_POWER as all country IEs will
133 * be ignored. 133 * be ignored.
134 * @REGULATORY_ENABLE_RELAX_NO_IR: for devices that wish to allow the
135 * NO_IR relaxation, which enables transmissions on channels on which
136 * otherwise initiating radiation is not allowed. This will enable the
137 * relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration
138 * option
134 */ 139 */
135enum ieee80211_regulatory_flags { 140enum ieee80211_regulatory_flags {
136 REGULATORY_CUSTOM_REG = BIT(0), 141 REGULATORY_CUSTOM_REG = BIT(0),
@@ -138,6 +143,7 @@ enum ieee80211_regulatory_flags {
138 REGULATORY_DISABLE_BEACON_HINTS = BIT(2), 143 REGULATORY_DISABLE_BEACON_HINTS = BIT(2),
139 REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3), 144 REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3),
140 REGULATORY_COUNTRY_IE_IGNORE = BIT(4), 145 REGULATORY_COUNTRY_IE_IGNORE = BIT(4),
146 REGULATORY_ENABLE_RELAX_NO_IR = BIT(5),
141}; 147};
142 148
143struct ieee80211_freq_range { 149struct ieee80211_freq_range {
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 35e4f94d7ba1..741445e498b0 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -262,7 +262,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
262 /* make a copy of the chandef, it could be modified below. */ 262 /* make a copy of the chandef, it could be modified below. */
263 chandef = *req_chandef; 263 chandef = *req_chandef;
264 chan = chandef.chan; 264 chan = chandef.chan;
265 if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { 265 if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef,
266 NL80211_IFTYPE_ADHOC)) {
266 if (chandef.width == NL80211_CHAN_WIDTH_5 || 267 if (chandef.width == NL80211_CHAN_WIDTH_5 ||
267 chandef.width == NL80211_CHAN_WIDTH_10 || 268 chandef.width == NL80211_CHAN_WIDTH_10 ||
268 chandef.width == NL80211_CHAN_WIDTH_20_NOHT || 269 chandef.width == NL80211_CHAN_WIDTH_20_NOHT ||
@@ -274,7 +275,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
274 chandef.width = NL80211_CHAN_WIDTH_20; 275 chandef.width = NL80211_CHAN_WIDTH_20;
275 chandef.center_freq1 = chan->center_freq; 276 chandef.center_freq1 = chan->center_freq;
276 /* check again for downgraded chandef */ 277 /* check again for downgraded chandef */
277 if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) { 278 if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef,
279 NL80211_IFTYPE_ADHOC)) {
278 sdata_info(sdata, 280 sdata_info(sdata,
279 "Failed to join IBSS, beacons forbidden\n"); 281 "Failed to join IBSS, beacons forbidden\n");
280 return; 282 return;
@@ -861,7 +863,8 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
861 goto disconnect; 863 goto disconnect;
862 } 864 }
863 865
864 if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef)) { 866 if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, &params.chandef,
867 NL80211_IFTYPE_ADHOC)) {
865 sdata_info(sdata, 868 sdata_info(sdata,
866 "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n", 869 "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
867 ifibss->bssid, 870 ifibss->bssid,
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,