[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