[PATCH wireless-next 2/2] wifi: mac80211: Add drv_set_eml_op_mode driver callback

Lorenzo Bianconi lorenzo at kernel.org
Thu Jan 22 05:51:34 PST 2026


Introduce drv_set_eml_op_mode mac80211 callback in order to configure
underlay driver with eMLSR info (control and bitmap). eMLMR is currently
not supported.

Tested-by: Christian Marangi <ansuelsmth at gmail.com>
Signed-off-by: Lorenzo Bianconi <lorenzo at kernel.org>
---
 include/net/mac80211.h    |  7 +++++++
 net/mac80211/driver-ops.h | 21 +++++++++++++++++++++
 net/mac80211/eht.c        | 26 ++++++++++++++++++++++++--
 net/mac80211/trace.h      | 31 +++++++++++++++++++++++++++++++
 4 files changed, 83 insertions(+), 2 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 36ae7fe9ddf35190921f4fee0fe3294418007a56..3920135595c545a4255bf513c2c8b0525a383c71 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -4513,6 +4513,9 @@ struct ieee80211_prep_tx_info {
  *      interface with the specified type would be added, and thus drivers that
  *      implement this callback need to handle such cases. The type is the full
  *      &enum nl80211_iftype.
+ * @set_eml_op_mode: Configure eMLSR/eMLMR operation mode in the underlay
+ *	driver according to the parameter received in the EML Operating mode
+ *	notification frame.
  */
 struct ieee80211_ops {
 	void (*tx)(struct ieee80211_hw *hw,
@@ -4908,6 +4911,10 @@ struct ieee80211_ops {
 			struct ieee80211_neg_ttlm *ttlm);
 	void (*prep_add_interface)(struct ieee80211_hw *hw,
 				   enum nl80211_iftype type);
+	int (*set_eml_op_mode)(struct ieee80211_hw *hw,
+			       struct ieee80211_vif *vif,
+			       struct ieee80211_link_sta *link_sta,
+			       u8 control, __le16 link_bitmap);
 };
 
 /**
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 55105d238d6bc5963eb2863575805bee72c42399..a3f2a38241edbea62698cb1104a11a80681983a0 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1772,4 +1772,25 @@ drv_prep_add_interface(struct ieee80211_local *local,
 	trace_drv_return_void(local);
 }
 
+static inline int drv_set_eml_op_mode(struct ieee80211_sub_if_data *sdata,
+				      struct ieee80211_link_sta *link_sta,
+				      u8 control, __le16 link_bitmap)
+{
+	struct ieee80211_local *local = sdata->local;
+	int ret = 0;
+
+	might_sleep();
+	lockdep_assert_wiphy(local->hw.wiphy);
+
+	trace_drv_set_eml_op_mode(local, sdata, link_sta, control,
+				  link_bitmap);
+	if (local->ops->set_eml_op_mode)
+		ret = local->ops->set_eml_op_mode(&local->hw, &sdata->vif,
+						  link_sta, control,
+						  link_bitmap);
+	trace_drv_return_int(local, ret);
+
+	return ret;
+}
+
 #endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/eht.c b/net/mac80211/eht.c
index f1f60d41fccfc2da4ecd2961f6a524e94a6bfa6c..cb5d0ca08ac3aa81f928ab4e05107515dc111858 100644
--- a/net/mac80211/eht.c
+++ b/net/mac80211/eht.c
@@ -5,6 +5,7 @@
  * Copyright(c) 2021-2025 Intel Corporation
  */
 
+#include "driver-ops.h"
 #include "ieee80211_i.h"
 
 void
@@ -136,17 +137,22 @@ void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
 {
 	int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.eml_omn);
 	enum nl80211_iftype type = ieee80211_vif_type_p2p(&sdata->vif);
+	struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
 	const struct wiphy_iftype_ext_capab *ift_ext_capa;
 	struct ieee80211_mgmt *mgmt = (void *)skb->data;
 	struct ieee80211_local *local = sdata->local;
 	u8 control = mgmt->u.action.u.eml_omn.control;
 	u8 *ptr = mgmt->u.action.u.eml_omn.variable;
+	struct wiphy *wiphy = local->hw.wiphy;
+	struct link_sta_info *link_sta;
+	__le16 link_bitmap = 0;
+	struct sta_info *sta;
 	u8 act_len = 3; /* action_code + dialog_token + control */
 
 	if (!ieee80211_vif_is_mld(&sdata->vif))
 		return;
 
-	ift_ext_capa = cfg80211_get_iftype_ext_capa(local->hw.wiphy, type);
+	ift_ext_capa = cfg80211_get_iftype_ext_capa(wiphy, type);
 	if (!ift_ext_capa)
 		return;
 
@@ -160,8 +166,10 @@ void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
 		return;
 
 	if ((control & IEEE80211_EML_CTRL_EMLSR_MODE) ||
-	    (control & IEEE80211_EML_CTRL_EMLMR_MODE))
+	    (control & IEEE80211_EML_CTRL_EMLMR_MODE)) {
+		link_bitmap = get_unaligned((__le16 *)ptr);
 		act_len += sizeof(__le16); /* eMLSR/eMLMR link_bitmap */
+	}
 
 	if (control & IEEE80211_EML_CTRL_EMLMR_MODE) {
 		u8 mcs_map_count = ptr[3];
@@ -176,5 +184,19 @@ void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
 	if (skb->len < hdr_len + act_len)
 		return;
 
+	if (!status->link_valid)
+		return;
+
+	sta = sta_info_get_bss(sdata, mgmt->sa);
+	if (!sta)
+		return;
+
+	link_sta = wiphy_dereference(wiphy, sta->link[status->link_id]);
+	if (!link_sta)
+		return;
+
+	if (drv_set_eml_op_mode(sdata, link_sta->pub, control, link_bitmap))
+		return;
+
 	ieee80211_send_eml_op_mode_notif(sdata, mgmt, act_len);
 }
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 0bfbce1574862b5a6a2ca39794abea7fe9a3f34a..584658bd4640c72aef3199cd9341699924fd5fea 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -3353,6 +3353,37 @@ TRACE_EVENT(drv_prep_add_interface,
 	)
 );
 
+TRACE_EVENT(drv_set_eml_op_mode,
+	    TP_PROTO(struct ieee80211_local *local,
+		     struct ieee80211_sub_if_data *sdata,
+		     struct ieee80211_link_sta *link_sta,
+		     u8 control, __le16 link_bitmap),
+
+	TP_ARGS(local, sdata, link_sta, control, link_bitmap),
+
+	TP_STRUCT__entry(LOCAL_ENTRY
+			 VIF_ENTRY
+			 STA_ENTRY
+			 __field(u32, link_id)
+			 __field(u8, control)
+			 __field(__le16, link_bitmap)),
+
+	TP_fast_assign(LOCAL_ASSIGN;
+		       VIF_ASSIGN;
+		       STA_NAMED_ASSIGN(link_sta->sta);
+		       __entry->link_id = link_sta->link_id;
+		       __entry->control = control;
+		       __entry->link_bitmap = link_bitmap;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT
+		" (link:%d control:%02x link_bitmap:%04x)",
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->link_id,
+		__entry->control, __entry->link_bitmap
+	)
+);
+
 #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
 
 #undef TRACE_INCLUDE_PATH

-- 
2.52.0




More information about the Linux-mediatek mailing list