Commit d1b7524b authored by Rajkumar Manoharan's avatar Rajkumar Manoharan Committed by Johannes Berg
Browse files

mac80211: build HE operation with 6 GHz oper information



Add 6 GHz operation information (IEEE 802.11ax/D6.0, Figure 9-787k)
while building HE operation element for non-HE AP. This field is used to
determine channel information in the absence of HT/VHT IEs.

Signed-off-by: default avatarRajkumar Manoharan <rmanohar@codeaurora.org>
Link: https://lore.kernel.org/r/1589399105-25472-8-git-send-email-rmanohar@codeaurora.org
[fix skb allocation size]
Link: https://lore.kernel.org/r/20200528193455.76796-1-johannes@sipsolutions.net


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 24a2042c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2179,7 +2179,7 @@ u8 *ieee80211_ie_build_he_cap(u8 *pos,
			      u8 *end);
void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata,
				    struct sk_buff *skb);
u8 *ieee80211_ie_build_he_oper(u8 *pos);
u8 *ieee80211_ie_build_he_oper(u8 *pos, struct cfg80211_chan_def *chandef);
int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
			     const struct ieee80211_supported_band *sband,
			     const u8 *srates, int srates_len, u32 *rates);
+9 −3
Original line number Diff line number Diff line
@@ -565,6 +565,7 @@ int mesh_add_he_oper_ie(struct ieee80211_sub_if_data *sdata,
{
	const struct ieee80211_sta_he_cap *he_cap;
	struct ieee80211_supported_band *sband;
	u32 len;
	u8 *pos;

	sband = ieee80211_get_sband(sdata);
@@ -578,11 +579,15 @@ int mesh_add_he_oper_ie(struct ieee80211_sub_if_data *sdata,
	    sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10)
		return 0;

	if (skb_tailroom(skb) < 2 + 1 + sizeof(struct ieee80211_he_operation))
	len = 2 + 1 + sizeof(struct ieee80211_he_operation);
	if (sdata->vif.bss_conf.chandef.chan->band == NL80211_BAND_6GHZ)
		len += sizeof(struct ieee80211_he_6ghz_oper);

	if (skb_tailroom(skb) < len)
		return -ENOMEM;

	pos = skb_put(skb, 2 + 1 + sizeof(struct ieee80211_he_operation));
	ieee80211_ie_build_he_oper(pos);
	pos = skb_put(skb, len);
	ieee80211_ie_build_he_oper(pos, &sdata->vif.bss_conf.chandef);

	return 0;
}
@@ -773,6 +778,7 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
		   2 + sizeof(struct ieee80211_vht_operation) +
		   ie_len_he_cap +
		   2 + 1 + sizeof(struct ieee80211_he_operation) +
			   sizeof(struct ieee80211_he_6ghz_oper) +
		   2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) +
		   ifmsh->ie_len;

+1 −0
Original line number Diff line number Diff line
@@ -238,6 +238,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
			    2 + sizeof(struct ieee80211_vht_operation) +
			    ie_len_he_cap +
			    2 + 1 + sizeof(struct ieee80211_he_operation) +
				    sizeof(struct ieee80211_he_6ghz_oper) +
			    2 + 1 + sizeof(struct ieee80211_he_6ghz_capa) +
			    2 + 8 + /* peering IE */
			    sdata->u.mesh.ie_len);
+61 −4
Original line number Diff line number Diff line
@@ -3008,13 +3008,18 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
	return pos + sizeof(struct ieee80211_vht_operation);
}

u8 *ieee80211_ie_build_he_oper(u8 *pos)
u8 *ieee80211_ie_build_he_oper(u8 *pos, struct cfg80211_chan_def *chandef)
{
	struct ieee80211_he_operation *he_oper;
	struct ieee80211_he_6ghz_oper *he_6ghz_op;
	u32 he_oper_params;
	u8 ie_len = 1 + sizeof(struct ieee80211_he_operation);

	if (chandef->chan->band == NL80211_BAND_6GHZ)
		ie_len += sizeof(struct ieee80211_he_6ghz_oper);

	*pos++ = WLAN_EID_EXTENSION;
	*pos++ = 1 + sizeof(struct ieee80211_he_operation);
	*pos++ = ie_len;
	*pos++ = WLAN_EID_EXT_HE_OPERATION;

	he_oper_params = 0;
@@ -3024,16 +3029,68 @@ u8 *ieee80211_ie_build_he_oper(u8 *pos)
				IEEE80211_HE_OPERATION_ER_SU_DISABLE);
	he_oper_params |= u32_encode_bits(1,
				IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED);
	if (chandef->chan->band == NL80211_BAND_6GHZ)
		he_oper_params |= u32_encode_bits(1,
				IEEE80211_HE_OPERATION_6GHZ_OP_INFO);

	he_oper = (struct ieee80211_he_operation *)pos;
	he_oper->he_oper_params = cpu_to_le32(he_oper_params);

	/* don't require special HE peer rates */
	he_oper->he_mcs_nss_set = cpu_to_le16(0xffff);
	pos += sizeof(struct ieee80211_he_operation);

	/* TODO add VHT operational and 6GHz operational subelement? */
	if (chandef->chan->band != NL80211_BAND_6GHZ)
		goto out;

	return pos + sizeof(struct ieee80211_vht_operation);
	/* TODO add VHT operational */
	he_6ghz_op = (struct ieee80211_he_6ghz_oper *)pos;
	he_6ghz_op->minrate = 6; /* 6 Mbps */
	he_6ghz_op->primary =
		ieee80211_frequency_to_channel(chandef->chan->center_freq);
	he_6ghz_op->ccfs0 =
		ieee80211_frequency_to_channel(chandef->center_freq1);
	if (chandef->center_freq2)
		he_6ghz_op->ccfs1 =
			ieee80211_frequency_to_channel(chandef->center_freq2);
	else
		he_6ghz_op->ccfs1 = 0;

	switch (chandef->width) {
	case NL80211_CHAN_WIDTH_160:
		/* Convert 160 MHz channel width to new style as interop
		 * workaround.
		 */
		he_6ghz_op->control =
			IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ;
		he_6ghz_op->ccfs1 = he_6ghz_op->ccfs0;
		if (chandef->chan->center_freq < chandef->center_freq1)
			he_6ghz_op->ccfs0 -= 8;
		else
			he_6ghz_op->ccfs0 += 8;
		fallthrough;
	case NL80211_CHAN_WIDTH_80P80:
		he_6ghz_op->control =
			IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_160MHZ;
		break;
	case NL80211_CHAN_WIDTH_80:
		he_6ghz_op->control =
			IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_80MHZ;
		break;
	case NL80211_CHAN_WIDTH_40:
		he_6ghz_op->control =
			IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_40MHZ;
		break;
	default:
		he_6ghz_op->control =
			IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ;
		break;
	}

	pos += sizeof(struct ieee80211_he_6ghz_oper);

out:
	return pos;
}

bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,