diff options
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/chan.c | 4 | ||||
-rw-r--r-- | net/wireless/core.h | 15 | ||||
-rw-r--r-- | net/wireless/debugfs.c | 24 | ||||
-rw-r--r-- | net/wireless/genregdb.awk | 6 | ||||
-rw-r--r-- | net/wireless/ibss.c | 24 | ||||
-rw-r--r-- | net/wireless/mlme.c | 6 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 102 | ||||
-rw-r--r-- | net/wireless/reg.c | 53 | ||||
-rw-r--r-- | net/wireless/reg.h | 4 | ||||
-rw-r--r-- | net/wireless/scan.c | 4 | ||||
-rw-r--r-- | net/wireless/sme.c | 4 | ||||
-rw-r--r-- | net/wireless/sysfs.h | 4 | ||||
-rw-r--r-- | net/wireless/util.c | 23 |
13 files changed, 201 insertions, 72 deletions
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 50f6195..9b8cc87 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -328,6 +328,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy, return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2, width); } +EXPORT_SYMBOL(cfg80211_chandef_dfs_required); static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, u32 center_freq, u32 bandwidth, @@ -503,7 +504,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev, case NL80211_IFTYPE_ADHOC: if (wdev->current_bss) { *chan = wdev->current_bss->pub.channel; - *chanmode = wdev->ibss_fixed + *chanmode = (wdev->ibss_fixed && + !wdev->ibss_dfs_possible) ? CHAN_MODE_SHARED : CHAN_MODE_EXCLUSIVE; return; diff --git a/net/wireless/core.h b/net/wireless/core.h index 3159e9c..af10e59 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -234,10 +234,10 @@ struct cfg80211_beacon_registration { }; /* free object */ -extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); +void cfg80211_dev_free(struct cfg80211_registered_device *rdev); -extern int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, - char *newname); +int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, + char *newname); void ieee80211_set_bitrate_flags(struct wiphy *wiphy); @@ -382,15 +382,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, enum cfg80211_chan_mode chanmode, u8 radar_detect); -/** - * 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 - */ -int cfg80211_chandef_dfs_required(struct wiphy *wiphy, - const struct cfg80211_chan_def *c); - void cfg80211_set_dfs_state(struct wiphy *wiphy, const struct cfg80211_chan_def *chandef, enum nl80211_dfs_state dfs_state); diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c index 90d0500..4541577 100644 --- a/net/wireless/debugfs.c +++ b/net/wireless/debugfs.c @@ -47,17 +47,19 @@ static int ht_print_chan(struct ieee80211_channel *chan, return 0; if (chan->flags & IEEE80211_CHAN_DISABLED) - return snprintf(buf + offset, - buf_size - offset, - "%d Disabled\n", - chan->center_freq); - - return snprintf(buf + offset, - buf_size - offset, - "%d HT40 %c%c\n", - chan->center_freq, - (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) ? ' ' : '-', - (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) ? ' ' : '+'); + return scnprintf(buf + offset, + buf_size - offset, + "%d Disabled\n", + chan->center_freq); + + return scnprintf(buf + offset, + buf_size - offset, + "%d HT40 %c%c\n", + chan->center_freq, + (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) ? + ' ' : '-', + (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) ? + ' ' : '+'); } static ssize_t ht40allow_map_read(struct file *file, diff --git a/net/wireless/genregdb.awk b/net/wireless/genregdb.awk index 9392f8c..42ed274 100644 --- a/net/wireless/genregdb.awk +++ b/net/wireless/genregdb.awk @@ -46,6 +46,12 @@ BEGIN { sub(/:/, "", country) printf "static const struct ieee80211_regdomain regdom_%s = {\n", country printf "\t.alpha2 = \"%s\",\n", country + if ($NF ~ /DFS-ETSI/) + printf "\t.dfs_region = NL80211_DFS_ETSI,\n" + else if ($NF ~ /DFS-FCC/) + printf "\t.dfs_region = NL80211_DFS_FCC,\n" + else if ($NF ~ /DFS-JP/) + printf "\t.dfs_region = NL80211_DFS_JP,\n" printf "\t.reg_rules = {\n" active = 1 regdb = regdb "\t®dom_" country ",\n" diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 403fe29..9d797df 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -83,6 +83,8 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, struct cfg80211_cached_keys *connkeys) { struct wireless_dev *wdev = dev->ieee80211_ptr; + struct ieee80211_channel *check_chan; + u8 radar_detect_width = 0; int err; ASSERT_WDEV_LOCK(wdev); @@ -114,14 +116,28 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, wdev->connect_keys = connkeys; wdev->ibss_fixed = params->channel_fixed; + wdev->ibss_dfs_possible = params->userspace_handles_dfs; #ifdef CONFIG_CFG80211_WEXT wdev->wext.ibss.chandef = params->chandef; #endif + check_chan = params->chandef.chan; + if (params->userspace_handles_dfs) { + /* use channel NULL to check for radar even if the current + * channel is not a radar channel - it might decide to change + * to DFS channel later. + */ + radar_detect_width = BIT(params->chandef.width); + check_chan = NULL; + } + + err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, + check_chan, + (params->channel_fixed && + !radar_detect_width) + ? CHAN_MODE_SHARED + : CHAN_MODE_EXCLUSIVE, + radar_detect_width); - err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan, - params->channel_fixed - ? CHAN_MODE_SHARED - : CHAN_MODE_EXCLUSIVE); if (err) { wdev->connect_keys = NULL; return err; diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 8d49c1c..6a6b1c8 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -707,11 +707,13 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work) if (c->dfs_state != NL80211_DFS_UNAVAILABLE) continue; - timeout = c->dfs_state_entered + - IEEE80211_DFS_MIN_NOP_TIME_MS; + timeout = c->dfs_state_entered + msecs_to_jiffies( + IEEE80211_DFS_MIN_NOP_TIME_MS); if (time_after_eq(jiffies, timeout)) { c->dfs_state = NL80211_DFS_USABLE; + c->dfs_state_entered = jiffies; + cfg80211_chandef_create(&chandef, c, NL80211_CHAN_NO_HT); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 626dc3b..a7f4e79 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -354,6 +354,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_CSA_IES] = { .type = NLA_NESTED }, [NL80211_ATTR_CSA_C_OFF_BEACON] = { .type = NLA_U16 }, [NL80211_ATTR_CSA_C_OFF_PRESP] = { .type = NLA_U16 }, + [NL80211_ATTR_STA_SUPPORTED_CHANNELS] = { .type = NLA_BINARY }, + [NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES] = { .type = NLA_BINARY }, + [NL80211_ATTR_HANDLE_DFS] = { .type = NLA_FLAG }, }; /* policy for the key attributes */ @@ -3896,9 +3899,45 @@ static int nl80211_parse_sta_wme(struct genl_info *info, return 0; } +static int nl80211_parse_sta_channel_info(struct genl_info *info, + struct station_parameters *params) +{ + if (info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]) { + params->supported_channels = + nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]); + params->supported_channels_len = + nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_CHANNELS]); + /* + * Need to include at least one (first channel, number of + * channels) tuple for each subband, and must have proper + * tuples for the rest of the data as well. + */ + if (params->supported_channels_len < 2) + return -EINVAL; + if (params->supported_channels_len % 2) + return -EINVAL; + } + + if (info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]) { + params->supported_oper_classes = + nla_data(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]); + params->supported_oper_classes_len = + nla_len(info->attrs[NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES]); + /* + * The value of the Length field of the Supported Operating + * Classes element is between 2 and 253. + */ + if (params->supported_oper_classes_len < 2 || + params->supported_oper_classes_len > 253) + return -EINVAL; + } + return 0; +} + static int nl80211_set_station_tdls(struct genl_info *info, struct station_parameters *params) { + int err; /* Dummy STA entry gets updated once the peer capabilities are known */ if (info->attrs[NL80211_ATTR_PEER_AID]) params->aid = nla_get_u16(info->attrs[NL80211_ATTR_PEER_AID]); @@ -3909,6 +3948,10 @@ static int nl80211_set_station_tdls(struct genl_info *info, params->vht_capa = nla_data(info->attrs[NL80211_ATTR_VHT_CAPABILITY]); + err = nl80211_parse_sta_channel_info(info, params); + if (err) + return err; + return nl80211_parse_sta_wme(info, params); } @@ -4089,6 +4132,10 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } + err = nl80211_parse_sta_channel_info(info, ¶ms); + if (err) + return err; + err = nl80211_parse_sta_wme(info, ¶ms); if (err) return err; @@ -5591,6 +5638,9 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, if (err) return err; + if (netif_carrier_ok(dev)) + return -EBUSY; + if (wdev->cac_started) return -EBUSY; @@ -5634,15 +5684,27 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1]; u8 radar_detect_width = 0; int err; + bool need_new_beacon = false; if (!rdev->ops->channel_switch || !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)) return -EOPNOTSUPP; - /* may add IBSS support later */ - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + switch (dev->ieee80211_ptr->iftype) { + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + need_new_beacon = true; + + /* useless if AP is not running */ + if (!wdev->beacon_interval) + return -EINVAL; + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + break; + default: return -EOPNOTSUPP; + } memset(¶ms, 0, sizeof(params)); @@ -5651,15 +5713,14 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) return -EINVAL; /* only important for AP, IBSS and mesh create IEs internally */ - if (!info->attrs[NL80211_ATTR_CSA_IES]) - return -EINVAL; - - /* useless if AP is not running */ - if (!wdev->beacon_interval) + if (need_new_beacon && !info->attrs[NL80211_ATTR_CSA_IES]) return -EINVAL; params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]); + if (!need_new_beacon) + goto skip_beacons; + err = nl80211_parse_beacon(info->attrs, ¶ms.beacon_after); if (err) return err; @@ -5699,6 +5760,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info) return -EINVAL; } +skip_beacons: err = nl80211_parse_chandef(rdev, info, ¶ms.chandef); if (err) return err; @@ -5706,12 +5768,17 @@ static int nl80211_channel_switch(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); - if (err < 0) { - return err; - } else if (err) { - radar_detect_width = BIT(params.chandef.width); - params.radar_required = true; + if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP || + dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO || + dev->ieee80211_ptr->iftype == NL80211_IFTYPE_ADHOC) { + err = cfg80211_chandef_dfs_required(wdev->wiphy, + ¶ms.chandef); + if (err < 0) { + return err; + } else if (err) { + radar_detect_width = BIT(params.chandef.width); + params.radar_required = true; + } } err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, @@ -6535,6 +6602,9 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) ibss.control_port = nla_get_flag(info->attrs[NL80211_ATTR_CONTROL_PORT]); + ibss.userspace_handles_dfs = + nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]); + err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys); if (err) kfree(connkeys); @@ -10740,7 +10810,9 @@ void cfg80211_ch_switch_notify(struct net_device *dev, wdev_lock(wdev); if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP && - wdev->iftype != NL80211_IFTYPE_P2P_GO)) + wdev->iftype != NL80211_IFTYPE_P2P_GO && + wdev->iftype != NL80211_IFTYPE_ADHOC && + wdev->iftype != NL80211_IFTYPE_MESH_POINT)) goto out; wdev->channel = chandef->chan; diff --git a/net/wireless/reg.c b/net/wireless/reg.c index de06d5d..7da67fd 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -172,11 +172,21 @@ static const struct ieee80211_regdomain world_regdom = { NL80211_RRF_NO_IBSS | NL80211_RRF_NO_OFDM), /* IEEE 802.11a, channel 36..48 */ - REG_RULE(5180-10, 5240+10, 80, 6, 20, + REG_RULE(5180-10, 5240+10, 160, 6, 20, NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), - /* NB: 5260 MHz - 5700 MHz requires DFS */ + /* IEEE 802.11a, channel 52..64 - DFS required */ + REG_RULE(5260-10, 5320+10, 160, 6, 20, + NL80211_RRF_PASSIVE_SCAN | + NL80211_RRF_NO_IBSS | + NL80211_RRF_DFS), + + /* IEEE 802.11a, channel 100..144 - DFS required */ + REG_RULE(5500-10, 5720+10, 160, 6, 20, + NL80211_RRF_PASSIVE_SCAN | + NL80211_RRF_NO_IBSS | + NL80211_RRF_DFS), /* IEEE 802.11a, channel 149..165 */ REG_RULE(5745-10, 5825+10, 80, 6, 20, @@ -758,24 +768,25 @@ const struct ieee80211_reg_rule *freq_reg_info(struct wiphy *wiphy, } EXPORT_SYMBOL(freq_reg_info); -#ifdef CONFIG_CFG80211_REG_DEBUG -static const char *reg_initiator_name(enum nl80211_reg_initiator initiator) +const char *reg_initiator_name(enum nl80211_reg_initiator initiator) { switch (initiator) { case NL80211_REGDOM_SET_BY_CORE: - return "Set by core"; + return "core"; case NL80211_REGDOM_SET_BY_USER: - return "Set by user"; + return "user"; case NL80211_REGDOM_SET_BY_DRIVER: - return "Set by driver"; + return "driver"; case NL80211_REGDOM_SET_BY_COUNTRY_IE: - return "Set by country IE"; + return "country IE"; default: WARN_ON(1); - return "Set by bug"; + return "bug"; } } +EXPORT_SYMBOL(reg_initiator_name); +#ifdef CONFIG_CFG80211_REG_DEBUG static void chan_reg_rule_print_dbg(struct ieee80211_channel *chan, const struct ieee80211_reg_rule *reg_rule) { @@ -962,6 +973,13 @@ static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy) } #endif +static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy) +{ + if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && + !(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) + return true; + return false; +} static bool ignore_reg_update(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) @@ -969,14 +987,17 @@ static bool ignore_reg_update(struct wiphy *wiphy, struct regulatory_request *lr = get_last_request(); if (!lr) { - REG_DBG_PRINT("Ignoring regulatory request %s since last_request is not set\n", + REG_DBG_PRINT("Ignoring regulatory request set by %s " + "since last_request is not set\n", reg_initiator_name(initiator)); return true; } if (initiator == NL80211_REGDOM_SET_BY_CORE && wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) { - REG_DBG_PRINT("Ignoring regulatory request %s since the driver uses its own custom regulatory domain\n", + REG_DBG_PRINT("Ignoring regulatory request set by %s " + "since the driver uses its own custom " + "regulatory domain\n", reg_initiator_name(initiator)); return true; } @@ -985,10 +1006,12 @@ static bool ignore_reg_update(struct wiphy *wiphy, * wiphy->regd will be set once the device has its own * desired regulatory domain set */ - if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY && !wiphy->regd && + if (wiphy_strict_alpha2_regd(wiphy) && !wiphy->regd && initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE && !is_world_regdom(lr->alpha2)) { - REG_DBG_PRINT("Ignoring regulatory request %s since the driver requires its own regulatory domain to be set first\n", + REG_DBG_PRINT("Ignoring regulatory request set by %s " + "since the driver requires its own regulatory " + "domain to be set first\n", reg_initiator_name(initiator)); return true; } @@ -1689,8 +1712,8 @@ int regulatory_hint(struct wiphy *wiphy, const char *alpha2) } EXPORT_SYMBOL(regulatory_hint); -void regulatory_hint_11d(struct wiphy *wiphy, enum ieee80211_band band, - const u8 *country_ie, u8 country_ie_len) +void regulatory_hint_country_ie(struct wiphy *wiphy, enum ieee80211_band band, + const u8 *country_ie, u8 country_ie_len) { char alpha2[2]; enum environment_cap env = ENVIRON_ANY; diff --git a/net/wireless/reg.h b/net/wireless/reg.h index af2d5f8..9677e3c 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -58,7 +58,7 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, gfp_t gfp); /** - * regulatory_hint_11d - hints a country IE as a regulatory domain + * regulatory_hint_country_ie - hints a country IE as a regulatory domain * @wiphy: the wireless device giving the hint (used only for reporting * conflicts) * @band: the band on which the country IE was received on. This determines @@ -78,7 +78,7 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy, * not observed. For this reason if a triplet is seen with channel * information for a band the BSS is not present in it will be ignored. */ -void regulatory_hint_11d(struct wiphy *wiphy, +void regulatory_hint_country_ie(struct wiphy *wiphy, enum ieee80211_band band, const u8 *country_ie, u8 country_ie_len); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index eeb7148..d4397eb 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -254,10 +254,10 @@ void __cfg80211_sched_scan_results(struct work_struct *wk) rdev = container_of(wk, struct cfg80211_registered_device, sched_scan_results_wk); - request = rdev->sched_scan_req; - rtnl_lock(); + request = rdev->sched_scan_req; + /* we don't have sched_scan_req anymore if the scan is stopping */ if (request) { if (request->flags & NL80211_SCAN_FLAG_FLUSH) { diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 20e86a9..65f8008 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -682,8 +682,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid, * - country_ie + 2, the start of the country ie data, and * - and country_ie[1] which is the IE length */ - regulatory_hint_11d(wdev->wiphy, bss->channel->band, - country_ie + 2, country_ie[1]); + regulatory_hint_country_ie(wdev->wiphy, bss->channel->band, + country_ie + 2, country_ie[1]); kfree(country_ie); } diff --git a/net/wireless/sysfs.h b/net/wireless/sysfs.h index 65acbeb..b533ed7 100644 --- a/net/wireless/sysfs.h +++ b/net/wireless/sysfs.h @@ -1,8 +1,8 @@ #ifndef __WIRELESS_SYSFS_H #define __WIRELESS_SYSFS_H -extern int wiphy_sysfs_init(void); -extern void wiphy_sysfs_exit(void); +int wiphy_sysfs_init(void); +void wiphy_sysfs_exit(void); extern struct class ieee80211_class; diff --git a/net/wireless/util.c b/net/wireless/util.c index ce090c1..935dea9 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -10,6 +10,7 @@ #include <net/cfg80211.h> #include <net/ip.h> #include <net/dsfield.h> +#include <linux/if_vlan.h> #include "core.h" #include "rdev-ops.h" @@ -691,6 +692,7 @@ EXPORT_SYMBOL(ieee80211_amsdu_to_8023s); unsigned int cfg80211_classify8021d(struct sk_buff *skb) { unsigned int dscp; + unsigned char vlan_priority; /* skb->priority values from 256->263 are magic values to * directly indicate a specific 802.1d priority. This is used @@ -700,6 +702,13 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb) if (skb->priority >= 256 && skb->priority <= 263) return skb->priority - 256; + if (vlan_tx_tag_present(skb)) { + vlan_priority = (vlan_tx_tag_get(skb) & VLAN_PRIO_MASK) + >> VLAN_PRIO_SHIFT; + if (vlan_priority > 0) + return vlan_priority; + } + switch (skb->protocol) { case htons(ETH_P_IP): dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc; @@ -1240,7 +1249,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, enum cfg80211_chan_mode chmode; int num_different_channels = 0; int total = 1; - bool radar_required; + bool radar_required = false; int i, j; ASSERT_RTNL(); @@ -1255,14 +1264,20 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_WDS: - radar_required = !!(chan && - (chan->flags & IEEE80211_CHAN_RADAR)); + /* if the interface could potentially choose a DFS channel, + * then mark DFS as required. + */ + if (!chan) { + if (chanmode != CHAN_MODE_UNDEFINED && radar_detect) + radar_required = true; + break; + } + radar_required = !!(chan->flags & IEEE80211_CHAN_RADAR); break; case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_DEVICE: case NL80211_IFTYPE_MONITOR: - radar_required = false; break; case NUM_NL80211_IFTYPES: case NL80211_IFTYPE_UNSPECIFIED: |