blob: a6bdd093382de8ff65808774f38419b4622b59b5 [file] [log] [blame]
developer05f3b2b2024-08-19 19:17:34 +08001From 8aabcfee2bb77e19fc592c27f1121c5725ee665f Mon Sep 17 00:00:00 2001
2From: Michael-CY Lee <michael-cy.lee@mediatek.com>
3Date: Wed, 3 Jul 2024 15:39:53 +0800
4Subject: [PATCH 119/126] mtk: hostapd: add A-TTLM support
5
6Add a data structure for AP MLD's Advertised Tid-to-Link Mapping (A-TTLM).
7Since it is MLD-level, this commit also adds it into struct hostapd_mld.
8
9There should be 'curr_attlm' and 'new_attlm', which means 2 TTLMs can be
10advertised at the same time ('curr_attlm' is used currently while
11'new_attlm' is about to be used)
12However, since the FW only support 1 attlm now, there is currently only
13'new_attlm'.
14
15There are 3 A-TTLM events from the driver, and hostap should handle them
16accordingly
171. A-TTLM started: link(s) sould start to advertise TTLM in the beacon.
182. A-TTLM switch time expired: enabled link(s) keep advertising TTLM in
19 the beacon with switch time excluded, whiel disabled link(s) should
20 stop TX/RX, including beacon
213. A-TTLM ended: all links stop advertising TTLM in the beacon, and
22 disabled link recover to TX/RX.
23
24This commit adds the support to set ATTLM, from hostapd_cli to driver.
25Setting an ATTLM requires 3 parameters
261. disabled_links: disabled link ID bitmap
272. switch_time: how much time it takes to start the A-TTLM (in ms)
283. duration: how long the A-TTLM lasts (in ms)
29
30Below is a hostapd_cli example that requires an A-TTLM starts to disable
31link_id=1 after 5 seconds and last for 20 seconds:
32$ hostapd_cli -i ap-mld-1 set_attlm disabled_links=2 switch_time=5000
33duration=20000
34
35Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
36---
37 hostapd/ctrl_iface.c | 66 +++++++++++++++++++++++++++++
38 hostapd/hostapd_cli.c | 8 ++++
39 src/ap/ap_drv_ops.c | 9 ++++
40 src/ap/ap_drv_ops.h | 1 +
41 src/ap/beacon.c | 4 ++
42 src/ap/drv_callbacks.c | 53 +++++++++++++++++++++++
43 src/ap/hostapd.c | 8 ++++
44 src/ap/hostapd.h | 4 ++
45 src/ap/ieee802_11.c | 8 ++++
46 src/ap/ieee802_11.h | 1 +
47 src/ap/ieee802_11_eht.c | 68 +++++++++++++++++++++++++++++-
48 src/common/ieee802_11_defs.h | 13 ++++++
49 src/drivers/driver.h | 56 ++++++++++++++++++++++++
50 src/drivers/driver_nl80211.c | 33 +++++++++++++++
51 src/drivers/driver_nl80211_event.c | 54 ++++++++++++++++++++++++
52 src/drivers/nl80211_copy.h | 24 +++++++++++
53 16 files changed, 409 insertions(+), 1 deletion(-)
54
55diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
56index 6db9fa617..2cd5487ca 100644
57--- a/hostapd/ctrl_iface.c
58+++ b/hostapd/ctrl_iface.c
59@@ -4039,6 +4039,68 @@ out:
60 return ret;
61 }
62
63+static int hostapd_ctrl_iface_set_attlm(struct hostapd_data *hapd, char *cmd,
64+ char *buf, size_t buflen)
65+{
66+#define MAX_SWITCH_TIME_MS 30000
67+#define MAX_DURATION_MS 16000000
68+ struct attlm_settings *attlm;
69+ struct hostapd_data *h;
70+ char *token, *context = NULL;
71+ u16 switch_time, disabled_links, valid_links = 0;
72+ u32 duration;
73+ int ret, i;
74+
75+ if (!hapd->conf->mld_ap || !hapd->mld)
76+ return -1;
77+
78+ attlm = &hapd->mld->new_attlm;
79+ if (attlm->valid) {
80+ wpa_printf(MSG_ERROR, "Busy: A-TTLM is on-going");
81+ return -1;
82+ }
83+
84+ for_each_mld_link(h, hapd)
85+ valid_links |= BIT(h->mld_link_id);
86+
87+ while ((token = str_token(cmd, " ", &context))) {
88+ if (os_strncmp(token, "switch_time=", 12) == 0) {
89+ switch_time = atoi(token + 12);
90+ if (switch_time > 0 && switch_time <= MAX_SWITCH_TIME_MS)
91+ continue;
92+ }
93+
94+ if (os_strncmp(token, "disabled_links=", 15) == 0) {
95+ disabled_links = atoi(token + 15);
96+
97+ if ((disabled_links & valid_links) &&
98+ !(disabled_links & ~valid_links))
99+ continue;
100+ }
101+
102+ if (os_strncmp(token, "duration=", 9) == 0) {
103+ duration = atoi(token + 9);
104+ if (duration > 0 && duration <= MAX_DURATION_MS)
105+ continue;
106+ }
107+
108+ wpa_printf(MSG_INFO, "CTRL: Invalid SET_ATTLM parameter: %s",
109+ token);
110+ return -1;
111+ }
112+
113+ wpa_printf(MSG_DEBUG,
114+ "MLD: set A-TTLM disabled_links=%u, switch_time=%u, duration=%u",
115+ disabled_links, switch_time, duration);
116+
117+ attlm->valid = true;
118+ attlm->direction = IEEE80211_TTLM_DIRECTION_BOTH;
119+ attlm->duration = duration;
120+ attlm->switch_time = switch_time;
121+ attlm->disabled_links = hapd->conf->mld_allowed_links & disabled_links;
122+
123+ return hostapd_mld_set_attlm(hapd);
124+}
125 #endif /* CONFIG_TESTING_OPTIONS */
126 #endif /* CONFIG_IEEE80211BE */
127
128@@ -6166,6 +6228,10 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
129 if (hostapd_ctrl_iface_link_add(hapd, buf + 9,
130 reply, reply_size))
131 reply_len = -1;
132+ } else if (os_strncmp(buf, "SET_ATTLM ", 10) == 0) {
133+ if (hostapd_ctrl_iface_set_attlm(hapd, buf + 10, reply,
134+ reply_size))
135+ reply_len = -1;
136 #endif /* CONFIG_TESTING_OPTIONS */
137 #endif /* CONFIG_IEEE80211BE */
138 } else if (os_strncmp(buf, "SET_EDCCA ", 10) == 0) {
139diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
140index 9dcc0d74b..f81211ba4 100644
141--- a/hostapd/hostapd_cli.c
142+++ b/hostapd/hostapd_cli.c
143@@ -1791,6 +1791,12 @@ static int hostapd_cli_cmd_link_remove(struct wpa_ctrl *ctrl, int argc,
144 return hostapd_cli_cmd(ctrl, "LINK_REMOVE", 1, argc, argv);
145 }
146
147+static int hostapd_cli_cmd_set_attlm(struct wpa_ctrl *ctrl, int argc,
148+ char *argv[])
149+{
150+ return hostapd_cli_cmd(ctrl, "SET_ATTLM", 1, argc, argv);
151+}
152+
153 struct hostapd_cli_cmd {
154 const char *cmd;
155 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
156@@ -2055,6 +2061,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
157 " = Add a new link to a MLD AP"},
158 { "link_remove", hostapd_cli_cmd_link_remove, NULL,
159 " [count=<count>] = Remove affiliated link of a MLD AP"},
160+ { "set_attlm", hostapd_cli_cmd_set_attlm, NULL,
161+ " = Disable the affiliated AP of a MLD AP" },
162 { NULL, NULL, NULL, NULL }
163 };
164
165diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
166index 8b6aed0c7..a25a67cdd 100644
167--- a/src/ap/ap_drv_ops.c
168+++ b/src/ap/ap_drv_ops.c
169@@ -619,6 +619,15 @@ int hostapd_if_link_remove(struct hostapd_data *hapd,
170 return hapd->driver->link_remove(hapd->drv_priv, type, ifname,
171 hapd->mld_link_id);
172 }
173+
174+
175+int hostapd_drv_set_attlm(struct hostapd_data *hapd)
176+{
177+ if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_attlm)
178+ return -1;
179+
180+ return hapd->driver->set_attlm(hapd->drv_priv, &hapd->mld->new_attlm);
181+}
182 #endif /* CONFIG_IEEE80211BE */
183
184
185diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
186index e74284b96..7f108bc1d 100644
187--- a/src/ap/ap_drv_ops.h
188+++ b/src/ap/ap_drv_ops.h
189@@ -68,6 +68,7 @@ int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
190 int hostapd_if_link_remove(struct hostapd_data *hapd,
191 enum wpa_driver_if_type type,
192 const char *ifname, u8 link_id);
193+int hostapd_drv_set_attlm(struct hostapd_data *hapd);
194 int hostapd_set_ieee8021x(struct hostapd_data *hapd,
195 struct wpa_bss_params *params);
196 int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
197diff --git a/src/ap/beacon.c b/src/ap/beacon.c
198index 5293ee4c1..a5a885213 100644
199--- a/src/ap/beacon.c
200+++ b/src/ap/beacon.c
201@@ -943,6 +943,9 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd,
202
203 pos = hostapd_eid_eht_capab(hapd, pos, IEEE80211_MODE_AP);
204 pos = hostapd_eid_eht_operation(hapd, pos);
205+
206+ if (!params->is_ml_sta_info)
207+ pos = hostapd_eid_eht_attlm(hapd, pos);
208 }
209 #endif /* CONFIG_IEEE80211BE */
210
211@@ -2536,6 +2539,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
212 tailpos = hostapd_eid_eht_capab(hapd, tailpos,
213 IEEE80211_MODE_AP);
214 tailpos = hostapd_eid_eht_operation(hapd, tailpos);
215+ tailpos = hostapd_eid_eht_attlm(hapd, tailpos);
216 }
217 #endif /* CONFIG_IEEE80211BE */
218
219diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
220index 9deb87c3d..17dc09807 100644
221--- a/src/ap/drv_callbacks.c
222+++ b/src/ap/drv_callbacks.c
223@@ -1368,6 +1368,54 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
224 }
225
226
227+#ifdef CONFIG_IEEE80211BE
228+void hostapd_event_attlm(struct hostapd_data *hapd, struct attlm_event *attlm_event)
229+{
230+ struct hostapd_mld *mld = hapd->mld;
231+ struct hostapd_data *p_hapd;
232+ bool mld_indicate_disabled = false;
233+
234+ if (!hapd->conf->mld_ap || !mld)
235+ return;
236+
237+ wpa_printf(MSG_DEBUG, "A-TTLM event");
238+ /*
239+ * T0: driver notifies A-TTLM has started and reports Switch Time TSF in TUs
240+ * T1: driver notifies Switch Time Expiry of a started A-TTLM
241+ * T2: driver notifies Duration Expiry of a started A-TTLM.
242+ */
243+ switch (attlm_event->event) {
244+ case EVENT_ATTLM_STARTED:
245+ ieee802_11_set_bss_critical_update(hapd,
246+ BSS_CRIT_UPDATE_EVENT_ATTLM);
247+ mld->new_attlm.switch_time_tsf_tu =
248+ attlm_event->switch_time_tsf_tu;
249+ break;
250+ case EVENT_ATTLM_SWITCH_TIME_EXPIRED:
251+ mld_indicate_disabled = true;
252+ mld->new_attlm.switch_time_tsf_tu = 0;
253+ os_get_reltime(&mld->new_attlm.start_time);
254+ break;
255+ case EVENT_ATTLM_END:
256+ mld->new_attlm.valid = false;
257+ break;
258+ default:
259+ wpa_printf(MSG_DEBUG, "Unsupported A-TTLM event");
260+ return;
261+ }
262+
263+ for_each_mld_link(p_hapd, hapd) {
264+ if (mld->new_attlm.disabled_links & BIT(p_hapd->mld_link_id))
265+ p_hapd->conf->mld_indicate_disabled =
266+ mld_indicate_disabled;
267+ }
268+
269+ ieee802_11_set_beacon(hapd);
270+ hapd->eht_mld_bss_critical_update = 0;
271+}
272+#endif /* CONFIG_IEEE80211BE */
273+
274+
275 void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
276 const u8 *addr, int reason_code)
277 {
278@@ -2755,6 +2803,11 @@ void hostapd_wpa_event(void *ctx, enum wpa_event_type event,
279 data->ch_switch.punct_bitmap,
280 event == EVENT_CH_SWITCH);
281 break;
282+ case EVENT_ATTLM:
283+#ifdef CONFIG_IEEE80211BE
284+ hostapd_event_attlm(hapd, &data->attlm_event);
285+#endif /* CONFIG_IEEE80211BE */
286+ break;
287 case EVENT_CONNECT_FAILED_REASON:
288 if (!data)
289 break;
290diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
291index e34bc1fa8..9388f6070 100644
292--- a/src/ap/hostapd.c
293+++ b/src/ap/hostapd.c
294@@ -537,6 +537,14 @@ void hostapd_link_remove_cb(struct hostapd_data *hapd, u16 removed_links)
295 }
296 }
297
298+
299+int hostapd_mld_set_attlm(struct hostapd_data *hapd)
300+{
301+ if (!hapd->drv_priv)
302+ return -1;
303+
304+ return hostapd_drv_set_attlm(hapd);
305+}
306 #endif /* CONFIG_TESTING_OPTIONS */
307 #endif /* CONFIG_IEEE80211BE */
308
309diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
310index c6c286304..f69fa0062 100644
311--- a/src/ap/hostapd.h
312+++ b/src/ap/hostapd.h
313@@ -553,6 +553,7 @@ struct hostapd_mld {
314 u16 active_links;
315 u16 removed_links;
316
317+ struct attlm_settings new_attlm;
318 struct hostapd_data *fbss;
319 struct dl_list links; /* List head of all affiliated links */
320
321@@ -924,6 +925,7 @@ struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd,
322 u8 link_id);
323 int hostapd_link_remove(struct hostapd_data *hapd, u32 count);
324 void hostapd_link_remove_cb(struct hostapd_data *hapd, u16 removed_links);
325+int hostapd_mld_set_attlm(struct hostapd_data *hapd);
326 bool hostapd_is_ml_partner(struct hostapd_data *hapd1,
327 struct hostapd_data *hapd2);
328 u8 hostapd_get_mld_id(struct hostapd_data *hapd);
329@@ -937,6 +939,8 @@ int hostapd_fill_cca_settings(struct hostapd_data *hapd,
330
331 #ifdef CONFIG_IEEE80211BE
332
333+void hostapd_event_attlm(struct hostapd_data *hapd, struct attlm_event *attlm_event);
334+
335 bool hostapd_mld_is_first_bss(struct hostapd_data *hapd);
336
337 #define for_each_mld_link(partner, self) \
338diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
339index 2861c09d7..886a21a66 100644
340--- a/src/ap/ieee802_11.c
341+++ b/src/ap/ieee802_11.c
342@@ -5088,6 +5088,7 @@ rsnxe_done:
343 p = hostapd_eid_eht_ml_assoc(hapd, sta, p);
344 p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
345 p = hostapd_eid_eht_operation(hapd, p);
346+ p = hostapd_eid_eht_attlm(hapd, p);
347 }
348 #endif /* CONFIG_IEEE80211BE */
349
350@@ -6343,6 +6344,13 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
351 wpa_printf(MSG_DEBUG, "MGMT: Drop the frame - MLD not ready");
352 return 1;
353 }
354+
355+ if (hapd->conf->mld_ap && hapd->mld->new_attlm.valid &&
356+ !hapd->mld->new_attlm.switch_time_tsf_tu &&
357+ (hapd->mld->new_attlm.disabled_links & BIT(hapd->mld_link_id))) {
358+ wpa_printf(MSG_DEBUG, "MGMT: Drop the frame - Disabled link");
359+ return 1;
360+ }
361 #endif /* CONFIG_IEEE80211BE */
362
363 if (fi && fi->freq)
364diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
365index 40301bce9..efaa20c86 100644
366--- a/src/ap/ieee802_11.h
367+++ b/src/ap/ieee802_11.h
368@@ -243,6 +243,7 @@ u8 * hostapd_eid_eht_capab(struct hostapd_data *hapd, u8 *eid,
369 enum ieee80211_op_mode opmode);
370 u8 * hostapd_eid_non_inheritance(struct hostapd_data *hapd, u8 *eid);
371 u8 * hostapd_eid_eht_operation(struct hostapd_data *hapd, u8 *eid);
372+u8 * hostapd_eid_eht_attlm(struct hostapd_data *hapd, u8 *eid);
373 u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta,
374 enum ieee80211_op_mode opmode,
375 const u8 *he_capab, size_t he_capab_len,
376diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
377index cad0d8437..2ed9414b8 100644
378--- a/src/ap/ieee802_11_eht.c
379+++ b/src/ap/ieee802_11_eht.c
380@@ -595,7 +595,7 @@ static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd,
381 mld_cap |= active_links & EHT_ML_MLD_CAPA_MAX_NUM_SIM_LINKS_MASK;
382
383 /* TODO: Advertise T2LM based on driver support as well */
384- mld_cap &= ~EHT_ML_MLD_CAPA_TID_TO_LINK_MAP_NEG_SUPP_MSK;
385+ mld_cap |= EHT_ML_MLD_CAPA_TID_TO_LINK_MAP_ALL_TO_ALL;
386
387 wpa_printf(MSG_DEBUG, "MLD: MLD Capabilities and Operations=0x%x",
388 mld_cap);
389@@ -824,6 +824,72 @@ static u8 * hostapd_eid_eht_reconf_ml(struct hostapd_data *hapd, u8 *eid)
390 }
391
392
393+u8 * hostapd_eid_eht_attlm(struct hostapd_data *hapd, u8 *eid)
394+{
395+ struct attlm_settings *attlm;
396+ struct os_reltime now, res;
397+ int i;
398+ u16 control = 0;
399+ u8 *pos = eid;
400+ u16 enabled_links;
401+
402+ if (!hapd->conf->mld_ap)
403+ return eid;
404+
405+ attlm = &hapd->mld->new_attlm;
406+ if (!attlm || !attlm->valid)
407+ return eid;
408+
409+ /* The length will be set at the end */
410+ *pos++ = WLAN_EID_EXTENSION;
411+ *pos++ = 0;
412+ *pos++ = WLAN_EID_EXT_TID_TO_LINK_MAPPING;
413+
414+ /* Set the A-TTLM Control field */
415+ control = (IEEE80211_TTLM_CONTROL_DIRECTION & attlm->direction) |
416+ IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT |
417+ IEEE80211_TTLM_CONTROL_INDICATOR;
418+
419+ if (attlm->switch_time_tsf_tu != 0)
420+ control |= IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT;
421+
422+ WPA_PUT_LE16(pos, control);
423+ pos += 2;
424+
425+ /* switch time & expected duration */
426+ if (attlm->switch_time_tsf_tu != 0) {
427+ WPA_PUT_LE16(pos, attlm->switch_time_tsf_tu);
428+ pos += 2;
429+
430+ WPA_PUT_LE24(pos, (attlm->duration * 1000) >> 10);
431+ pos += 3;
432+ } else {
433+ u32 diff;
434+
435+ os_get_reltime(&now);
436+ os_reltime_sub(&now, &attlm->start_time, &res);
437+ diff = (u32)os_reltime_in_ms(&res);
438+
439+ if (attlm->duration <= diff)
440+ return eid;
441+
442+ WPA_PUT_LE24(pos, ((attlm->duration - diff) * 1000) >> 10);
443+ pos += 3;
444+ }
445+
446+ /* Link Mapping of each TID (0 - 7) */
447+ enabled_links = hapd->conf->mld_allowed_links & ~attlm->disabled_links;
448+ for (i = 0; i < 8; i++) {
449+ WPA_PUT_LE16(pos, enabled_links);
450+ pos += 2;
451+ }
452+
453+ eid[1] = pos - eid - 2;
454+
455+ return pos;
456+}
457+
458+
459 static size_t hostapd_eid_eht_ml_len(struct mld_info *info,
460 bool include_mld_id,
461 u8 eml_disable)
462diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
463index d93fa6660..afcc2f861 100644
464--- a/src/common/ieee802_11_defs.h
465+++ b/src/common/ieee802_11_defs.h
466@@ -2912,6 +2912,19 @@ enum ieee80211_eht_ml_sub_elem {
467 EHT_ML_SUB_ELEM_FRAGMENT = 254,
468 };
469
470+/* IEEE P802.11be/D5.0, 9.4.2.314 - TID-to-Link Mapping control */
471+#define IEEE80211_TTLM_CONTROL_DIRECTION 0x0003
472+#define IEEE80211_TTLM_CONTROL_DEF_LINK_MAP 0x0004
473+#define IEEE80211_TTLM_CONTROL_SWITCH_TIME_PRESENT 0x0008
474+#define IEEE80211_TTLM_CONTROL_EXPECTED_DUR_PRESENT 0x0010
475+#define IEEE80211_TTLM_CONTROL_LINK_MAP_SIZE 0x0020
476+#define IEEE80211_TTLM_CONTROL_INDICATOR 0xff00
477+
478+/* TTLM direction */
479+#define IEEE80211_TTLM_DIRECTION_DOWN 0
480+#define IEEE80211_TTLM_DIRECTION_UP 1
481+#define IEEE80211_TTLM_DIRECTION_BOTH 2
482+
483 /* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */
484 #define EDMG_BSS_OPERATING_CHANNELS_OFFSET 6
485 #define EDMG_OPERATING_CHANNEL_WIDTH_OFFSET 7
486diff --git a/src/drivers/driver.h b/src/drivers/driver.h
487index eb2a48381..fe327e560 100644
488--- a/src/drivers/driver.h
489+++ b/src/drivers/driver.h
490@@ -2805,6 +2805,29 @@ struct cca_settings {
491 int link_id;
492 };
493
494+#ifdef CONFIG_IEEE80211BE
495+/**
496+ * struct attlm_settings - Setting for Advertised Tid-to-Link Mapping
497+ * @valid: whether this A-TTLM is still valid
498+ * @direction: direction of this A-TTLM
499+ * @disabled_links: disabled link ID bitmap
500+ * @switch_time: duration in ms to establish the A-TTLM
501+ * @switch_time_tsf_tu: time in TUs that the A-TTLM is established. It should be
502+ * the bits 10 to 25 of the TSF
503+ * @duration_tu: duration in ms that the A-TTLM lasts
504+ * @start_time: the relative time that this A-TTLM is entablished
505+ */
506+struct attlm_settings {
507+ bool valid;
508+ u8 direction;
509+ u16 disabled_links;
510+ u16 switch_time;
511+ u16 switch_time_tsf_tu;
512+ u32 duration;
513+ struct os_reltime start_time;
514+};
515+#endif /* CONFIG_IEEE80211BE */
516+
517 /* TDLS peer capabilities for send_tdls_mgmt() */
518 enum tdls_peer_capability {
519 TDLS_PEER_HT = BIT(0),
520@@ -5239,6 +5262,14 @@ struct wpa_driver_ops {
521 int (*link_remove)(void *priv, enum wpa_driver_if_type type,
522 const char *ifname, u8 link_id);
523
524+ /**
525+ * set_attlm - Set AP MLD advertised Tid-to-Link Mapping
526+ * @priv: Private driver interface data
527+ * @attlm: setting of Tid-to-Link Mapping
528+ * Returns: 0 on success, negative value on failure
529+ */
530+ int (*set_attlm)(void *priv, struct attlm_settings *attlm);
531+
532 /**
533 * is_drv_shared - Check whether the driver interface is shared
534 * @priv: Private driver interface data from init()
535@@ -6025,6 +6056,16 @@ enum wpa_event_type {
536 */
537 EVENT_LINK_CH_SWITCH_STARTED,
538
539+ /**
540+ * EVENT_ATTLM - MLD AP Advertised Tid-to-Link Mapping event
541+ *
542+ * This event is used by the driver to indicate the state transition of
543+ * A-TTLM.
544+ *
545+ * Described in wpa_event_data.attlm_event
546+ */
547+ EVENT_ATTLM,
548+
549 /**
550 * EVENT_TID_LINK_MAP - MLD event to set TID-to-link mapping
551 *
552@@ -6834,6 +6875,21 @@ union wpa_event_data {
553 u16 punct_bitmap;
554 } ch_switch;
555
556+ /**
557+ * struct attlm_event
558+ * @switch_time_tsf_tu: the TSF of switch time in unit of TUs
559+ * @started: the ATTLM is started or has been done.
560+ * @switch_time_expired: the switch time has expired
561+ */
562+ struct attlm_event {
563+ enum {
564+ EVENT_ATTLM_STARTED,
565+ EVENT_ATTLM_SWITCH_TIME_EXPIRED,
566+ EVENT_ATTLM_END
567+ } event;
568+ u16 switch_time_tsf_tu;
569+ } attlm_event;
570+
571 /**
572 * struct connect_failed - Data for EVENT_CONNECT_FAILED_REASON
573 * @addr: Remote client address
574diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
575index 1d334b75f..05b231c52 100644
576--- a/src/drivers/driver_nl80211.c
577+++ b/src/drivers/driver_nl80211.c
578@@ -11020,6 +11020,38 @@ static bool nl80211_is_drv_shared(void *priv, void *bss_ctx)
579 return true;
580 }
581
582+
583+static int nl80211_set_attlm(void *priv, struct attlm_settings *attlm)
584+{
585+ struct nl_msg *msg;
586+ struct i802_bss *bss = priv;
587+ struct wpa_driver_nl80211_data *drv = bss->drv;
588+ int ret = -ENOBUFS;
589+
590+ wpa_printf(MSG_DEBUG, "nl80211: Set A-TTLM");
591+
592+ if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_ATTLM)) ||
593+ nla_put_u16(msg, NL80211_ATTR_MLO_LINK_DISABLED_BMP,
594+ attlm->disabled_links) ||
595+ nla_put_u16(msg, NL80211_ATTR_MLO_ATTLM_SWITCH_TIME,
596+ attlm->switch_time) ||
597+ nla_put_u32(msg, NL80211_ATTR_MLO_ATTLM_DURATION,
598+ attlm->duration))
599+ goto error;
600+
601+ ret = send_and_recv_cmd(drv, msg);
602+ if (ret) {
603+ wpa_printf(MSG_DEBUG,
604+ "nl80211: disable link failed err=%d (%s)",
605+ ret, strerror(-ret));
606+ }
607+
608+ return ret;
609+error:
610+ nlmsg_free(msg);
611+ wpa_printf(MSG_DEBUG, "nl80211: Could not build link disabling request");
612+ return ret;
613+}
614 #endif /* CONFIG_IEEE80211BE */
615
616
617@@ -15717,6 +15749,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
618 .link_add = nl80211_link_add,
619 #ifdef CONFIG_IEEE80211BE
620 .link_remove = driver_nl80211_link_remove,
621+ .set_attlm = nl80211_set_attlm,
622 .is_drv_shared = nl80211_is_drv_shared,
623 .link_sta_remove = wpa_driver_nl80211_link_sta_remove,
624 #endif /* CONFIG_IEEE80211BE */
625diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
626index 24a4bf3cf..863c4eb65 100644
627--- a/src/drivers/driver_nl80211_event.c
628+++ b/src/drivers/driver_nl80211_event.c
629@@ -188,6 +188,8 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd)
630 C2S(NL80211_CMD_SET_HW_TIMESTAMP)
631 C2S(NL80211_CMD_LINKS_REMOVED)
632 C2S(NL80211_CMD_SET_TID_TO_LINK_MAPPING)
633+ C2S(NL80211_CMD_ATTLM_EVENT)
634+ C2S(NL80211_CMD_SET_ATTLM)
635 C2S(__NL80211_CMD_AFTER_LAST)
636 }
637 #undef C2S
638@@ -1313,6 +1315,53 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
639 }
640
641
642+static void mlme_event_attlm(struct wpa_driver_nl80211_data *drv,
643+ struct nlattr *ifindex,
644+ struct nlattr *event,
645+ struct nlattr *switch_time_tsf_tu)
646+{
647+ enum nl80211_attlm_event event_type;
648+ union wpa_event_data data;
649+ struct i802_bss *bss;
650+ int ifidx;
651+
652+ ifidx = nla_get_u32(ifindex);
653+ bss = get_bss_ifindex(drv, ifidx);
654+ if (bss == NULL) {
655+ wpa_printf(MSG_WARNING,
656+ "nl80211: Unknown ifindex (%d) for A-TTLM, ignoring",
657+ ifidx);
658+ return;
659+ }
660+
661+ if (!event)
662+ return;
663+
664+ wpa_printf(MSG_DEBUG, "nl80211: %s: A-TTLM event", bss->ifname);
665+
666+ data.attlm_event.switch_time_tsf_tu = switch_time_tsf_tu ?
667+ nla_get_u16(switch_time_tsf_tu) : 0;
668+ event_type = nla_get_u32(event);
669+ switch (event_type) {
670+ case NL80211_ATTLM_STARTED:
671+ data.attlm_event.event = EVENT_ATTLM_STARTED;
672+ break;
673+ case NL80211_ATTLM_SWITCH_TIME_EXPIRED:
674+ data.attlm_event.event = EVENT_ATTLM_SWITCH_TIME_EXPIRED;
675+ break;
676+ case NL80211_ATTLM_END:
677+ data.attlm_event.event = EVENT_ATTLM_END;
678+ break;
679+ default:
680+ wpa_printf(MSG_DEBUG,
681+ "nl80211: Unsupported A-TTLM event");
682+ return;
683+ }
684+
685+ wpa_supplicant_event(bss->ctx, EVENT_ATTLM, &data);
686+}
687+
688+
689 static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
690 enum nl80211_commands cmd, struct nlattr *addr)
691 {
692@@ -4125,6 +4174,11 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
693 NULL,
694 1);
695 break;
696+ case NL80211_CMD_ATTLM_EVENT:
697+ mlme_event_attlm(drv, tb[NL80211_ATTR_IFINDEX],
698+ tb[NL80211_ATTR_MLO_ATTLM_EVENT],
699+ tb[NL80211_ATTR_MLO_ATTLM_SWITCH_TIME_TSF_TU]);
700+ break;
701 case NL80211_CMD_DISCONNECT:
702 mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
703 tb[NL80211_ATTR_MAC],
704diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
705index 13837297c..f997edd6e 100644
706--- a/src/drivers/nl80211_copy.h
707+++ b/src/drivers/nl80211_copy.h
708@@ -1588,6 +1588,10 @@ enum nl80211_commands {
709
710 /* add new commands above here */
711
712+ /* MTK internal */
713+ NL80211_CMD_ATTLM_EVENT,
714+ NL80211_CMD_SET_ATTLM,
715+
716 /* used to define NL80211_CMD_MAX below */
717 __NL80211_CMD_AFTER_LAST,
718 NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
719@@ -3388,6 +3392,7 @@ enum nl80211_attrs {
720
721 NL80211_ATTR_MLO_LINKS,
722 NL80211_ATTR_MLO_LINK_ID,
723+ NL80211_ATTR_MLO_LINK_DISABLED_BMP,
724 NL80211_ATTR_MLD_ADDR,
725
726 NL80211_ATTR_MLO_SUPPORT,
727@@ -3425,6 +3430,11 @@ enum nl80211_attrs {
728 /* MTK internal */
729 NL80211_ATTR_CNTDWN_OFFS_STA_PROF,
730
731+ NL80211_ATTR_MLO_ATTLM_EVENT,
732+ NL80211_ATTR_MLO_ATTLM_SWITCH_TIME,
733+ NL80211_ATTR_MLO_ATTLM_DURATION,
734+ NL80211_ATTR_MLO_ATTLM_SWITCH_TIME_TSF_TU,
735+
736 __NL80211_ATTR_AFTER_LAST,
737 NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
738 NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
739@@ -8090,4 +8100,18 @@ enum nl80211_wiphy_radio_freq_range {
740 NL80211_WIPHY_RADIO_FREQ_ATTR_MAX = __NL80211_WIPHY_RADIO_FREQ_ATTR_LAST - 1,
741 };
742
743+/**
744+ * enum nl80211_attlm_event - type of events for Advertised Tid-to-Link
745+ * Mapping operations
746+ *
747+ * @NL80211_ATTLM_STARTED: A A-TTLM request has been set and start to count down.
748+ * @NL80211_ATTLM_SWITCH_TIME_EXPIRED: The switch time of A-TTLM has expired.
749+ * @NL80211ATTLM_END: The A-TTLM has been done.
750+ */
751+enum nl80211_attlm_event {
752+ NL80211_ATTLM_STARTED,
753+ NL80211_ATTLM_SWITCH_TIME_EXPIRED,
754+ NL80211_ATTLM_END,
755+};
756+
757 #endif /* __LINUX_NL80211_H */
758--
7592.18.0
760