Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+18 −3
Original line number Diff line number Diff line
@@ -58,6 +58,8 @@
 * structures here describe these capabilities in detail.
 */

struct wiphy;

/*
 * wireless hardware capability structures
 */
@@ -387,6 +389,22 @@ const struct cfg80211_chan_def *
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
 *
@@ -1045,9 +1063,6 @@ struct ieee80211_txq_params {
	u8 aifs;
};

/* from net/wireless.h */
struct wiphy;

/**
 * DOC: Scanning and BSS list handling
 *
+63 −29
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
}
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;

@@ -105,6 +105,7 @@ bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef)

	return true;
}
EXPORT_SYMBOL(cfg80211_chandef_valid);

static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
				  int *pri40, int *pri80)
@@ -187,7 +188,7 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
}
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 prohibited_flags)
{
@@ -205,55 +206,88 @@ bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
	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;

	if (res && chandef->center_freq2)
		res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq2,
						  width);
	trace_cfg80211_reg_can_beacon(wiphy, chandef);

	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;
+0 −6
Original line number Diff line number Diff line
@@ -483,12 +483,6 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
			       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

#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
+4 −34
Original line number Diff line number Diff line
@@ -1420,63 +1420,33 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
	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;
}
@@ -1841,7 +1811,7 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
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))