[rdkb][common][bsp][Refactor and sync wifi from openwrt]
[Description]
3a2eef0b [MAC80211][Release][Update release note for Filogic 880/860 MLO Beta release]
cfbd2411 [MAC80211][Release][Filogic 880/860 MLO Beta release]
6c180e3f [MAC80211][WiFi7][misc][Add Eagle BE14000 efem default bin]
a55f34db [MAC80211][Release][Prepare for Filogic 880/860 release]
5b45ebca [MAC80211][WiFi7][hostapd][Add puncture bitmap to ucode]
95bbea73 [MAC80211][WiFi6][mt76][Add PID to only report data-frame TX rate]
b15ced26 [MAC80211][WiFi6][hostapd][Fix DFS channel selection issue]
d59133cb [MAC80211][WiFi6][mt76][Fix pse info not correct information]
3921b4b2 [MAC80211][WiFi6][mt76][Fix incomplete QoS-map setting to FW]
4e7690c7 [MAC80211][WiFi6/7][app][Change ATECHANNEL mapping cmd]
eb37af90 [MAC80211][WiFi7][app][Add support for per-packet bw & primary selection]
0ea82adf [MAC80211][WiFi6][core][Fix DFS CAC issue after CSA]
[Release-log]
Change-Id: I9bec97ec1b2e1c49ed43a812a07a5b21fcbb70a6
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/0119-mtk-hostapd-add-A-TTLM-support.patch b/recipes-wifi/hostapd/files/patches-2.10.3/0119-mtk-hostapd-add-A-TTLM-support.patch
new file mode 100644
index 0000000..a6bdd09
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/0119-mtk-hostapd-add-A-TTLM-support.patch
@@ -0,0 +1,760 @@
+From 8aabcfee2bb77e19fc592c27f1121c5725ee665f Mon Sep 17 00:00:00 2001
+From: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Date: Wed, 3 Jul 2024 15:39:53 +0800
+Subject: [PATCH 119/126] mtk: hostapd: add A-TTLM support
+
+Add a data structure for AP MLD's Advertised Tid-to-Link Mapping (A-TTLM).
+Since it is MLD-level, this commit also adds it into struct hostapd_mld.
+
+There should be 'curr_attlm' and 'new_attlm', which means 2 TTLMs can be
+advertised at the same time ('curr_attlm' is used currently while
+'new_attlm' is about to be used)
+However, since the FW only support 1 attlm now, there is currently only
+'new_attlm'.
+
+There are 3 A-TTLM events from the driver, and hostap should handle them
+accordingly
+1. A-TTLM started: link(s) sould start to advertise TTLM in the beacon.
+2. A-TTLM switch time expired: enabled link(s) keep advertising TTLM in
+ the beacon with switch time excluded, whiel disabled link(s) should
+ stop TX/RX, including beacon
+3. A-TTLM ended: all links stop advertising TTLM in the beacon, and
+ disabled link recover to TX/RX.
+
+This commit adds the support to set ATTLM, from hostapd_cli to driver.
+Setting an ATTLM requires 3 parameters
+1. disabled_links: disabled link ID bitmap
+2. switch_time: how much time it takes to start the A-TTLM (in ms)
+3. duration: how long the A-TTLM lasts (in ms)
+
+Below is a hostapd_cli example that requires an A-TTLM starts to disable
+link_id=1 after 5 seconds and last for 20 seconds:
+$ hostapd_cli -i ap-mld-1 set_attlm disabled_links=2 switch_time=5000
+duration=20000
+
+Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
+---
+ hostapd/ctrl_iface.c | 66 +++++++++++++++++++++++++++++
+ hostapd/hostapd_cli.c | 8 ++++
+ src/ap/ap_drv_ops.c | 9 ++++
+ src/ap/ap_drv_ops.h | 1 +
+ src/ap/beacon.c | 4 ++
+ src/ap/drv_callbacks.c | 53 +++++++++++++++++++++++
+ src/ap/hostapd.c | 8 ++++
+ src/ap/hostapd.h | 4 ++
+ src/ap/ieee802_11.c | 8 ++++
+ src/ap/ieee802_11.h | 1 +
+ src/ap/ieee802_11_eht.c | 68 +++++++++++++++++++++++++++++-
+ src/common/ieee802_11_defs.h | 13 ++++++
+ src/drivers/driver.h | 56 ++++++++++++++++++++++++
+ src/drivers/driver_nl80211.c | 33 +++++++++++++++
+ src/drivers/driver_nl80211_event.c | 54 ++++++++++++++++++++++++
+ src/drivers/nl80211_copy.h | 24 +++++++++++
+ 16 files changed, 409 insertions(+), 1 deletion(-)
+
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index 6db9fa617..2cd5487ca 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -4039,6 +4039,68 @@ out:
+ return ret;
+ }
+
++static int hostapd_ctrl_iface_set_attlm(struct hostapd_data *hapd, char *cmd,
++ char *buf, size_t buflen)
++{
++#define MAX_SWITCH_TIME_MS 30000
++#define MAX_DURATION_MS 16000000
++ struct attlm_settings *attlm;
++ struct hostapd_data *h;
++ char *token, *context = NULL;
++ u16 switch_time, disabled_links, valid_links = 0;
++ u32 duration;
++ int ret, i;
++
++ if (!hapd->conf->mld_ap || !hapd->mld)
++ return -1;
++
++ attlm = &hapd->mld->new_attlm;
++ if (attlm->valid) {
++ wpa_printf(MSG_ERROR, "Busy: A-TTLM is on-going");
++ return -1;
++ }
++
++ for_each_mld_link(h, hapd)
++ valid_links |= BIT(h->mld_link_id);
++
++ while ((token = str_token(cmd, " ", &context))) {
++ if (os_strncmp(token, "switch_time=", 12) == 0) {
++ switch_time = atoi(token + 12);
++ if (switch_time > 0 && switch_time <= MAX_SWITCH_TIME_MS)
++ continue;
++ }
++
++ if (os_strncmp(token, "disabled_links=", 15) == 0) {
++ disabled_links = atoi(token + 15);
++
++ if ((disabled_links & valid_links) &&
++ !(disabled_links & ~valid_links))
++ continue;
++ }
++
++ if (os_strncmp(token, "duration=", 9) == 0) {
++ duration = atoi(token + 9);
++ if (duration > 0 && duration <= MAX_DURATION_MS)
++ continue;
++ }
++
++ wpa_printf(MSG_INFO, "CTRL: Invalid SET_ATTLM parameter: %s",
++ token);
++ return -1;
++ }
++
++ wpa_printf(MSG_DEBUG,
++ "MLD: set A-TTLM disabled_links=%u, switch_time=%u, duration=%u",
++ disabled_links, switch_time, duration);
++
++ attlm->valid = true;
++ attlm->direction = IEEE80211_TTLM_DIRECTION_BOTH;
++ attlm->duration = duration;
++ attlm->switch_time = switch_time;
++ attlm->disabled_links = hapd->conf->mld_allowed_links & disabled_links;
++
++ return hostapd_mld_set_attlm(hapd);
++}
+ #endif /* CONFIG_TESTING_OPTIONS */
+ #endif /* CONFIG_IEEE80211BE */
+
+@@ -6166,6 +6228,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ if (hostapd_ctrl_iface_link_add(hapd, buf + 9,
+ reply, reply_size))
+ reply_len = -1;
++ } else if (os_strncmp(buf, "SET_ATTLM ", 10) == 0) {
++ if (hostapd_ctrl_iface_set_attlm(hapd, buf + 10, reply,
++ reply_size))
++ reply_len = -1;
+ #endif /* CONFIG_TESTING_OPTIONS */
+ #endif /* CONFIG_IEEE80211BE */
+ } else if (os_strncmp(buf, "SET_EDCCA ", 10) == 0) {
+diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
+index 9dcc0d74b..f81211ba4 100644
+--- a/hostapd/hostapd_cli.c
++++ b/hostapd/hostapd_cli.c
+@@ -1791,6 +1791,12 @@ static int hostapd_cli_cmd_link_remove(struct wpa_ctrl *ctrl, int argc,
+ return hostapd_cli_cmd(ctrl, "LINK_REMOVE", 1, argc, argv);
+ }
+
++static int hostapd_cli_cmd_set_attlm(struct wpa_ctrl *ctrl, int argc,
++ char *argv[])
++{
++ return hostapd_cli_cmd(ctrl, "SET_ATTLM", 1, argc, argv);
++}
++
+ struct hostapd_cli_cmd {
+ const char *cmd;
+ int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+@@ -2055,6 +2061,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
+ " = Add a new link to a MLD AP"},
+ { "link_remove", hostapd_cli_cmd_link_remove, NULL,
+ " [count=<count>] = Remove affiliated link of a MLD AP"},
++ { "set_attlm", hostapd_cli_cmd_set_attlm, NULL,
++ " = Disable the affiliated AP of a MLD AP" },
+ { NULL, NULL, NULL, NULL }
+ };
+
+diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
+index 8b6aed0c7..a25a67cdd 100644
+--- a/src/ap/ap_drv_ops.c
++++ b/src/ap/ap_drv_ops.c
+@@ -619,6 +619,15 @@ int hostapd_if_link_remove(struct hostapd_data *hapd,
+ return hapd->driver->link_remove(hapd->drv_priv, type, ifname,
+ hapd->mld_link_id);
+ }
++
++
++int hostapd_drv_set_attlm(struct hostapd_data *hapd)
++{
++ if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_attlm)
++ return -1;
++
++ return hapd->driver->set_attlm(hapd->drv_priv, &hapd->mld->new_attlm);
++}
+ #endif /* CONFIG_IEEE80211BE */
+
+
+diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
+index e74284b96..7f108bc1d 100644
+--- a/src/ap/ap_drv_ops.h
++++ b/src/ap/ap_drv_ops.h
+@@ -68,6 +68,7 @@ int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+ int hostapd_if_link_remove(struct hostapd_data *hapd,
+ enum wpa_driver_if_type type,
+ const char *ifname, u8 link_id);
++int hostapd_drv_set_attlm(struct hostapd_data *hapd);
+ int hostapd_set_ieee8021x(struct hostapd_data *hapd,
+ struct wpa_bss_params *params);
+ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
+diff --git a/src/ap/beacon.c b/src/ap/beacon.c
+index 5293ee4c1..a5a885213 100644
+--- a/src/ap/beacon.c
++++ b/src/ap/beacon.c
+@@ -943,6 +943,9 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd,
+
+ pos = hostapd_eid_eht_capab(hapd, pos, IEEE80211_MODE_AP);
+ pos = hostapd_eid_eht_operation(hapd, pos);
++
++ if (!params->is_ml_sta_info)
++ pos = hostapd_eid_eht_attlm(hapd, pos);
+ }
+ #endif /* CONFIG_IEEE80211BE */
+
+@@ -2536,6 +2539,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
+ tailpos = hostapd_eid_eht_capab(hapd, tailpos,
+ IEEE80211_MODE_AP);
+ tailpos = hostapd_eid_eht_operation(hapd, tailpos);
++ tailpos = hostapd_eid_eht_attlm(hapd, tailpos);
+ }
+ #endif /* CONFIG_IEEE80211BE */
+
+diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
+index 9deb87c3d..17dc09807 100644
+--- a/src/ap/drv_callbacks.c
++++ b/src/ap/drv_callbacks.c
+@@ -1368,6 +1368,54 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
+ }
+
+
++#ifdef CONFIG_IEEE80211BE
++void hostapd_event_attlm(struct hostapd_data *hapd, struct attlm_event *attlm_event)
++{
++ struct hostapd_mld *mld = hapd->mld;
++ struct hostapd_data *p_hapd;
++ bool mld_indicate_disabled = false;
++
++ if (!hapd->conf->mld_ap || !mld)
++ return;
++
++ wpa_printf(MSG_DEBUG, "A-TTLM event");
++ /*
++ * T0: driver notifies A-TTLM has started and reports Switch Time TSF in TUs
++ * T1: driver notifies Switch Time Expiry of a started A-TTLM
++ * T2: driver notifies Duration Expiry of a started A-TTLM.
++ */
++ switch (attlm_event->event) {
++ case EVENT_ATTLM_STARTED:
++ ieee802_11_set_bss_critical_update(hapd,
++ BSS_CRIT_UPDATE_EVENT_ATTLM);
++ mld->new_attlm.switch_time_tsf_tu =
++ attlm_event->switch_time_tsf_tu;
++ break;
++ case EVENT_ATTLM_SWITCH_TIME_EXPIRED:
++ mld_indicate_disabled = true;
++ mld->new_attlm.switch_time_tsf_tu = 0;
++ os_get_reltime(&mld->new_attlm.start_time);
++ break;
++ case EVENT_ATTLM_END:
++ mld->new_attlm.valid = false;
++ break;
++ default:
++ wpa_printf(MSG_DEBUG, "Unsupported A-TTLM event");
++ return;
++ }
++
++ for_each_mld_link(p_hapd, hapd) {
++ if (mld->new_attlm.disabled_links & BIT(p_hapd->mld_link_id))
++ p_hapd->conf->mld_indicate_disabled =
++ mld_indicate_disabled;
++ }
++
++ ieee802_11_set_beacon(hapd);
++ hapd->eht_mld_bss_critical_update = 0;
++}
++#endif /* CONFIG_IEEE80211BE */
++
++
+ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
+ const u8 *addr, int reason_code)
+ {
+@@ -2755,6 +2803,11 @@ void hostapd_wpa_event(void *ctx, enum wpa_event_type event,
+ data->ch_switch.punct_bitmap,
+ event == EVENT_CH_SWITCH);
+ break;
++ case EVENT_ATTLM:
++#ifdef CONFIG_IEEE80211BE
++ hostapd_event_attlm(hapd, &data->attlm_event);
++#endif /* CONFIG_IEEE80211BE */
++ break;
+ case EVENT_CONNECT_FAILED_REASON:
+ if (!data)
+ break;
+diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
+index e34bc1fa8..9388f6070 100644
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -537,6 +537,14 @@ void hostapd_link_remove_cb(struct hostapd_data *hapd, u16 removed_links)
+ }
+ }
+
++
++int hostapd_mld_set_attlm(struct hostapd_data *hapd)
++{
++ if (!hapd->drv_priv)
++ return -1;
++
++ return hostapd_drv_set_attlm(hapd);
++}
+ #endif /* CONFIG_TESTING_OPTIONS */
+ #endif /* CONFIG_IEEE80211BE */
+
+diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
+index c6c286304..f69fa0062 100644
+--- a/src/ap/hostapd.h
++++ b/src/ap/hostapd.h
+@@ -553,6 +553,7 @@ struct hostapd_mld {
+ u16 active_links;
+ u16 removed_links;
+
++ struct attlm_settings new_attlm;
+ struct hostapd_data *fbss;
+ struct dl_list links; /* List head of all affiliated links */
+
+@@ -924,6 +925,7 @@ struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd,
+ u8 link_id);
+ int hostapd_link_remove(struct hostapd_data *hapd, u32 count);
+ void hostapd_link_remove_cb(struct hostapd_data *hapd, u16 removed_links);
++int hostapd_mld_set_attlm(struct hostapd_data *hapd);
+ bool hostapd_is_ml_partner(struct hostapd_data *hapd1,
+ struct hostapd_data *hapd2);
+ u8 hostapd_get_mld_id(struct hostapd_data *hapd);
+@@ -937,6 +939,8 @@ int hostapd_fill_cca_settings(struct hostapd_data *hapd,
+
+ #ifdef CONFIG_IEEE80211BE
+
++void hostapd_event_attlm(struct hostapd_data *hapd, struct attlm_event *attlm_event);
++
+ bool hostapd_mld_is_first_bss(struct hostapd_data *hapd);
+
+ #define for_each_mld_link(partner, self) \
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index 2861c09d7..886a21a66 100644
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -5088,6 +5088,7 @@ rsnxe_done:
+ p = hostapd_eid_eht_ml_assoc(hapd, sta, p);
+ p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
+ p = hostapd_eid_eht_operation(hapd, p);
++ p = hostapd_eid_eht_attlm(hapd, p);
+ }
+ #endif /* CONFIG_IEEE80211BE */
+
+@@ -6343,6 +6344,13 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
+ wpa_printf(MSG_DEBUG, "MGMT: Drop the frame - MLD not ready");
+ return 1;
+ }
++
++ if (hapd->conf->mld_ap && hapd->mld->new_attlm.valid &&
++ !hapd->mld->new_attlm.switch_time_tsf_tu &&
++ (hapd->mld->new_attlm.disabled_links & BIT(hapd->mld_link_id))) {
++ wpa_printf(MSG_DEBUG, "MGMT: Drop the frame - Disabled link");
++ return 1;
++ }
+ #endif /* CONFIG_IEEE80211BE */
+
+ if (fi && fi->freq)
+diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
+index 40301bce9..efaa20c86 100644
+--- a/src/ap/ieee802_11.h
++++ b/src/ap/ieee802_11.h
+@@ -243,6 +243,7 @@ u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid,
+ enum ieee80211_op_mode opmode);
+ u8 * hostapd_eid_non_inheritance(struct hostapd_data *hapd, u8 *eid);
+ u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid);
++u8 * hostapd_eid_eht_attlm(struct hostapd_data *hapd, u8 *eid);
+ u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ enum ieee80211_op_mode opmode,
+ const u8 *he_capab, size_t he_capab_len,
+diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
+index cad0d8437..2ed9414b8 100644
+--- a/src/ap/ieee802_11_eht.c
++++ b/src/ap/ieee802_11_eht.c
+@@ -595,7 +595,7 @@ static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd,
+ mld_cap |= active_links & EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK;
+
+ /* TODO: Advertise T2LM based on driver support as well */
+- mld_cap &= ~EHT_ML_MLD_CAPA_TID_TO_LINK_MAP_NEG_SUPP_MSK;
++ mld_cap |= EHT_ML_MLD_CAPA_TID_TO_LINK_MAP_ALL_TO_ALL;
+
+ wpa_printf(MSG_DEBUG, "MLD: MLD Capabilities and Operations=0x%x",
+ mld_cap);
+@@ -824,6 +824,72 @@ static u8 * hostapd_eid_eht_reconf_ml(struct hostapd_data *hapd, u8 *eid)
+ }
+
+
++u8 * hostapd_eid_eht_attlm(struct hostapd_data *hapd, u8 *eid)
++{
++ struct attlm_settings *attlm;
++ struct os_reltime now, res;
++ int i;
++ u16 control = 0;
++ u8 *pos = eid;
++ u16 enabled_links;
++
++ if (!hapd->conf->mld_ap)
++ return eid;
++
++ attlm = &hapd->mld->new_attlm;
++ if (!attlm || !attlm->valid)
++ return eid;
++
++ /* The length will be set at the end */
++ *pos++ = WLAN_EID_EXTENSION;
++ *pos++ = 0;
++ *pos++ = WLAN_EID_EXT_TID_TO_LINK_MAPPING;
++
++ /* Set the A-TTLM Control field */
++ control = (IEEE80211_TTLM_CONTROL_DIRECTION & attlm->direction) |
++ IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT |
++ IEEE80211_TTLM_CONTROL_INDICATOR;
++
++ if (attlm->switch_time_tsf_tu != 0)
++ control |= IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT;
++
++ WPA_PUT_LE16(pos, control);
++ pos += 2;
++
++ /* switch time & expected duration */
++ if (attlm->switch_time_tsf_tu != 0) {
++ WPA_PUT_LE16(pos, attlm->switch_time_tsf_tu);
++ pos += 2;
++
++ WPA_PUT_LE24(pos, (attlm->duration * 1000) >> 10);
++ pos += 3;
++ } else {
++ u32 diff;
++
++ os_get_reltime(&now);
++ os_reltime_sub(&now, &attlm->start_time, &res);
++ diff = (u32)os_reltime_in_ms(&res);
++
++ if (attlm->duration <= diff)
++ return eid;
++
++ WPA_PUT_LE24(pos, ((attlm->duration - diff) * 1000) >> 10);
++ pos += 3;
++ }
++
++ /* Link Mapping of each TID (0 - 7) */
++ enabled_links = hapd->conf->mld_allowed_links & ~attlm->disabled_links;
++ for (i = 0; i < 8; i++) {
++ WPA_PUT_LE16(pos, enabled_links);
++ pos += 2;
++ }
++
++ eid[1] = pos - eid - 2;
++
++ return pos;
++}
++
++
+ static size_t hostapd_eid_eht_ml_len(struct mld_info *info,
+ bool include_mld_id,
+ u8 eml_disable)
+diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
+index d93fa6660..afcc2f861 100644
+--- a/src/common/ieee802_11_defs.h
++++ b/src/common/ieee802_11_defs.h
+@@ -2912,6 +2912,19 @@ enum ieee80211_eht_ml_sub_elem {
+ EHT_ML_SUB_ELEM_FRAGMENT = 254,
+ };
+
++/* IEEE P802.11be/D5.0, 9.4.2.314 - TID-to-Link Mapping control */
++#define IEEE80211_TTLM_CONTROL_DIRECTION 0x0003
++#define IEEE80211_TTLM_CONTROL_DEF_LINK_MAP 0x0004
++#define IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT 0x0008
++#define IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT 0x0010
++#define IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE 0x0020
++#define IEEE80211_TTLM_CONTROL_INDICATOR 0xff00
++
++/* TTLM direction */
++#define IEEE80211_TTLM_DIRECTION_DOWN 0
++#define IEEE80211_TTLM_DIRECTION_UP 1
++#define IEEE80211_TTLM_DIRECTION_BOTH 2
++
+ /* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */
+ #define EDMG_BSS_OPERATING_CHANNELS_OFFSET 6
+ #define EDMG_OPERATING_CHANNEL_WIDTH_OFFSET 7
+diff --git a/src/drivers/driver.h b/src/drivers/driver.h
+index eb2a48381..fe327e560 100644
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -2805,6 +2805,29 @@ struct cca_settings {
+ int link_id;
+ };
+
++#ifdef CONFIG_IEEE80211BE
++/**
++ * struct attlm_settings - Setting for Advertised Tid-to-Link Mapping
++ * @valid: whether this A-TTLM is still valid
++ * @direction: direction of this A-TTLM
++ * @disabled_links: disabled link ID bitmap
++ * @switch_time: duration in ms to establish the A-TTLM
++ * @switch_time_tsf_tu: time in TUs that the A-TTLM is established. It should be
++ * the bits 10 to 25 of the TSF
++ * @duration_tu: duration in ms that the A-TTLM lasts
++ * @start_time: the relative time that this A-TTLM is entablished
++ */
++struct attlm_settings {
++ bool valid;
++ u8 direction;
++ u16 disabled_links;
++ u16 switch_time;
++ u16 switch_time_tsf_tu;
++ u32 duration;
++ struct os_reltime start_time;
++};
++#endif /* CONFIG_IEEE80211BE */
++
+ /* TDLS peer capabilities for send_tdls_mgmt() */
+ enum tdls_peer_capability {
+ TDLS_PEER_HT = BIT(0),
+@@ -5239,6 +5262,14 @@ struct wpa_driver_ops {
+ int (*link_remove)(void *priv, enum wpa_driver_if_type type,
+ const char *ifname, u8 link_id);
+
++ /**
++ * set_attlm - Set AP MLD advertised Tid-to-Link Mapping
++ * @priv: Private driver interface data
++ * @attlm: setting of Tid-to-Link Mapping
++ * Returns: 0 on success, negative value on failure
++ */
++ int (*set_attlm)(void *priv, struct attlm_settings *attlm);
++
+ /**
+ * is_drv_shared - Check whether the driver interface is shared
+ * @priv: Private driver interface data from init()
+@@ -6025,6 +6056,16 @@ enum wpa_event_type {
+ */
+ EVENT_LINK_CH_SWITCH_STARTED,
+
++ /**
++ * EVENT_ATTLM - MLD AP Advertised Tid-to-Link Mapping event
++ *
++ * This event is used by the driver to indicate the state transition of
++ * A-TTLM.
++ *
++ * Described in wpa_event_data.attlm_event
++ */
++ EVENT_ATTLM,
++
+ /**
+ * EVENT_TID_LINK_MAP - MLD event to set TID-to-link mapping
+ *
+@@ -6834,6 +6875,21 @@ union wpa_event_data {
+ u16 punct_bitmap;
+ } ch_switch;
+
++ /**
++ * struct attlm_event
++ * @switch_time_tsf_tu: the TSF of switch time in unit of TUs
++ * @started: the ATTLM is started or has been done.
++ * @switch_time_expired: the switch time has expired
++ */
++ struct attlm_event {
++ enum {
++ EVENT_ATTLM_STARTED,
++ EVENT_ATTLM_SWITCH_TIME_EXPIRED,
++ EVENT_ATTLM_END
++ } event;
++ u16 switch_time_tsf_tu;
++ } attlm_event;
++
+ /**
+ * struct connect_failed - Data for EVENT_CONNECT_FAILED_REASON
+ * @addr: Remote client address
+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
+index 1d334b75f..05b231c52 100644
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -11020,6 +11020,38 @@ static bool nl80211_is_drv_shared(void *priv, void *bss_ctx)
+ return true;
+ }
+
++
++static int nl80211_set_attlm(void *priv, struct attlm_settings *attlm)
++{
++ struct nl_msg *msg;
++ struct i802_bss *bss = priv;
++ struct wpa_driver_nl80211_data *drv = bss->drv;
++ int ret = -ENOBUFS;
++
++ wpa_printf(MSG_DEBUG, "nl80211: Set A-TTLM");
++
++ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_ATTLM)) ||
++ nla_put_u16(msg, NL80211_ATTR_MLO_LINK_DISABLED_BMP,
++ attlm->disabled_links) ||
++ nla_put_u16(msg, NL80211_ATTR_MLO_ATTLM_SWITCH_TIME,
++ attlm->switch_time) ||
++ nla_put_u32(msg, NL80211_ATTR_MLO_ATTLM_DURATION,
++ attlm->duration))
++ goto error;
++
++ ret = send_and_recv_cmd(drv, msg);
++ if (ret) {
++ wpa_printf(MSG_DEBUG,
++ "nl80211: disable link failed err=%d (%s)",
++ ret, strerror(-ret));
++ }
++
++ return ret;
++error:
++ nlmsg_free(msg);
++ wpa_printf(MSG_DEBUG, "nl80211: Could not build link disabling request");
++ return ret;
++}
+ #endif /* CONFIG_IEEE80211BE */
+
+
+@@ -15717,6 +15749,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+ .link_add = nl80211_link_add,
+ #ifdef CONFIG_IEEE80211BE
+ .link_remove = driver_nl80211_link_remove,
++ .set_attlm = nl80211_set_attlm,
+ .is_drv_shared = nl80211_is_drv_shared,
+ .link_sta_remove = wpa_driver_nl80211_link_sta_remove,
+ #endif /* CONFIG_IEEE80211BE */
+diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
+index 24a4bf3cf..863c4eb65 100644
+--- a/src/drivers/driver_nl80211_event.c
++++ b/src/drivers/driver_nl80211_event.c
+@@ -188,6 +188,8 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
+ C2S(NL80211_CMD_SET_HW_TIMESTAMP)
+ C2S(NL80211_CMD_LINKS_REMOVED)
+ C2S(NL80211_CMD_SET_TID_TO_LINK_MAPPING)
++ C2S(NL80211_CMD_ATTLM_EVENT)
++ C2S(NL80211_CMD_SET_ATTLM)
+ C2S(__NL80211_CMD_AFTER_LAST)
+ }
+ #undef C2S
+@@ -1313,6 +1315,53 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
+ }
+
+
++static void mlme_event_attlm(struct wpa_driver_nl80211_data *drv,
++ struct nlattr *ifindex,
++ struct nlattr *event,
++ struct nlattr *switch_time_tsf_tu)
++{
++ enum nl80211_attlm_event event_type;
++ union wpa_event_data data;
++ struct i802_bss *bss;
++ int ifidx;
++
++ ifidx = nla_get_u32(ifindex);
++ bss = get_bss_ifindex(drv, ifidx);
++ if (bss == NULL) {
++ wpa_printf(MSG_WARNING,
++ "nl80211: Unknown ifindex (%d) for A-TTLM, ignoring",
++ ifidx);
++ return;
++ }
++
++ if (!event)
++ return;
++
++ wpa_printf(MSG_DEBUG, "nl80211: %s: A-TTLM event", bss->ifname);
++
++ data.attlm_event.switch_time_tsf_tu = switch_time_tsf_tu ?
++ nla_get_u16(switch_time_tsf_tu) : 0;
++ event_type = nla_get_u32(event);
++ switch (event_type) {
++ case NL80211_ATTLM_STARTED:
++ data.attlm_event.event = EVENT_ATTLM_STARTED;
++ break;
++ case NL80211_ATTLM_SWITCH_TIME_EXPIRED:
++ data.attlm_event.event = EVENT_ATTLM_SWITCH_TIME_EXPIRED;
++ break;
++ case NL80211_ATTLM_END:
++ data.attlm_event.event = EVENT_ATTLM_END;
++ break;
++ default:
++ wpa_printf(MSG_DEBUG,
++ "nl80211: Unsupported A-TTLM event");
++ return;
++ }
++
++ wpa_supplicant_event(bss->ctx, EVENT_ATTLM, &data);
++}
++
++
+ static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
+ enum nl80211_commands cmd, struct nlattr *addr)
+ {
+@@ -4125,6 +4174,11 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
+ NULL,
+ 1);
+ break;
++ case NL80211_CMD_ATTLM_EVENT:
++ mlme_event_attlm(drv, tb[NL80211_ATTR_IFINDEX],
++ tb[NL80211_ATTR_MLO_ATTLM_EVENT],
++ tb[NL80211_ATTR_MLO_ATTLM_SWITCH_TIME_TSF_TU]);
++ break;
+ case NL80211_CMD_DISCONNECT:
+ mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
+ tb[NL80211_ATTR_MAC],
+diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
+index 13837297c..f997edd6e 100644
+--- a/src/drivers/nl80211_copy.h
++++ b/src/drivers/nl80211_copy.h
+@@ -1588,6 +1588,10 @@ enum nl80211_commands {
+
+ /* add new commands above here */
+
++ /* MTK internal */
++ NL80211_CMD_ATTLM_EVENT,
++ NL80211_CMD_SET_ATTLM,
++
+ /* used to define NL80211_CMD_MAX below */
+ __NL80211_CMD_AFTER_LAST,
+ NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
+@@ -3388,6 +3392,7 @@ enum nl80211_attrs {
+
+ NL80211_ATTR_MLO_LINKS,
+ NL80211_ATTR_MLO_LINK_ID,
++ NL80211_ATTR_MLO_LINK_DISABLED_BMP,
+ NL80211_ATTR_MLD_ADDR,
+
+ NL80211_ATTR_MLO_SUPPORT,
+@@ -3425,6 +3430,11 @@ enum nl80211_attrs {
+ /* MTK internal */
+ NL80211_ATTR_CNTDWN_OFFS_STA_PROF,
+
++ NL80211_ATTR_MLO_ATTLM_EVENT,
++ NL80211_ATTR_MLO_ATTLM_SWITCH_TIME,
++ NL80211_ATTR_MLO_ATTLM_DURATION,
++ NL80211_ATTR_MLO_ATTLM_SWITCH_TIME_TSF_TU,
++
+ __NL80211_ATTR_AFTER_LAST,
+ NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
+ NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
+@@ -8090,4 +8100,18 @@ enum nl80211_wiphy_radio_freq_range {
+ NL80211_WIPHY_RADIO_FREQ_ATTR_MAX = __NL80211_WIPHY_RADIO_FREQ_ATTR_LAST - 1,
+ };
+
++/**
++ * enum nl80211_attlm_event - type of events for Advertised Tid-to-Link
++ * Mapping operations
++ *
++ * @NL80211_ATTLM_STARTED: A A-TTLM request has been set and start to count down.
++ * @NL80211_ATTLM_SWITCH_TIME_EXPIRED: The switch time of A-TTLM has expired.
++ * @NL80211ATTLM_END: The A-TTLM has been done.
++ */
++enum nl80211_attlm_event {
++ NL80211_ATTLM_STARTED,
++ NL80211_ATTLM_SWITCH_TIME_EXPIRED,
++ NL80211_ATTLM_END,
++};
++
+ #endif /* __LINUX_NL80211_H */
+--
+2.18.0
+