Commit 3743bec6 authored by Jia Ding's avatar Jia Ding Committed by Johannes Berg
Browse files
parent 5cd5a8a3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -836,6 +836,8 @@ static int hwsim_get_chanwidth(enum nl80211_chan_width bw)
	case NL80211_CHAN_WIDTH_80P80:
	case NL80211_CHAN_WIDTH_160:
		return 160;
	case NL80211_CHAN_WIDTH_320:
		return 320;
	case NL80211_CHAN_WIDTH_5:
		return 5;
	case NL80211_CHAN_WIDTH_10:
+6 −1
Original line number Diff line number Diff line
@@ -109,7 +109,11 @@ struct wiphy;
 *	on this channel.
 * @IEEE80211_CHAN_16MHZ: 16 MHz bandwidth is permitted
 *	on this channel.
 *
 * @IEEE80211_CHAN_NO_320MHZ: If the driver supports 320 MHz on the band,
 *	this flag indicates that a 320 MHz channel cannot use this
 *	channel as the control or any of the secondary channels.
 *	This may be due to the driver or due to regulatory bandwidth
 *	restrictions.
 */
enum ieee80211_channel_flags {
	IEEE80211_CHAN_DISABLED		= 1<<0,
@@ -131,6 +135,7 @@ enum ieee80211_channel_flags {
	IEEE80211_CHAN_4MHZ		= 1<<16,
	IEEE80211_CHAN_8MHZ		= 1<<17,
	IEEE80211_CHAN_16MHZ		= 1<<18,
	IEEE80211_CHAN_NO_320MHZ	= 1<<19,
};

#define IEEE80211_CHAN_NO_HT40 \
+3 −0
Original line number Diff line number Diff line
@@ -4684,6 +4684,8 @@ enum nl80211_key_mode {
 * @NL80211_CHAN_WIDTH_4: 4 MHz OFDM channel
 * @NL80211_CHAN_WIDTH_8: 8 MHz OFDM channel
 * @NL80211_CHAN_WIDTH_16: 16 MHz OFDM channel
 * @NL80211_CHAN_WIDTH_320: 320 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
 *	attribute must be provided as well
 */
enum nl80211_chan_width {
	NL80211_CHAN_WIDTH_20_NOHT,
@@ -4699,6 +4701,7 @@ enum nl80211_chan_width {
	NL80211_CHAN_WIDTH_4,
	NL80211_CHAN_WIDTH_8,
	NL80211_CHAN_WIDTH_16,
	NL80211_CHAN_WIDTH_320,
};

/**
+84 −7
Original line number Diff line number Diff line
@@ -181,6 +181,9 @@ static int nl80211_chan_width_to_mhz(enum nl80211_chan_width chan_width)
	case NL80211_CHAN_WIDTH_160:
		mhz = 160;
		break;
	case NL80211_CHAN_WIDTH_320:
		mhz = 320;
		break;
	default:
		WARN_ON_ONCE(1);
		return -1;
@@ -271,6 +274,17 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
	case NL80211_CHAN_WIDTH_16:
		/* all checked above */
		break;
	case NL80211_CHAN_WIDTH_320:
		if (chandef->center_freq1 == control_freq + 150 ||
		    chandef->center_freq1 == control_freq + 130 ||
		    chandef->center_freq1 == control_freq + 110 ||
		    chandef->center_freq1 == control_freq + 90 ||
		    chandef->center_freq1 == control_freq - 90 ||
		    chandef->center_freq1 == control_freq - 110 ||
		    chandef->center_freq1 == control_freq - 130 ||
		    chandef->center_freq1 == control_freq - 150)
			break;
		fallthrough;
	case NL80211_CHAN_WIDTH_160:
		if (chandef->center_freq1 == control_freq + 70 ||
		    chandef->center_freq1 == control_freq + 50 ||
@@ -307,7 +321,7 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
EXPORT_SYMBOL(cfg80211_chandef_valid);

static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
				  u32 *pri40, u32 *pri80)
				  u32 *pri40, u32 *pri80, u32 *pri160)
{
	int tmp;

@@ -315,9 +329,11 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
	case NL80211_CHAN_WIDTH_40:
		*pri40 = c->center_freq1;
		*pri80 = 0;
		*pri160 = 0;
		break;
	case NL80211_CHAN_WIDTH_80:
	case NL80211_CHAN_WIDTH_80P80:
		*pri160 = 0;
		*pri80 = c->center_freq1;
		/* n_P20 */
		tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
@@ -327,6 +343,7 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
		*pri40 = c->center_freq1 - 20 + 40 * tmp;
		break;
	case NL80211_CHAN_WIDTH_160:
		*pri160 = c->center_freq1;
		/* n_P20 */
		tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
		/* n_P40 */
@@ -337,6 +354,20 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
		tmp /= 2;
		*pri80 = c->center_freq1 - 40 + 80 * tmp;
		break;
	case NL80211_CHAN_WIDTH_320:
		/* n_P20 */
		tmp = (150 + c->chan->center_freq - c->center_freq1) / 20;
		/* n_P40 */
		tmp /= 2;
		/* freq_P40 */
		*pri40 = c->center_freq1 - 140 + 40 * tmp;
		/* n_P80 */
		tmp /= 2;
		*pri80 = c->center_freq1 - 120 + 80 * tmp;
		/* n_P160 */
		tmp /= 2;
		*pri160 = c->center_freq1 - 80 + 160 * tmp;
		break;
	default:
		WARN_ON_ONCE(1);
	}
@@ -346,7 +377,7 @@ const struct cfg80211_chan_def *
cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
			    const struct cfg80211_chan_def *c2)
{
	u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
	u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80, c1_pri160, c2_pri160;

	/* If they are identical, return */
	if (cfg80211_chandef_identical(c1, c2))
@@ -381,14 +412,31 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
	    c2->width == NL80211_CHAN_WIDTH_20)
		return c1;

	chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
	chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
	chandef_primary_freqs(c1, &c1_pri40, &c1_pri80, &c1_pri160);
	chandef_primary_freqs(c2, &c2_pri40, &c2_pri80, &c2_pri160);

	if (c1_pri40 != c2_pri40)
		return NULL;

	WARN_ON(!c1_pri80 && !c2_pri80);
	if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
	if (c1->width == NL80211_CHAN_WIDTH_40)
		return c2;

	if (c2->width == NL80211_CHAN_WIDTH_40)
		return c1;

	if (c1_pri80 != c2_pri80)
		return NULL;

	if (c1->width == NL80211_CHAN_WIDTH_80 &&
	    c2->width > NL80211_CHAN_WIDTH_80)
		return c2;

	if (c2->width == NL80211_CHAN_WIDTH_80 &&
	    c1->width > NL80211_CHAN_WIDTH_80)
		return c1;

	WARN_ON(!c1_pri160 && !c2_pri160);
	if (c1_pri160 && c2_pri160 && c1_pri160 != c2_pri160)
		return NULL;

	if (c1->width > c2->width)
@@ -960,7 +1008,10 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
	struct ieee80211_sta_vht_cap *vht_cap;
	struct ieee80211_edmg *edmg_cap;
	u32 width, control_freq, cap;
	bool ext_nss_cap, support_80_80 = false;
	bool ext_nss_cap, support_80_80 = false, support_320 = false;
	const struct ieee80211_sband_iftype_data *iftd;
	struct ieee80211_supported_band *sband;
	int i;

	if (WARN_ON(!cfg80211_chandef_valid(chandef)))
		return false;
@@ -1062,6 +1113,32 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
		      (vht_cap->cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)))
			return false;
		break;
	case NL80211_CHAN_WIDTH_320:
		prohibited_flags |= IEEE80211_CHAN_NO_320MHZ;
		width = 320;

		if (chandef->chan->band != NL80211_BAND_6GHZ)
			return false;

		sband = wiphy->bands[NL80211_BAND_6GHZ];
		if (!sband)
			return false;

		for (i = 0; i < sband->n_iftype_data; i++) {
			iftd = &sband->iftype_data[i];
			if (!iftd->eht_cap.has_eht)
				continue;

			if (iftd->eht_cap.eht_cap_elem.phy_cap_info[0] &
			    IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) {
				support_320 = true;
				break;
			}
		}

		if (!support_320)
			return false;
		break;
	default:
		WARN_ON_ONCE(1);
		return false;
+2 −0
Original line number Diff line number Diff line
@@ -10589,6 +10589,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
					     NL80211_EXT_FEATURE_VHT_IBSS))
			return -EINVAL;
		break;
	case NL80211_CHAN_WIDTH_320:
		return -EINVAL;
	default:
		return -EINVAL;
	}