diff options
-rw-r--r-- | include/net/cfg80211.h | 4 | ||||
-rw-r--r-- | include/net/regulatory.h | 6 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 9 | ||||
-rw-r--r-- | net/wireless/Kconfig | 24 | ||||
-rw-r--r-- | net/wireless/chan.c | 76 | ||||
-rw-r--r-- | net/wireless/mesh.c | 3 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 11 | ||||
-rw-r--r-- | net/wireless/reg.c | 29 | ||||
-rw-r--r-- | net/wireless/reg.h | 12 | ||||
-rw-r--r-- | net/wireless/trace.h | 11 |
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 | */ |
4546 | bool cfg80211_reg_can_beacon(struct wiphy *wiphy, | 4547 | bool 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 | */ |
135 | enum ieee80211_regulatory_flags { | 140 | enum 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 | ||
143 | struct ieee80211_freq_range { | 149 | struct 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, ¶ms.chandef)) { | 866 | if (!cfg80211_reg_can_beacon(sdata->local->hw.wiphy, ¶ms.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 | ||
111 | config 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 | |||
111 | config CFG80211_DEFAULT_PS | 135 | config 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 | } |
662 | EXPORT_SYMBOL(cfg80211_chandef_usable); | 662 | EXPORT_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 | */ | ||
671 | static 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 | |||
664 | bool cfg80211_reg_can_beacon(struct wiphy *wiphy, | 723 | bool 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, ¶ms)) | 3271 | } else if (!nl80211_get_ap_channel(rdev, ¶ms)) |
3272 | return -EINVAL; | 3272 | return -EINVAL; |
3273 | 3273 | ||
3274 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef)) | 3274 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef, |
3275 | wdev->iftype)) | ||
3275 | return -EINVAL; | 3276 | return -EINVAL; |
3276 | 3277 | ||
3277 | err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.chandef); | 3278 | err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.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, ¶ms.chandef)) | 5945 | if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.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 | */ | ||
2623 | int 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 | |||
2619 | int __init regulatory_init(void) | 2648 | int __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 | */ |
105 | void regulatory_hint_disconnect(void); | 105 | void 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 | */ | ||
117 | int 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 | ||
2195 | TRACE_EVENT(cfg80211_reg_can_beacon, | 2195 | TRACE_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 | ||
2210 | TRACE_EVENT(cfg80211_chandef_dfs_required, | 2213 | TRACE_EVENT(cfg80211_chandef_dfs_required, |