@@ -441,10 +441,13 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
* cfg80211_chandef_dfs_required - checks if radar detection is required
* @wiphy: the wiphy to validate against
* @chandef: the channel definition to check
- * Return: 1 if radar detection is required, 0 if it is not, < 0 on error
+ * @iftype: the interface type as specified in &enum nl80211_iftype
+ * Returns:
+ * 1 if radar detection is required, 0 if it is not, < 0 on error
*/
int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
- const struct cfg80211_chan_def *chandef);
+ const struct cfg80211_chan_def *chandef,
+ enum nl80211_iftype);
/**
* ieee80211_chandef_rate_flags - returns rate flags for a channel
@@ -228,7 +228,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
struct beacon_data *presp;
enum nl80211_bss_scan_width scan_width;
bool have_higher_than_11mbit;
- bool radar_required = false;
+ bool radar_required;
int err;
sdata_assert_lock(sdata);
@@ -282,21 +282,20 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
}
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
- &chandef);
+ &chandef, NL80211_IFTYPE_ADHOC);
if (err < 0) {
sdata_info(sdata,
"Failed to join IBSS, invalid chandef\n");
return;
}
- if (err > 0) {
- if (!ifibss->userspace_handles_dfs) {
- sdata_info(sdata,
- "Failed to join IBSS, DFS channel without control program\n");
- return;
- }
- radar_required = true;
+ if (err > 0 && !ifibss->userspace_handles_dfs) {
+ sdata_info(sdata,
+ "Failed to join IBSS, DFS channel without control program\n");
+ return;
}
+ radar_required = err;
+
mutex_lock(&local->mtx);
if (ieee80211_vif_use_channel(sdata, &chandef,
ifibss->fixed_channel ?
@@ -775,7 +774,8 @@ static void ieee80211_ibss_csa_mark_radar(struct ieee80211_sub_if_data *sdata)
* unavailable.
*/
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
- &ifibss->chandef);
+ &ifibss->chandef,
+ NL80211_IFTYPE_ADHOC);
if (err > 0)
cfg80211_radar_event(sdata->local->hw.wiphy, &ifibss->chandef,
GFP_ATOMIC);
@@ -873,17 +873,17 @@ ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
}
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
- ¶ms.chandef);
+ ¶ms.chandef,
+ NL80211_IFTYPE_ADHOC);
if (err < 0)
goto disconnect;
- if (err) {
+ if (err > 0 && !ifibss->userspace_handles_dfs) {
/* IBSS-DFS only allowed with a control program */
- if (!ifibss->userspace_handles_dfs)
- goto disconnect;
-
- params.radar_required = true;
+ goto disconnect;
}
+ params.radar_required = err;
+
if (cfg80211_chandef_identical(¶ms.chandef,
&sdata->vif.bss_conf.chandef)) {
ibss_dbg(sdata,
@@ -903,14 +903,15 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata,
}
err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
- ¶ms.chandef);
+ ¶ms.chandef,
+ NL80211_IFTYPE_MESH_POINT);
if (err < 0)
return false;
- if (err) {
- params.radar_required = true;
+ if (err > 0)
/* TODO: DFS not (yet) supported */
return false;
- }
+
+ params.radar_required = err;
if (cfg80211_chandef_identical(¶ms.chandef,
&sdata->vif.bss_conf.chandef)) {
@@ -326,28 +326,57 @@ static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
- const struct cfg80211_chan_def *chandef)
+ const struct cfg80211_chan_def *chandef,
+ enum nl80211_iftype iftype)
{
int width;
- int r;
+ int ret;
if (WARN_ON(!cfg80211_chandef_valid(chandef)))
return -EINVAL;
- width = cfg80211_chandef_get_width(chandef);
- if (width < 0)
- return -EINVAL;
+ switch (iftype) {
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_MESH_POINT:
+ width = cfg80211_chandef_get_width(chandef);
+ if (width < 0)
+ return -EINVAL;
- r = cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq1,
- width);
- if (r)
- return r;
+ ret = cfg80211_get_chans_dfs_required(wiphy,
+ chandef->center_freq1,
+ width);
+ if (ret < 0)
+ return ret;
+ else if (ret > 0)
+ return BIT(chandef->width);
- if (!chandef->center_freq2)
- return 0;
+ if (!chandef->center_freq2)
+ return 0;
+
+ ret = cfg80211_get_chans_dfs_required(wiphy,
+ chandef->center_freq2,
+ width);
+ if (ret < 0)
+ return ret;
+ else if (ret > 0)
+ return BIT(chandef->width);
- return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2,
- width);
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_P2P_DEVICE:
+ break;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NUM_NL80211_IFTYPES:
+ WARN_ON(1);
+ }
+
+ return 0;
}
EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
@@ -671,7 +700,8 @@ bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
trace_cfg80211_reg_can_beacon(wiphy, chandef);
- if (cfg80211_chandef_dfs_required(wiphy, chandef) > 0 &&
+ if (cfg80211_chandef_dfs_required(wiphy, chandef,
+ NL80211_IFTYPE_UNSPECIFIED) > 0 &&
cfg80211_chandef_dfs_available(wiphy, chandef)) {
/* We can skip IEEE80211_CHAN_NO_IR if chandef dfs available */
prohibited_flags = IEEE80211_CHAN_DISABLED;
@@ -701,6 +731,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
enum cfg80211_chan_mode *chanmode,
u8 *radar_detect)
{
+ int ret;
+
*chan = NULL;
*chanmode = CHAN_MODE_UNDEFINED;
@@ -743,8 +775,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
*chan = wdev->chandef.chan;
*chanmode = CHAN_MODE_SHARED;
- if (cfg80211_chandef_dfs_required(wdev->wiphy,
- &wdev->chandef))
+ ret = cfg80211_chandef_dfs_required(wdev->wiphy,
+ &wdev->chandef,
+ wdev->iftype);
+ WARN_ON(ret < 0);
+ if (ret > 0)
*radar_detect |= BIT(wdev->chandef.width);
}
return;
@@ -753,8 +788,11 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
*chan = wdev->chandef.chan;
*chanmode = CHAN_MODE_SHARED;
- if (cfg80211_chandef_dfs_required(wdev->wiphy,
- &wdev->chandef))
+ ret = cfg80211_chandef_dfs_required(wdev->wiphy,
+ &wdev->chandef,
+ wdev->iftype);
+ WARN_ON(ret < 0);
+ if (ret > 0)
*radar_detect |= BIT(wdev->chandef.width);
}
return;
@@ -178,10 +178,13 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
return -EINVAL;
- err = cfg80211_chandef_dfs_required(wdev->wiphy, &setup->chandef);
+ err = cfg80211_chandef_dfs_required(wdev->wiphy,
+ &setup->chandef,
+ NL80211_IFTYPE_MESH_POINT);
if (err < 0)
return err;
- if (err)
+
+ if (err > 0)
radar_detect_width = BIT(setup->chandef.width);
err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
@@ -3261,12 +3261,15 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef))
return -EINVAL;
- err = cfg80211_chandef_dfs_required(wdev->wiphy, ¶ms.chandef);
+ err = cfg80211_chandef_dfs_required(wdev->wiphy,
+ ¶ms.chandef,
+ NL80211_IFTYPE_AP);
if (err < 0)
return err;
- if (err) {
- radar_detect_width = BIT(params.chandef.width);
+
+ if (err > 0) {
params.radar_required = true;
+ radar_detect_width = BIT(params.chandef.width);
}
err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
@@ -5796,7 +5799,8 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
if (wdev->cac_started)
return -EBUSY;
- err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef);
+ err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef,
+ NL80211_IFTYPE_UNSPECIFIED);
if (err < 0)
return err;
@@ -5931,22 +5935,15 @@ skip_beacons:
if (!cfg80211_reg_can_beacon(&rdev->wiphy, ¶ms.chandef))
return -EINVAL;
- switch (dev->ieee80211_ptr->iftype) {
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_P2P_GO:
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_MESH_POINT:
- err = cfg80211_chandef_dfs_required(wdev->wiphy,
- ¶ms.chandef);
- if (err < 0)
- return err;
- if (err) {
- radar_detect_width = BIT(params.chandef.width);
- params.radar_required = true;
- }
- break;
- default:
- break;
+ err = cfg80211_chandef_dfs_required(wdev->wiphy,
+ ¶ms.chandef,
+ wdev->iftype);
+ if (err < 0)
+ return err;
+
+ if (err > 0) {
+ radar_detect_width = BIT(params.chandef.width);
+ params.radar_required = true;
}
err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
Some interface types don't require DFS (such as STATION, P2P_CLIENT etc). In order to centralize these decisions, make cfg80211_chandef_dfs_required() take the iftype into consideration. Signed-off-by: Luciano Coelho <luciano.coelho@intel.com> --- In v4: * rebased on top of slightly modified applied patches * removed the double negations when assigning err to a boolean; In v7: * change cfg80211_chandef_dfs_required() back to returning 1 if radar detection is needed instead of a bitmap with the width required. In v9: * fixed commit message; * added braces in a couple of if's that had comments and a statement; * move NL80211_IFTYPE_UNSPECIFIED to the WARN part of the switch in dfs_required) and remove default; --- include/net/cfg80211.h | 7 +++-- net/mac80211/ibss.c | 32 +++++++++++----------- net/mac80211/mesh.c | 9 +++--- net/wireless/chan.c | 74 ++++++++++++++++++++++++++++++++++++++------------ net/wireless/mesh.c | 7 +++-- net/wireless/nl80211.c | 37 ++++++++++++------------- 6 files changed, 104 insertions(+), 62 deletions(-)