Commit 9f5e8f6e authored by Johannes Berg's avatar Johannes Berg

cfg80211: rework chandef checking and export it

Some of the chandef checking that we do in cfg80211
to check if a channel is supported or not is also
needed in mac80211, so rework that a bit and export
the functions that are needed.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent ec816087
...@@ -58,6 +58,8 @@ ...@@ -58,6 +58,8 @@
* structures here describe these capabilities in detail. * structures here describe these capabilities in detail.
*/ */
struct wiphy;
/* /*
* wireless hardware capability structures * wireless hardware capability structures
*/ */
...@@ -387,6 +389,22 @@ const struct cfg80211_chan_def * ...@@ -387,6 +389,22 @@ const struct cfg80211_chan_def *
cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1, cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1,
const struct cfg80211_chan_def *chandef2); 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 * enum survey_info_flags - survey information flags
* *
...@@ -1045,9 +1063,6 @@ struct ieee80211_txq_params { ...@@ -1045,9 +1063,6 @@ struct ieee80211_txq_params {
u8 aifs; u8 aifs;
}; };
/* from net/wireless.h */
struct wiphy;
/** /**
* DOC: Scanning and BSS list handling * DOC: Scanning and BSS list handling
* *
......
...@@ -44,7 +44,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef, ...@@ -44,7 +44,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
} }
EXPORT_SYMBOL(cfg80211_chandef_create); 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; u32 control_freq;
...@@ -105,6 +105,7 @@ bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef) ...@@ -105,6 +105,7 @@ bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef)
return true; return true;
} }
EXPORT_SYMBOL(cfg80211_chandef_valid);
static void chandef_primary_freqs(const struct cfg80211_chan_def *c, static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
int *pri40, int *pri80) int *pri40, int *pri80)
...@@ -187,7 +188,7 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, ...@@ -187,7 +188,7 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
} }
EXPORT_SYMBOL(cfg80211_chandef_compatible); EXPORT_SYMBOL(cfg80211_chandef_compatible);
bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
u32 center_freq, u32 bandwidth, u32 center_freq, u32 bandwidth,
u32 prohibited_flags) u32 prohibited_flags)
{ {
...@@ -205,55 +206,88 @@ bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, ...@@ -205,55 +206,88 @@ bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
return true; return true;
} }
static bool cfg80211_check_beacon_chans(struct wiphy *wiphy, bool cfg80211_chandef_usable(struct wiphy *wiphy,
u32 center_freq, u32 bw) const struct cfg80211_chan_def *chandef,
u32 prohibited_flags)
{ {
return cfg80211_secondary_chans_ok(wiphy, center_freq, bw, struct ieee80211_sta_ht_cap *ht_cap;
IEEE80211_CHAN_DISABLED | struct ieee80211_sta_vht_cap *vht_cap;
IEEE80211_CHAN_PASSIVE_SCAN | u32 width, control_freq;
IEEE80211_CHAN_NO_IBSS |
IEEE80211_CHAN_RADAR);
}
bool cfg80211_reg_can_beacon(struct wiphy *wiphy, if (WARN_ON(!cfg80211_chandef_valid(chandef)))
struct cfg80211_chan_def *chandef) return false;
{
u32 width;
bool res;
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))) { control_freq = chandef->chan->center_freq;
trace_cfg80211_return_bool(false);
return false;
}
switch (chandef->width) { switch (chandef->width) {
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_20: case NL80211_CHAN_WIDTH_20:
if (!ht_cap->ht_supported)
return false;
case NL80211_CHAN_WIDTH_20_NOHT:
width = 20; width = 20;
break; break;
case NL80211_CHAN_WIDTH_40: case NL80211_CHAN_WIDTH_40:
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; break;
case NL80211_CHAN_WIDTH_80:
case NL80211_CHAN_WIDTH_80P80: 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; width = 80;
break; break;
case NL80211_CHAN_WIDTH_160: 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; width = 160;
break; break;
default: default:
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
trace_cfg80211_return_bool(false);
return 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;
if (res && chandef->center_freq2) trace_cfg80211_reg_can_beacon(wiphy, chandef);
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); trace_cfg80211_return_bool(res);
return res; return res;
......
...@@ -483,12 +483,6 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, ...@@ -483,12 +483,6 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
enum nl80211_iftype iftype, int num); enum nl80211_iftype iftype, int num);
bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef);
bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
u32 center_freq, u32 bandwidth,
u32 prohibited_flags);
#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
......
...@@ -1420,63 +1420,33 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev, ...@@ -1420,63 +1420,33 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap; ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap;
vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap; vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap;
if (!cfg80211_chan_def_valid(chandef)) if (!cfg80211_chandef_valid(chandef))
return -EINVAL; return -EINVAL;
switch (chandef->width) { switch (chandef->width) {
case NL80211_CHAN_WIDTH_20: case NL80211_CHAN_WIDTH_20:
if (!ht_cap->ht_supported)
return -EINVAL;
case NL80211_CHAN_WIDTH_20_NOHT: case NL80211_CHAN_WIDTH_20_NOHT:
width = 20; width = 20;
break; break;
case NL80211_CHAN_WIDTH_40: case NL80211_CHAN_WIDTH_40:
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; break;
case NL80211_CHAN_WIDTH_80: case NL80211_CHAN_WIDTH_80:
width = 80; width = 80;
if (!vht_cap->vht_supported)
return -EINVAL;
break; break;
case NL80211_CHAN_WIDTH_80P80: case NL80211_CHAN_WIDTH_80P80:
width = 80; width = 80;
if (!vht_cap->vht_supported)
return -EINVAL;
if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
return -EINVAL;
break; break;
case NL80211_CHAN_WIDTH_160: case NL80211_CHAN_WIDTH_160:
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; break;
default: default:
return -EINVAL; return -EINVAL;
} }
if (!cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq1, if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
width, IEEE80211_CHAN_DISABLED)) IEEE80211_CHAN_DISABLED))
return -EINVAL; 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; return 0;
} }
...@@ -1841,7 +1811,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev) ...@@ -1841,7 +1811,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
static int nl80211_send_chandef(struct sk_buff *msg, static int nl80211_send_chandef(struct sk_buff *msg,
struct cfg80211_chan_def *chandef) 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, if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
chandef->chan->center_freq)) chandef->chan->center_freq))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment