* structures here describe these capabilities in detail.
*/
+struct wiphy;
+
/*
* wireless hardware capability structures
*/
cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1,
const struct cfg80211_chan_def *chandef2);
+/**
+ * cfg80211_chandef_valid - check if a channel definition is valid
+ * @chandef: the channel definition to check
+ */
+bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef);
+
+/**
+ * cfg80211_chandef_usable - check if secondary channels can be used
+ * @wiphy: the wiphy to validate against
+ * @chandef: the channel definition to check
+ * @prohibited_flags: the regulatory chanenl flags that must not be set
+ */
+bool cfg80211_chandef_usable(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef,
+ u32 prohibited_flags);
+
/**
* enum survey_info_flags - survey information flags
*
u8 aifs;
};
-/* from net/wireless.h */
-struct wiphy;
-
/**
* DOC: Scanning and BSS list handling
*
}
EXPORT_SYMBOL(cfg80211_chandef_create);
-bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef)
+bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
{
u32 control_freq;
return true;
}
+EXPORT_SYMBOL(cfg80211_chandef_valid);
static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
int *pri40, int *pri80)
}
EXPORT_SYMBOL(cfg80211_chandef_compatible);
-bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
- u32 center_freq, u32 bandwidth,
- u32 prohibited_flags)
+static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
+ u32 center_freq, u32 bandwidth,
+ u32 prohibited_flags)
{
struct ieee80211_channel *c;
u32 freq;
return true;
}
-static bool cfg80211_check_beacon_chans(struct wiphy *wiphy,
- u32 center_freq, u32 bw)
+bool cfg80211_chandef_usable(struct wiphy *wiphy,
+ const struct cfg80211_chan_def *chandef,
+ u32 prohibited_flags)
{
- return cfg80211_secondary_chans_ok(wiphy, center_freq, bw,
- IEEE80211_CHAN_DISABLED |
- IEEE80211_CHAN_PASSIVE_SCAN |
- IEEE80211_CHAN_NO_IBSS |
- IEEE80211_CHAN_RADAR);
-}
+ struct ieee80211_sta_ht_cap *ht_cap;
+ struct ieee80211_sta_vht_cap *vht_cap;
+ u32 width, control_freq;
-bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
- struct cfg80211_chan_def *chandef)
-{
- u32 width;
- bool res;
+ if (WARN_ON(!cfg80211_chandef_valid(chandef)))
+ return false;
- trace_cfg80211_reg_can_beacon(wiphy, chandef);
+ ht_cap = &wiphy->bands[chandef->chan->band]->ht_cap;
+ vht_cap = &wiphy->bands[chandef->chan->band]->vht_cap;
- if (WARN_ON(!cfg80211_chan_def_valid(chandef))) {
- trace_cfg80211_return_bool(false);
- return false;
- }
+ control_freq = chandef->chan->center_freq;
switch (chandef->width) {
- case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_20:
+ if (!ht_cap->ht_supported)
+ return false;
+ case NL80211_CHAN_WIDTH_20_NOHT:
width = 20;
break;
case NL80211_CHAN_WIDTH_40:
width = 40;
+ if (!ht_cap->ht_supported)
+ return false;
+ if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
+ ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
+ return false;
+ if (chandef->center_freq1 < control_freq &&
+ chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
+ return false;
+ if (chandef->center_freq1 > control_freq &&
+ chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
+ return false;
break;
- case NL80211_CHAN_WIDTH_80:
case NL80211_CHAN_WIDTH_80P80:
+ if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
+ return false;
+ case NL80211_CHAN_WIDTH_80:
+ if (!vht_cap->vht_supported)
+ return false;
width = 80;
break;
case NL80211_CHAN_WIDTH_160:
+ if (!vht_cap->vht_supported)
+ return false;
+ if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ))
+ return false;
width = 160;
break;
default:
WARN_ON_ONCE(1);
- trace_cfg80211_return_bool(false);
return false;
}
- res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq1, width);
+ /* TODO: missing regulatory check on 80/160 bandwidth */
+
+ if (!cfg80211_secondary_chans_ok(wiphy, chandef->center_freq1,
+ width, prohibited_flags))
+ return false;
+
+ if (!chandef->center_freq2)
+ return true;
+ return cfg80211_secondary_chans_ok(wiphy, chandef->center_freq2,
+ width, prohibited_flags);
+}
+EXPORT_SYMBOL(cfg80211_chandef_usable);
+
+bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef)
+{
+ bool res;
+
+ trace_cfg80211_reg_can_beacon(wiphy, chandef);
- if (res && chandef->center_freq2)
- res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq2,
- width);
+ res = cfg80211_chandef_usable(wiphy, chandef,
+ IEEE80211_CHAN_DISABLED |
+ IEEE80211_CHAN_PASSIVE_SCAN |
+ IEEE80211_CHAN_NO_IBSS |
+ IEEE80211_CHAN_RADAR);
trace_cfg80211_return_bool(res);
return res;
ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap;
vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap;
- if (!cfg80211_chan_def_valid(chandef))
+ if (!cfg80211_chandef_valid(chandef))
return -EINVAL;
switch (chandef->width) {
case NL80211_CHAN_WIDTH_20:
- if (!ht_cap->ht_supported)
- return -EINVAL;
case NL80211_CHAN_WIDTH_20_NOHT:
width = 20;
break;
case NL80211_CHAN_WIDTH_40:
width = 40;
- /* quick early regulatory check */
- if (chandef->center_freq1 < control_freq &&
- chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
- return -EINVAL;
- if (chandef->center_freq1 > control_freq &&
- chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
- return -EINVAL;
- if (!ht_cap->ht_supported)
- return -EINVAL;
- if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
- ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
- return -EINVAL;
break;
case NL80211_CHAN_WIDTH_80:
width = 80;
- if (!vht_cap->vht_supported)
- return -EINVAL;
break;
case NL80211_CHAN_WIDTH_80P80:
width = 80;
- if (!vht_cap->vht_supported)
- return -EINVAL;
- if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
- return -EINVAL;
break;
case NL80211_CHAN_WIDTH_160:
width = 160;
- if (!vht_cap->vht_supported)
- return -EINVAL;
- if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ))
- return -EINVAL;
break;
default:
return -EINVAL;
}
- if (!cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq1,
- width, IEEE80211_CHAN_DISABLED))
+ if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
+ IEEE80211_CHAN_DISABLED))
return -EINVAL;
- if (chandef->center_freq2 &&
- !cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq2,
- width, IEEE80211_CHAN_DISABLED))
- return -EINVAL;
-
- /* TODO: missing regulatory check on bandwidth */
return 0;
}
static int nl80211_send_chandef(struct sk_buff *msg,
struct cfg80211_chan_def *chandef)
{
- WARN_ON(!cfg80211_chan_def_valid(chandef));
+ WARN_ON(!cfg80211_chandef_valid(chandef));
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
chandef->chan->center_freq))