blob: a6bdd093382de8ff65808774f38419b4622b59b5 [file] [log] [blame]
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