diff mbox series

[wireless-next,2/3] wifi: mac80211: Add preamble puncturing support for mesh

Message ID 20250609001048.2263586-3-ramasamy.kaliappan@oss.qualcomm.com
State New
Headers show
Series wifi: Preamble puncturing support for mesh | expand

Commit Message

Ramasamy Kaliappan June 9, 2025, 12:10 a.m. UTC
From: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>

Preamble puncturing(“Punctured 242-tone RU") refers to the
transmission of a PPDU in which no signal is present in at
least one of the 20 MHz subchannels within the PPDU bandwidth.
Puncturing might be the result of the unavailability of 20 MHz
subchannel(s) within the PPDU bandwidth, such as a busy channel
indicated by the CCA or the setting of the disabled subchannel
bitmap field (16 bit field) in the EHT Operations element.

EHT disabled sub channel bitmap is a 16 bit field where
each bit corresponds to a 20 MHz channel in the given bandwidth.
Bit 0 corresponding to the channel with lowest frequency.
Bit set to 1 indicates that the channel is punctured, otherwise active.

Userspace may send the EHT disabled sub channel bitmap via attribute
NL80211_ATTR_PUNCT_BITMAP in frequency params as a part of join mesh
(NL80211_CMD_JOIN_MESH) command. Validate the received puncturing bitmap
and copy it to chandef’s punctured bitmap for the mesh interface data.

Build the mesh beacon's EHT Operation element, including
disable_sub_chan_bitmap_present and disable_subchannel_bitmap
based on chandef's puncture.

Validate and update peer mesh stations puncturing bitmap
in local structures while adding new mesh station
(parsed from peer mesh station's EHT Operation element)

Add changes to allow mesh peering with stations that advertise
different puncturing pattern than the local station, and determine
the bandwidth for each peer mesh.

Signed-off-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>
Signed-off-by: Ramasamy Kaliappan <ramasamy.kaliappan@oss.qualcomm.com>
---
 include/net/mac80211.h    |  5 ++++-
 net/mac80211/cfg.c        | 19 ++++++++++++++++++-
 net/mac80211/mesh.c       |  9 +++++++++
 net/mac80211/mesh_plink.c | 38 ++++++++++++++++++++++++++++++++++++++
 net/mac80211/util.c       | 15 +++++++++++++--
 5 files changed, 82 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 82617579d910..fc3fcd3c3ec8 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2435,7 +2435,9 @@  struct ieee80211_sta_aggregates {
  *	notifications and capabilities. The value is only valid after
  *	the station moves to associated state.
  * @txpwr: the station tx power configuration
- *
+ * @punctured: Preamble puncturing bitmap. Each bit represents
+ *	a 20 MHz channel, lowest bit corresponding to the lowest channel.
+ *	Bit set to 1 indicates that the channel is punctured.
  */
 struct ieee80211_link_sta {
 	struct ieee80211_sta *sta;
@@ -2456,6 +2458,7 @@  struct ieee80211_link_sta {
 	u8 rx_nss;
 	enum ieee80211_sta_rx_bandwidth bandwidth;
 	struct ieee80211_sta_txpwr txpwr;
+	u16 punctured;
 };
 
 /**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index d9d88f2f2831..8caedd353796 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1948,13 +1948,30 @@  static int sta_link_apply_parameters(struct ieee80211_local *local,
 						  (void *)params->he_6ghz_capa,
 						  link_sta);
 
-	if (params->he_capa && params->eht_capa)
+	if (params->he_capa && params->eht_capa) {
 		ieee80211_eht_cap_ie_to_sta_eht_cap(sdata, sband,
 						    (u8 *)params->he_capa,
 						    params->he_capa_len,
 						    params->eht_capa,
 						    params->eht_capa_len,
 						    link_sta);
+		/* 802.11s mesh STA may have different eht puncturing pattern,
+		 * update it here so that drivers can use if needed.
+		 */
+		if (ieee80211_vif_is_mesh(&sdata->vif) && params->punctured) {
+			struct cfg80211_chan_def chandef;
+			struct ieee80211_channel *chan = link->conf->chanreq.oper.chan;
+
+			cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
+			chandef.punctured = params->punctured;
+			chandef.width = link->conf->chanreq.oper.width;
+			chandef.width = link->conf->chanreq.oper.width;
+			chandef.center_freq1 = link->conf->chanreq.oper.center_freq1;
+
+			if (cfg80211_chandef_valid(&chandef))
+				link_sta->pub->punctured = params->punctured;
+		}
+	}
 
 	ieee80211_sta_init_nss(link_sta);
 
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 5cc56d578048..1edb4bc9d635 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -112,6 +112,12 @@  bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
 				       ie->eht_operation,
 				       &sta_chan_def);
 
+	/* In order to allow mesh peering when peer advertising different
+	 * puncturing bitmaps, update the local mesh punctured bitmap
+	 * with the new mesh peer punctured bitmap to ensure compatibility.
+	 */
+	sta_chan_def.punctured = sdata->vif.bss_conf.chanreq.oper.punctured;
+
 	if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chanreq.oper,
 					 &sta_chan_def))
 		return false;
@@ -672,6 +678,9 @@  int mesh_add_eht_oper_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *sk
 	len = 2 + 1 + offsetof(struct ieee80211_eht_operation, optional) +
 		      offsetof(struct ieee80211_eht_operation_info, optional);
 
+	if (sdata->vif.bss_conf.chanreq.oper.punctured)
+		len += sizeof(sdata->vif.bss_conf.chanreq.oper.punctured);
+
 	if (skb_tailroom(skb) < len)
 		return -ENOMEM;
 
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 9c6a2b342170..5fde9d6ec1f1 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -430,11 +430,49 @@  static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_supported_band *sband;
 	u32 rates, changed = 0;
 	enum ieee80211_sta_rx_bandwidth bw = sta->sta.deflink.bandwidth;
+	struct cfg80211_chan_def eht_chandef;
 
 	sband = ieee80211_get_sband(sdata);
 	if (!sband)
 		return;
 
+	/* 802.11s mesh peer may have different eht puncturing pattern,
+	 * update it here so that drivers can use if needed.
+	 */
+	if (elems->eht_operation &&
+	    (elems->eht_operation->params & IEEE80211_EHT_OPER_INFO_PRESENT) &&
+	    (u8_get_bits(elems->eht_operation->optional[0],
+			 IEEE80211_EHT_OPER_CHAN_WIDTH) >=
+	     IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ) &&
+	    (elems->eht_operation->params &
+	     IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT)) {
+		struct ieee80211_channel *chan = sdata->vif.bss_conf.chanreq.oper.chan;
+
+		cfg80211_chandef_create(&eht_chandef, chan, NL80211_CHAN_NO_HT);
+		eht_chandef.punctured = (elems->eht_operation->optional[4] << 8) |
+					 elems->eht_operation->optional[3];
+		/* Validate Peer's Puncturing Bitmap and reset if invalid */
+		switch (u8_get_bits(elems->eht_operation->optional[0],
+				    IEEE80211_EHT_OPER_CHAN_WIDTH)) {
+		case IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ:
+			eht_chandef.width = NL80211_CHAN_WIDTH_80;
+			break;
+		case IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ:
+			eht_chandef.width = NL80211_CHAN_WIDTH_160;
+			break;
+		case IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ:
+			eht_chandef.width = NL80211_CHAN_WIDTH_320;
+			break;
+		default:
+			eht_chandef.width = NL80211_CHAN_WIDTH_20;
+		}
+		eht_chandef.center_freq1 =
+			ieee80211_channel_to_frequency(elems->eht_operation->optional[1],
+						       chan->band);
+		if (cfg80211_chandef_valid(&eht_chandef))
+			sta->sta.deflink.punctured = eht_chandef.punctured;
+	}
+
 	rates = ieee80211_sta_get_rates(sdata, elems, sband->band, NULL);
 
 	spin_lock_bh(&sta->mesh->plink_lock);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 27d414efa3fd..442def202cad 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2850,9 +2850,13 @@  u8 *ieee80211_ie_build_eht_oper(u8 *pos, const struct cfg80211_chan_def *chandef
 	u8 eht_oper_info_len =
 		offsetof(struct ieee80211_eht_operation_info, optional);
 	u8 chan_width = 0;
+	u8 ie_len = 0;
+
+	if (chandef->punctured)
+		ie_len += sizeof(chandef->punctured);
 
 	*pos++ = WLAN_EID_EXTENSION;
-	*pos++ = 1 + eht_oper_len + eht_oper_info_len;
+	*pos++ = 1 + eht_oper_len + eht_oper_info_len + ie_len;
 	*pos++ = WLAN_EID_EXT_EHT_OPERATION;
 
 	eht_oper = (struct ieee80211_eht_operation *)pos;
@@ -2904,7 +2908,14 @@  u8 *ieee80211_ie_build_eht_oper(u8 *pos, const struct cfg80211_chan_def *chandef
 	eht_oper_info->control = chan_width;
 	pos += eht_oper_info_len;
 
-	/* TODO: eht_oper_info->optional */
+	if (chandef->punctured) {
+		eht_oper->params |=
+			IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT;
+
+		eht_oper_info->optional[0] = chandef->punctured & 0x00FF;
+		eht_oper_info->optional[1] = chandef->punctured >> 8;
+		pos += sizeof(chandef->punctured);
+	}
 
 	return pos;
 }