blob: f34a8adafcdd679d1db8632cc1d313a6f45565bd [file] [log] [blame]
developer05f3b2b2024-08-19 19:17:34 +08001From d46df816cadde59bde528c08db281923874152cc Mon Sep 17 00:00:00 2001
2From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Tue, 23 Apr 2024 16:03:19 +0800
4Subject: [PATCH 085/126] mtk: hostapd: add critical update support
5
6Add critical update support
7modification: wmm configuration
8inclusion: channel switch
9(affiliated link's per-STA profile CSA/eCSA countdown &
10 channel switch wrapper is included)
11Note that max channel switch time IE is not implemented
12in hostapd yet.
13
141.Add max channel switch time IE
15Note that fw will find the MCST IE on its own,
16so there is no need to send the offset of the MCST IE to the kernel.
17The MCST's value is currently hardcoded to 500 TUs, since the WFA test plan
18restricts it to not exceeding 500 TUs (APUT 4.22.1).
192. Add critical update support for radar triggered channel switch
20
21According to the test plan of APUT 4.44, the CSA after beacon should also
22include the CU flag and increase BPCC due to operation IE modification.
23Additionally, avoid setting beacons in hostapd_event_ch_switch after CSA
24is finished since it would conflict with the CSA after beacon.
25
26Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
27Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
28---
29 hostapd/ctrl_iface.c | 88 +++++++++++++++++++
30 hostapd/hostapd_cli.c | 8 ++
31 hostapd/main.c | 4 +-
32 src/ap/beacon.c | 161 ++++++++++++++++++++++++++++++++++-
33 src/ap/beacon.h | 37 ++++++++
34 src/ap/dfs.c | 12 +++
35 src/ap/drv_callbacks.c | 1 -
36 src/ap/hostapd.c | 85 +++++++++++++++++-
37 src/ap/hostapd.h | 5 ++
38 src/ap/ieee802_11.c | 15 ++++
39 src/ap/ieee802_11_eht.c | 7 +-
40 src/ap/sta_info.h | 6 ++
41 src/ap/ucode.c | 9 +-
42 src/common/ieee802_11_defs.h | 1 +
43 src/drivers/driver.h | 1 +
44 src/drivers/driver_nl80211.c | 53 +++++++-----
45 src/drivers/nl80211_copy.h | 8 ++
46 17 files changed, 470 insertions(+), 31 deletions(-)
47
48diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
49index e19502d1d..ebe9053cf 100644
50--- a/hostapd/ctrl_iface.c
51+++ b/hostapd/ctrl_iface.c
52@@ -2911,6 +2911,18 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
53 ret = err;
54 num_err++;
55 }
56+
57+#ifdef CONFIG_IEEE80211BE
58+ if (iface->bss[i]->conf->mld_ap)
59+ hostapd_update_aff_link_beacon(iface->bss[i], settings.cs_count);
60+
61+ /*
62+ * Currently, no FW notification event for clearing CU flag after DTIM period.
63+ * Also, another CU or set beacon is not allowed during CSA period.
64+ * Therefore, just clear it manually here for workaround.
65+ */
66+ iface->bss[i]->eht_mld_bss_critical_update = 0;
67+#endif /* CONFIG_IEEE80211BE */
68 }
69
70 return (iface->num_bss == num_err) ? ret : 0;
71@@ -5279,6 +5291,79 @@ hostapd_ctrl_iface_dump_csi(struct hostapd_data *hapd, char *cmd,
72 return 0;
73 }
74
75+static int
76+hostapd_ctrl_iface_wmm(struct hostapd_data *hapd, char *cmd, char *buf,
77+ size_t buflen)
78+{
79+ char *pos = cmd, *ac, *token, *context = NULL;
80+ struct hostapd_wmm_ac_params *acp;
81+ int num;
82+
83+ if (!hapd->conf->mld_ap)
84+ return -1;
85+
86+ ac = pos;
87+ pos = os_strchr(pos, ' ');
88+ if (pos)
89+ *pos++ = '\0';
90+
91+ if (os_strncmp(ac, "BE", 2) == 0) {
92+ num = 0;
93+ } else if (os_strncmp(ac, "BK", 2) == 0) {
94+ num = 1;
95+ } else if (os_strncmp(ac, "VI", 2) == 0) {
96+ num = 2;
97+ } else if (os_strncmp(ac, "VO", 2) == 0) {
98+ num = 3;
99+ } else {
100+ wpa_printf(MSG_ERROR, "Unknown AC name '%s'", ac);
101+ return -1;
102+ }
103+
104+ acp = &hapd->iconf->wmm_ac_params[num];
105+
106+ /* if only ac is provied, show wmm params */
107+ if (!pos)
108+ return os_snprintf(buf, buflen,
109+ "link=%d ac=%s cwmin=%d cwmax=%d aifs=%d txop_limit=%d\n",
110+ hapd->mld_link_id, ac, acp->cwmin, acp->cwmax, acp->aifs, acp->txop_limit);
111+
112+ while ((token = str_token(pos, " ", &context))) {
113+ if (os_strncmp(token, "cwmin=", 6) == 0) {
114+ acp->cwmin = atoi(token + 6);
115+ continue;
116+ }
117+
118+ if (os_strncmp(token, "cwmax=", 6) == 0) {
119+ acp->cwmax = atoi(token + 6);
120+ continue;
121+ }
122+
123+ if (os_strncmp(token, "aifs=", 5) == 0) {
124+ acp->aifs = atoi(token + 5);
125+ continue;
126+ }
127+
128+ if (os_strncmp(token, "txop_limit=", 11) == 0) {
129+ acp->txop_limit = atoi(token + 11);
130+ continue;
131+ }
132+
133+ wpa_printf(MSG_ERROR, "CTRL: Invalid WMM parameter: %s", token);
134+ return -1;
135+ }
136+
137+ if (acp->cwmin > acp->cwmax)
138+ return -1;
139+
140+ ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_EDCA);
141+
142+ if (ieee802_11_set_beacon(hapd))
143+ return -1;
144+
145+ return os_snprintf(buf, buflen, "OK\n");
146+}
147+
148 static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
149 char *buf, char *reply,
150 int reply_size,
151@@ -5946,6 +6031,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
152 } else if (os_strncmp(buf, "DUMP_CSI ", 8) == 0) {
153 reply_len = hostapd_ctrl_iface_dump_csi(hapd, buf + 9,
154 reply, reply_size);
155+ } else if (os_strncmp(buf, "WMM", 3) == 0) {
156+ reply_len = hostapd_ctrl_iface_wmm(hapd, buf + 4,
157+ reply, reply_size);
158 } else {
159 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
160 reply_len = 16;
161diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
162index 4e94db21d..e578c5b7e 100644
163--- a/hostapd/hostapd_cli.c
164+++ b/hostapd/hostapd_cli.c
165@@ -1767,6 +1767,12 @@ static int hostapd_cli_cmd_get_pp(struct wpa_ctrl *ctrl, int argc,
166 return hostapd_cli_cmd(ctrl, "get_pp", 1, argc, argv);
167 }
168
169+static int hostapd_cli_cmd_wmm(struct wpa_ctrl *ctrl, int argc,
170+ char *argv[])
171+{
172+ return hostapd_cli_cmd(ctrl, "WMM", 1, argc, argv);
173+}
174+
175 struct hostapd_cli_cmd {
176 const char *cmd;
177 int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
178@@ -2023,6 +2029,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
179 " = Set preamble puncture mode"},
180 { "get_pp", hostapd_cli_cmd_get_pp, NULL,
181 " = Get preamble puncture status"},
182+ { "wmm", hostapd_cli_cmd_wmm, NULL,
183+ " = <ac> [cwmin=] [cwmax=] [aifs=] [txop_limit=]"},
184 { NULL, NULL, NULL, NULL }
185 };
186
187diff --git a/hostapd/main.c b/hostapd/main.c
188index e790f18ce..8ecec6c1a 100644
189--- a/hostapd/main.c
190+++ b/hostapd/main.c
191@@ -330,8 +330,8 @@ setup_mld:
192 return -1;
193 }
194
195- /* Initialize the BSS parameter change to 1 */
196- hapd->eht_mld_bss_param_change = 1;
197+ /* Initialize the BSS parameter change to 0 */
198+ hapd->eht_mld_bss_param_change = 0;
199
200 wpa_printf(MSG_DEBUG,
201 "MLD: Set link_id=%u, mld_addr=" MACSTR
202diff --git a/src/ap/beacon.c b/src/ap/beacon.c
203index 88e35acc2..9b5c4fc1e 100644
204--- a/src/ap/beacon.c
205+++ b/src/ap/beacon.c
206@@ -514,6 +514,23 @@ static u8 * hostapd_eid_ecsa(struct hostapd_data *hapd, u8 *eid)
207 }
208
209
210+static u8 * hostapd_eid_max_chsw_time(struct hostapd_data *hapd, u8 *eid)
211+{
212+ u32 max_chsw_time = 800;
213+
214+ if (!hapd->cs_freq_params.channel)
215+ return eid;
216+
217+ *eid++ = WLAN_EID_EXTENSION;
218+ *eid++ = 4;
219+ *eid++ = WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME;
220+ WPA_PUT_LE24(eid, max_chsw_time);
221+ eid += 3;
222+
223+ return eid;
224+}
225+
226+
227 static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
228 {
229 u8 op_class, channel;
230@@ -878,6 +895,7 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd,
231 #endif /* CONFIG_IEEE80211AX */
232
233 pos = hostapd_eid_wb_chsw_wrapper(hapd, pos);
234+ pos = hostapd_eid_max_chsw_time(hapd, pos);
235
236 if (!params->is_ml_sta_info)
237 pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP,
238@@ -2185,6 +2203,63 @@ static u8 * hostapd_fils_discovery(struct hostapd_data *hapd,
239 #endif /* CONFIG_FILS */
240
241
242+static void hostapd_fill_bcn_sta_profile(struct hostapd_data *hapd,
243+ struct mld_info *info)
244+{
245+ struct hostapd_data *h;
246+
247+ if (!info)
248+ return;
249+
250+ os_memset(info, 0, sizeof(*info));
251+
252+ for_each_mld_link(h, hapd) {
253+ unsigned int link_id = h->mld_link_id;
254+ struct mld_link_info *link = &info->links[link_id];
255+ u8 *epos, *csa_pos, buf[EHT_ML_MAX_STA_PROF_LEN];
256+
257+ if (!h->started || h == hapd ||
258+ h->eht_mld_bss_critical_update != BSS_CRIT_UPDATE_ALL)
259+ continue;
260+
261+ link->valid = true;
262+ os_memcpy(link->local_addr, h->own_addr, ETH_ALEN);
263+
264+ /* Build per-STA profile */
265+ epos = buf;
266+ /* Capabilities */
267+ WPA_PUT_LE16(epos, hostapd_own_capab_info(h));
268+ epos += 2;
269+
270+ /* CSA IE */
271+ csa_pos = hostapd_eid_csa(h, epos);
272+ if (csa_pos != epos)
273+ link->sta_prof_csa_offset = csa_pos - 1 - buf;
274+ epos = csa_pos;
275+
276+ /* eCSA IE */
277+ csa_pos = hostapd_eid_ecsa(h, epos);
278+ if (csa_pos != epos)
279+ link->sta_prof_ecsa_offset = csa_pos - 1 - buf;
280+ epos = csa_pos;
281+
282+ /* channel switch wrapper */
283+ epos = hostapd_eid_wb_chsw_wrapper(h, epos);
284+
285+ /* max channel switch time */
286+ epos = hostapd_eid_max_chsw_time(h, epos);
287+
288+ link->resp_sta_profile_len = epos - buf;
289+ link->resp_sta_profile = os_memdup(buf, link->resp_sta_profile_len);
290+
291+ /* TODO:
292+ * 1. add other IEs
293+ * 2. handle per-STA profile inheritance
294+ * 3. handle csa offset if fragmentation is required
295+ */
296+ }
297+}
298+
299 int ieee802_11_build_ap_params(struct hostapd_data *hapd,
300 struct wpa_driver_ap_params *params)
301 {
302@@ -2394,6 +2469,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
303 #endif /* CONFIG_IEEE80211AX */
304
305 tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos);
306+ tailpos = hostapd_eid_max_chsw_time(hapd, tailpos);
307
308 tailpos = hostapd_eid_rnr(hapd, tailpos, WLAN_FC_STYPE_BEACON, true);
309 tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
310@@ -2423,9 +2499,30 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
311
312 #ifdef CONFIG_IEEE80211BE
313 if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
314- if (hapd->conf->mld_ap)
315- tailpos = hostapd_eid_eht_ml_beacon(hapd, NULL,
316+ if (hapd->conf->mld_ap) {
317+ struct hostapd_data *h;
318+ struct mld_info info;
319+ struct mld_link_info *link;
320+ u32 base;
321+ u8 link_id, *ml_pos = tailpos;
322+
323+ hostapd_fill_bcn_sta_profile(hapd, &info);
324+ tailpos = hostapd_eid_eht_ml_beacon(hapd, &info,
325 tailpos, false);
326+
327+ for_each_mld_link(h, hapd) {
328+ link_id = h->mld_link_id;
329+ link = &info.links[link_id];
330+ base = ml_pos - tail + link->sta_prof_offset;
331+ if (link->sta_prof_csa_offset)
332+ hapd->cs_c_off_sta_prof[link_id] =
333+ base + link->sta_prof_csa_offset;
334+ if (link->sta_prof_ecsa_offset)
335+ hapd->cs_c_off_ecsa_sta_prof[link_id] =
336+ base + link->sta_prof_ecsa_offset;
337+ }
338+ ap_sta_free_sta_profile(&info);
339+ }
340 tailpos = hostapd_eid_eht_capab(hapd, tailpos,
341 IEEE80211_MODE_AP);
342 tailpos = hostapd_eid_eht_operation(hapd, tailpos);
343@@ -2803,7 +2900,8 @@ void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd)
344 int ieee802_11_set_beacon(struct hostapd_data *hapd)
345 {
346 struct hostapd_iface *iface = hapd->iface;
347- int ret;
348+ struct hostapd_data *h;
349+ int ret, link_id;
350 size_t i, j;
351 bool is_6g, hapd_mld = false;
352
353@@ -2846,6 +2944,17 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
354 }
355 }
356
357+#ifdef CONFIG_IEEE80211BE
358+ /* clear critical update flag for UPDATE_SINGLE type, for other types,
359+ * we should get some notified events from driver
360+ */
361+ if (hapd->conf->mld_ap) {
362+ for_each_mld_link(h, hapd)
363+ if (h->eht_mld_bss_critical_update == BSS_CRIT_UPDATE_SINGLE)
364+ h->eht_mld_bss_critical_update = 0;
365+ }
366+#endif /* CONFIG_IEEE80211BE */
367+
368 return 0;
369 }
370
371@@ -2880,4 +2989,50 @@ int ieee802_11_update_beacons(struct hostapd_iface *iface)
372 return ret;
373 }
374
375+
376+int ieee802_11_set_bss_critical_update(struct hostapd_data *hapd,
377+ enum bss_crit_update_event event)
378+{
379+ if (!hapd->conf->mld_ap)
380+ return 0;
381+
382+ switch (event) {
383+ case BSS_CRIT_UPDATE_EVENT_CSA:
384+ case BSS_CRIT_UPDATE_EVENT_ECSA:
385+ case BSS_CRIT_UPDATE_EVENT_QUIET:
386+ case BSS_CRIT_UPDATE_EVENT_WBCS:
387+ case BSS_CRIT_UPDATE_EVENT_CS_WRAP:
388+ case BSS_CRIT_UPDATE_EVENT_OP_MODE_NOTIF:
389+ case BSS_CRIT_UPDATE_EVENT_QUIET_CH:
390+ case BSS_CRIT_UPDATE_EVENT_CCA:
391+ case BSS_CRIT_UPDATE_EVENT_BCAST_TWT:
392+ case BSS_CRIT_UPDATE_EVENT_BCAST_TWT_PARAM_SET:
393+ case BSS_CRIT_UPDATE_EVENT_IDX_ADJUST_FACTOR:
394+ case BSS_CRIT_UPDATE_EVENT_TPE:
395+ hapd->eht_mld_bss_param_change += 1;
396+ hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_ALL;
397+ return 0;
398+ case BSS_CRIT_UPDATE_EVENT_EDCA:
399+ case BSS_CRIT_UPDATE_EVENT_DSSS:
400+ case BSS_CRIT_UPDATE_EVENT_HT_OPERATION:
401+ case BSS_CRIT_UPDATE_EVENT_VHT_OPERATION:
402+ case BSS_CRIT_UPDATE_EVENT_HE_OPERATION:
403+ case BSS_CRIT_UPDATE_EVENT_MU_EDCA:
404+ case BSS_CRIT_UPDATE_EVENT_SR:
405+ case BSS_CRIT_UPDATE_EVENT_UORA:
406+ case BSS_CRIT_UPDATE_EVENT_EHT_OPERATION:
407+ hapd->eht_mld_bss_param_change += 1;
408+ hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_SINGLE;
409+ return 0;
410+ case BSS_CRIT_UPDATE_EVENT_RECONFIG:
411+ case BSS_CRIT_UPDATE_EVENT_ADD_LINK:
412+ case BSS_CRIT_UPDATE_EVENT_ATTLM:
413+ hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_FLAG;
414+ return 0;
415+ default:
416+ hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_NONE;
417+ return -1;
418+ }
419+}
420+
421 #endif /* CONFIG_NATIVE_WINDOWS */
422diff --git a/src/ap/beacon.h b/src/ap/beacon.h
423index e381542a8..809393902 100644
424--- a/src/ap/beacon.h
425+++ b/src/ap/beacon.h
426@@ -12,12 +12,49 @@
427
428 struct ieee80211_mgmt;
429
430+enum bss_crit_update_event {
431+ BSS_CRIT_UPDATE_EVENT_CSA,
432+ BSS_CRIT_UPDATE_EVENT_ECSA,
433+ BSS_CRIT_UPDATE_EVENT_EDCA,
434+ BSS_CRIT_UPDATE_EVENT_QUIET,
435+ BSS_CRIT_UPDATE_EVENT_DSSS,
436+ BSS_CRIT_UPDATE_EVENT_HT_OPERATION,
437+ BSS_CRIT_UPDATE_EVENT_WBCS,
438+ BSS_CRIT_UPDATE_EVENT_CS_WRAP,
439+ BSS_CRIT_UPDATE_EVENT_OP_MODE_NOTIF,
440+ BSS_CRIT_UPDATE_EVENT_QUIET_CH,
441+ BSS_CRIT_UPDATE_EVENT_VHT_OPERATION,
442+ BSS_CRIT_UPDATE_EVENT_HE_OPERATION,
443+ BSS_CRIT_UPDATE_EVENT_BCAST_TWT,
444+ BSS_CRIT_UPDATE_EVENT_BCAST_TWT_PARAM_SET,
445+ BSS_CRIT_UPDATE_EVENT_CCA,
446+ BSS_CRIT_UPDATE_EVENT_MU_EDCA,
447+ BSS_CRIT_UPDATE_EVENT_SR,
448+ BSS_CRIT_UPDATE_EVENT_UORA,
449+ BSS_CRIT_UPDATE_EVENT_IDX_ADJUST_FACTOR,
450+ BSS_CRIT_UPDATE_EVENT_EHT_OPERATION,
451+ BSS_CRIT_UPDATE_EVENT_TPE,
452+ BSS_CRIT_UPDATE_EVENT_CH_CHANGED,
453+ BSS_CRIT_UPDATE_EVENT_RECONFIG,
454+ BSS_CRIT_UPDATE_EVENT_ADD_LINK,
455+ BSS_CRIT_UPDATE_EVENT_ATTLM
456+};
457+
458+enum {
459+ BSS_CRIT_UPDATE_NONE,
460+ BSS_CRIT_UPDATE_SINGLE,
461+ BSS_CRIT_UPDATE_ALL,
462+ BSS_CRIT_UPDATE_FLAG
463+};
464+
465 void handle_probe_req(struct hostapd_data *hapd,
466 const struct ieee80211_mgmt *mgmt, size_t len,
467 int ssi_signal);
468 void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd);
469 int ieee802_11_set_beacon(struct hostapd_data *hapd);
470 int ieee802_11_set_beacons(struct hostapd_iface *iface);
471+int ieee802_11_set_bss_critical_update(struct hostapd_data *hapd,
472+ enum bss_crit_update_event event);
473 int ieee802_11_update_beacons(struct hostapd_iface *iface);
474 int ieee802_11_build_ap_params(struct hostapd_data *hapd,
475 struct wpa_driver_ap_params *params);
476diff --git a/src/ap/dfs.c b/src/ap/dfs.c
477index fc7699973..697e6364c 100644
478--- a/src/ap/dfs.c
479+++ b/src/ap/dfs.c
480@@ -1120,6 +1120,18 @@ static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
481 err = hostapd_switch_channel(iface->bss[i], &csa_settings);
482 if (err)
483 num_err++;
484+
485+#ifdef CONFIG_IEEE80211BE
486+ if (iface->bss[i]->conf->mld_ap)
487+ hostapd_update_aff_link_beacon(iface->bss[i], csa_settings.cs_count);
488+
489+ /*
490+ * Currently, no FW notification event for clearing CU flag after DTIM period.
491+ * Also, another CU or set beacon is not allowed during CSA period.
492+ * Therefore, just clear it manually here for workaround.
493+ */
494+ iface->bss[i]->eht_mld_bss_critical_update = 0;
495+#endif /* CONFIG_IEEE80211BE */
496 }
497
498 if (num_err == iface->num_bss) {
499diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
500index 1107fd70e..705acfb67 100644
501--- a/src/ap/drv_callbacks.c
502+++ b/src/ap/drv_callbacks.c
503@@ -1314,7 +1314,6 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
504 if (hapd->csa_in_progress &&
505 freq == hapd->cs_freq_params.freq) {
506 hostapd_cleanup_cs_params(hapd);
507- ieee802_11_set_beacon(hapd);
508
509 wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
510 "freq=%d dfs=%d", freq, is_dfs);
511diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
512index 2c9e54b23..f03a6242f 100644
513--- a/src/ap/hostapd.c
514+++ b/src/ap/hostapd.c
515@@ -4524,6 +4524,9 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
516 old_punct_bitmap = iface->conf->punct_bitmap;
517 iface->conf->punct_bitmap = settings->punct_bitmap;
518 #endif /* CONFIG_IEEE80211BE */
519+
520+ /* Another CU in the new channel due to OP element modification */
521+ ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_EHT_OPERATION);
522 ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
523
524 /* change back the configuration */
525@@ -4541,20 +4544,32 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
526 hapd->cs_count = settings->cs_count;
527 hapd->cs_block_tx = settings->block_tx;
528
529+#ifdef CONFIG_IEEE80211BE
530+ /* Restore BPCC to build the CSA beacon */
531+ hapd->eht_mld_bss_param_change--;
532+ hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_ALL;
533+#endif /* CONFIG_IEEE80211BE */
534+
535 ret = hostapd_build_beacon_data(hapd, &settings->beacon_csa);
536 if (ret) {
537 free_beacon_data(&settings->beacon_after);
538 return ret;
539 }
540
541+ /* Change back to the final BPCC and CU flag */
542+ ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_EHT_OPERATION);
543+
544 settings->counter_offset_beacon[0] = hapd->cs_c_off_beacon;
545 settings->counter_offset_presp[0] = hapd->cs_c_off_proberesp;
546 settings->counter_offset_beacon[1] = hapd->cs_c_off_ecsa_beacon;
547 settings->counter_offset_presp[1] = hapd->cs_c_off_ecsa_proberesp;
548 settings->link_id = -1;
549+ settings->freq_params.link_id = -1;
550 #ifdef CONFIG_IEEE80211BE
551- if (hapd->conf->mld_ap)
552+ if (hapd->conf->mld_ap) {
553 settings->link_id = hapd->mld_link_id;
554+ settings->freq_params.link_id = hapd->mld_link_id;
555+ }
556 #endif /* CONFIG_IEEE80211BE */
557
558 #ifdef CONFIG_IEEE80211AX
559@@ -4616,6 +4631,8 @@ int hostapd_switch_channel(struct hostapd_data *hapd,
560 return -1;
561 }
562
563+ ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_CSA);
564+
565 ret = hostapd_fill_csa_settings(hapd, settings);
566 if (ret)
567 return ret;
568@@ -4637,6 +4654,72 @@ int hostapd_switch_channel(struct hostapd_data *hapd,
569 return 0;
570 }
571
572+int hostapd_update_aff_link_beacon(struct hostapd_data *hapd, u8 cs_count)
573+{
574+ struct hostapd_data *h;
575+ unsigned int cs_link_id = hapd->mld_link_id;
576+ int cs_channel = hapd->cs_freq_params.channel;
577+
578+ /* TODO: add beacon offload driver flag */
579+ for_each_mld_link(h, hapd) {
580+ struct hostapd_config *conf = h->iconf;
581+ struct hostapd_hw_modes *mode = h->iface->current_mode;
582+ struct csa_settings settings = {};
583+ unsigned int link_id = h->mld_link_id;
584+ int ret;
585+
586+ if (!h->started || h == hapd)
587+ continue;
588+
589+ hostapd_set_freq_params(&settings.freq_params, conf->hw_mode,
590+ hostapd_hw_get_freq(h, conf->channel),
591+ conf->channel, conf->enable_edmg,
592+ conf->edmg_channel, conf->ieee80211n,
593+ conf->ieee80211ac, conf->ieee80211ax,
594+ conf->ieee80211be, conf->secondary_channel,
595+ hostapd_get_oper_chwidth(conf),
596+ hostapd_get_oper_centr_freq_seg0_idx(conf),
597+ hostapd_get_oper_centr_freq_seg1_idx(conf),
598+ conf->vht_capab,
599+ mode ? &mode->he_capab[IEEE80211_MODE_AP] : NULL,
600+ mode ? &mode->eht_capab[IEEE80211_MODE_AP] : NULL,
601+ hostapd_get_punct_bitmap(h));
602+ hapd->cs_freq_params.channel = 0;
603+ ret = hostapd_build_beacon_data(h, &settings.beacon_after);
604+ if (ret)
605+ return ret;
606+
607+ hapd->cs_freq_params.channel = cs_channel;
608+ /* Restore BPCC to build the RNR for the CS link */
609+ hapd->eht_mld_bss_param_change--;
610+ hapd->eht_mld_bss_critical_update = BSS_CRIT_UPDATE_ALL;
611+ ret = hostapd_build_beacon_data(h, &settings.beacon_csa);
612+ if (ret) {
613+ free_beacon_data(&settings.beacon_after);
614+ return ret;
615+ }
616+
617+ /* Change back to the final BPCC and CU flag */
618+ ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_EHT_OPERATION);
619+
620+ settings.counter_offset_sta_prof[cs_link_id][0] =
621+ h->cs_c_off_sta_prof[cs_link_id];
622+ settings.counter_offset_sta_prof[cs_link_id][1] =
623+ h->cs_c_off_ecsa_sta_prof[cs_link_id];
624+ settings.link_id = cs_link_id;
625+ settings.freq_params.link_id = link_id;
626+ settings.cs_count = cs_count;
627+ settings.punct_bitmap = conf->punct_bitmap;
628+ ret = hostapd_drv_switch_channel(h, &settings);
629+ free_beacon_data(&settings.beacon_csa);
630+ free_beacon_data(&settings.beacon_after);
631+ if (ret)
632+ return ret;
633+ }
634+
635+ return 0;
636+}
637+
638
639 void
640 hostapd_switch_channel_fallback(struct hostapd_iface *iface,
641diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
642index 4db67096b..99d5a01d6 100644
643--- a/src/ap/hostapd.h
644+++ b/src/ap/hostapd.h
645@@ -342,6 +342,9 @@ struct hostapd_data {
646 unsigned int cs_c_off_ecsa_beacon;
647 unsigned int cs_c_off_ecsa_proberesp;
648
649+ unsigned int cs_c_off_sta_prof[MAX_NUM_MLD_LINKS];
650+ unsigned int cs_c_off_ecsa_sta_prof[MAX_NUM_MLD_LINKS];
651+
652 #ifdef CONFIG_IEEE80211AX
653 bool cca_in_progress;
654 u8 cca_count;
655@@ -501,6 +504,7 @@ struct hostapd_data {
656
657 #ifdef CONFIG_IEEE80211BE
658 u8 eht_mld_bss_param_change;
659+ u8 eht_mld_bss_critical_update;
660 struct hostapd_mld *mld;
661 struct dl_list link;
662 u8 mld_link_id;
663@@ -850,6 +854,7 @@ void hostapd_chan_switch_config(struct hostapd_data *hapd,
664 struct hostapd_freq_params *freq_params);
665 int hostapd_switch_channel(struct hostapd_data *hapd,
666 struct csa_settings *settings);
667+int hostapd_update_aff_link_beacon(struct hostapd_data *hapd, u8 cs_count);
668 void
669 hostapd_switch_channel_fallback(struct hostapd_iface *iface,
670 const struct hostapd_freq_params *freq_params);
671diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
672index 1365bc822..bb508fe79 100644
673--- a/src/ap/ieee802_11.c
674+++ b/src/ap/ieee802_11.c
675@@ -282,6 +282,7 @@ u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
676
677 u16 hostapd_own_capab_info(struct hostapd_data *hapd)
678 {
679+ struct hostapd_data *h;
680 int capab = WLAN_CAPABILITY_ESS;
681 int privacy = 0;
682 int dfs;
683@@ -342,6 +343,18 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd)
684 }
685 }
686
687+#ifdef CONFIG_IEEE80211BE
688+ if (hapd->conf->mld_ap) {
689+ for_each_mld_link(h, hapd) {
690+ if (h->eht_mld_bss_critical_update) {
691+ capab |= WLAN_CAPABILITY_PBCC;
692+ break;
693+ }
694+ }
695+ }
696+#endif /* CONFIG_IEEE80211BE */
697+
698+
699 return capab;
700 }
701
702@@ -7838,6 +7851,8 @@ static bool hostapd_eid_rnr_bss(struct hostapd_data *hapd,
703 (MAX_NUM_MLD_LINKS | 0xF0);
704 /* BPCC (Bit 3 to Bit 0) */
705 *eid = is_partner ? ((param_ch & 0xF0) >> 4) : 0x0F;
706+ if (bss->eht_mld_bss_critical_update == BSS_CRIT_UPDATE_ALL)
707+ *eid |= RNR_TBTT_INFO_MLD_PARAM2_ALL_UPDATE_INC;
708 #ifdef CONFIG_TESTING_OPTIONS
709 if (bss->conf->mld_indicate_disabled)
710 *eid |= RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED;
711diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
712index a04eb23e0..2b5c06d6d 100644
713--- a/src/ap/ieee802_11_eht.c
714+++ b/src/ap/ieee802_11_eht.c
715@@ -495,7 +495,7 @@ static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd,
716 wpabuf_put_u8(buf, hapd->mld_link_id);
717
718 /* Currently hard code the BSS Parameters Change Count to 0x1 */
719- wpabuf_put_u8(buf, 0x1);
720+ wpabuf_put_u8(buf, hapd->eht_mld_bss_param_change);
721
722 wpa_printf(MSG_DEBUG, "MLD: EML Capabilities=0x%x",
723 hapd->iface->mld_eml_capa);
724@@ -593,11 +593,14 @@ static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd,
725 wpabuf_put_u8(buf, link_bss->conf->dtim_period);
726
727 /* BSS Parameters Change Count */
728- wpabuf_put_u8(buf, hapd->eht_mld_bss_param_change);
729+ wpabuf_put_u8(buf, link_bss->eht_mld_bss_param_change);
730
731 if (!link->resp_sta_profile)
732 continue;
733
734+#define EXT_EID_TAG_LEN 3
735+ link->sta_prof_offset = wpabuf_len(buf) + EXT_EID_TAG_LEN;
736+
737 /* Fragment the sub element if needed */
738 if (total_len <= 255) {
739 wpabuf_put_data(buf, link->resp_sta_profile,
740diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
741index 67b97671a..60b33f049 100644
742--- a/src/ap/sta_info.h
743+++ b/src/ap/sta_info.h
744@@ -89,6 +89,12 @@ struct mld_info {
745 u16 status;
746 u16 resp_sta_profile_len;
747 u8 *resp_sta_profile;
748+
749+ u32 sta_prof_csa_offset;
750+ u32 sta_prof_ecsa_offset;
751+ u32 sta_prof_offset;
752+
753+ const u8 *rsne, *rsnxe;
754 } links[MAX_NUM_MLD_LINKS];
755 };
756
757diff --git a/src/ap/ucode.c b/src/ap/ucode.c
758index da1c4c1ac..a72193282 100644
759--- a/src/ap/ucode.c
760+++ b/src/ap/ucode.c
761@@ -738,9 +738,16 @@ uc_hostapd_iface_switch_channel(uc_vm_t *vm, size_t nargs)
762 wpa_printf(MSG_INFO, " * center_freq2 is %d\n",
763 csa.freq_params.center_freq2);
764
765- for (i = 0; i < iface->num_bss; i++)
766+ for (i = 0; i < iface->num_bss; i++) {
767 ret = hostapd_switch_channel(iface->bss[i], &csa);
768
769+ if (iface->bss[i]->conf->mld_ap)
770+ hostapd_update_aff_link_beacon(iface->bss[i], csa.cs_count);
771+
772+ /* FIXME: remove this line after CU event merged */
773+ iface->bss[i]->eht_mld_bss_critical_update = 0;
774+ }
775+
776 return ucv_boolean_new(!ret);
777 }
778
779diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
780index c380d0c7e..efb584c66 100644
781--- a/src/common/ieee802_11_defs.h
782+++ b/src/common/ieee802_11_defs.h
783@@ -504,6 +504,7 @@
784 #define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
785 #define WLAN_EID_EXT_SPATIAL_REUSE 39
786 #define WLAN_EID_EXT_COLOR_CHANGE_ANNOUNCEMENT 42
787+#define WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME 52
788 #define WLAN_EID_EXT_OCV_OCI 54
789 #define WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION 55
790 #define WLAN_EID_EXT_NON_INHERITANCE 56
791diff --git a/src/drivers/driver.h b/src/drivers/driver.h
792index b75580374..924a1baba 100644
793--- a/src/drivers/driver.h
794+++ b/src/drivers/driver.h
795@@ -2763,6 +2763,7 @@ struct csa_settings {
796
797 u16 counter_offset_beacon[2];
798 u16 counter_offset_presp[2];
799+ u16 counter_offset_sta_prof[MAX_NUM_MLD_LINKS][2];
800
801 u16 punct_bitmap;
802 int link_id;
803diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
804index 8b64c3983..555c97bf7 100644
805--- a/src/drivers/driver_nl80211.c
806+++ b/src/drivers/driver_nl80211.c
807@@ -11417,9 +11417,10 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
808 struct i802_bss *bss = priv;
809 struct wpa_driver_nl80211_data *drv = bss->drv;
810 struct nlattr *beacon_csa;
811- int ret = -ENOBUFS;
812- int csa_off_len = 0;
813- int i;
814+ int i, csa_off_len = 0, ret = -ENOBUFS;
815+ unsigned int cs_link_id = settings->link_id;
816+ u16 *counter_offset_beacon = settings->counter_offset_beacon;
817+ u16 *counter_offset_presp = settings->counter_offset_presp;
818
819 wpa_printf(MSG_DEBUG,
820 "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d channel=%d sec_channel_offset=%d width=%d cf1=%d cf2=%d puncturing_bitmap=0x%04x link_id=%d%s%s%s)",
821@@ -11431,7 +11432,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
822 settings->freq_params.center_freq1,
823 settings->freq_params.center_freq2,
824 settings->punct_bitmap,
825- settings->link_id,
826+ settings->freq_params.link_id,
827 settings->freq_params.ht_enabled ? " ht" : "",
828 settings->freq_params.vht_enabled ? " vht" : "",
829 settings->freq_params.he_enabled ? " he" : "");
830@@ -11451,18 +11452,19 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
831 * counters match. This implementation assumes that there are only two
832 * counters.
833 */
834- if (settings->counter_offset_beacon[0] &&
835- !settings->counter_offset_beacon[1]) {
836+ if (cs_link_id != settings->freq_params.link_id) {
837+ counter_offset_beacon = settings->counter_offset_sta_prof[cs_link_id];
838+ counter_offset_presp = NULL;
839+ }
840+
841+ if (counter_offset_beacon[0] && !counter_offset_beacon[1]) {
842 csa_off_len = 1;
843- } else if (settings->counter_offset_beacon[1] &&
844- !settings->counter_offset_beacon[0]) {
845+ } else if (counter_offset_beacon[1] && !counter_offset_beacon[0]) {
846 csa_off_len = 1;
847- settings->counter_offset_beacon[0] =
848- settings->counter_offset_beacon[1];
849- settings->counter_offset_presp[0] =
850- settings->counter_offset_presp[1];
851- } else if (settings->counter_offset_beacon[1] &&
852- settings->counter_offset_beacon[0]) {
853+ counter_offset_beacon[0] = counter_offset_beacon[1];
854+ if (counter_offset_presp)
855+ counter_offset_presp[0] = counter_offset_presp[1];
856+ } else if (counter_offset_beacon[1] && counter_offset_beacon[0]) {
857 csa_off_len = 2;
858 } else {
859 wpa_printf(MSG_ERROR, "nl80211: No CSA counters provided");
860@@ -11481,14 +11483,18 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
861 return -EINVAL;
862
863 for (i = 0; i < csa_off_len; i++) {
864- u16 csa_c_off_bcn = settings->counter_offset_beacon[i];
865- u16 csa_c_off_presp = settings->counter_offset_presp[i];
866+ u16 csa_c_off_bcn = counter_offset_beacon[i];
867+ u16 csa_c_off_presp;
868
869 if ((settings->beacon_csa.tail_len <= csa_c_off_bcn) ||
870 (settings->beacon_csa.tail[csa_c_off_bcn] !=
871 settings->cs_count))
872 return -EINVAL;
873
874+ if (!counter_offset_presp)
875+ continue;
876+
877+ csa_c_off_presp = counter_offset_presp[i];
878 if (settings->beacon_csa.probe_resp &&
879 ((settings->beacon_csa.probe_resp_len <=
880 csa_c_off_presp) ||
881@@ -11506,8 +11512,8 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
882 (settings->punct_bitmap &&
883 nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP,
884 settings->punct_bitmap)) ||
885- (settings->link_id != NL80211_DRV_LINK_ID_NA &&
886- nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, settings->link_id)))
887+ (settings->freq_params.link_id != NL80211_DRV_LINK_ID_NA &&
888+ nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, settings->freq_params.link_id)))
889 goto error;
890
891 /* beacon_after params */
892@@ -11528,9 +11534,14 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
893 if (ret)
894 goto error;
895
896- if (nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
897- csa_off_len * sizeof(u16),
898- settings->counter_offset_beacon) ||
899+ if ((cs_link_id == settings->freq_params.link_id &&
900+ nla_put(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
901+ csa_off_len * sizeof(u16),
902+ settings->counter_offset_beacon)) ||
903+ (cs_link_id != settings->freq_params.link_id &&
904+ nla_put(msg, NL80211_ATTR_CSA_C_OFF_STA_PROF,
905+ csa_off_len * sizeof(u16),
906+ settings->counter_offset_sta_prof[cs_link_id])) ||
907 (settings->beacon_csa.probe_resp &&
908 nla_put(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
909 csa_off_len * sizeof(u16),
910diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
911index d425c797c..13837297c 100644
912--- a/src/drivers/nl80211_copy.h
913+++ b/src/drivers/nl80211_copy.h
914@@ -2868,6 +2868,10 @@ enum nl80211_commands {
915 * nested item, it contains attributes defined in
916 * &enum nl80211_if_combination_attrs.
917 *
918+ * @NL80211_ATTR_CNTDWN_OFFS_STA_PROF: An array of offsets (u16) to the channel
919+ * switch or color change counters in the per-STA profile corresponding to
920+ * the affected AP.
921+ *
922 * @NUM_NL80211_ATTR: total number of nl80211_attrs available
923 * @NL80211_ATTR_MAX: highest attribute number currently defined
924 * @__NL80211_ATTR_AFTER_LAST: internal use
925@@ -3418,6 +3422,9 @@ enum nl80211_attrs {
926
927 /* add attributes here, update the policy in nl80211.c */
928
929+ /* MTK internal */
930+ NL80211_ATTR_CNTDWN_OFFS_STA_PROF,
931+
932 __NL80211_ATTR_AFTER_LAST,
933 NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
934 NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
935@@ -3430,6 +3437,7 @@ enum nl80211_attrs {
936 #define NL80211_ATTR_SAE_DATA NL80211_ATTR_AUTH_DATA
937 #define NL80211_ATTR_CSA_C_OFF_BEACON NL80211_ATTR_CNTDWN_OFFS_BEACON
938 #define NL80211_ATTR_CSA_C_OFF_PRESP NL80211_ATTR_CNTDWN_OFFS_PRESP
939+#define NL80211_ATTR_CSA_C_OFF_STA_PROF NL80211_ATTR_CNTDWN_OFFS_STA_PROF
940
941 /*
942 * Allow user space programs to use #ifdef on new attributes by defining them
943--
9442.18.0
945