blob: 473d91f0fac493b06ef92c55a4b5d26a81064a97 [file] [log] [blame]
developer05f3b2b2024-08-19 19:17:34 +08001From fd208c32b7e95c3aafce8f89917d4a961713fa75 Mon Sep 17 00:00:00 2001
2From: Allen Ye <allen.ye@mediatek.com>
3Date: Tue, 2 Jul 2024 10:38:49 +0800
4Subject: [PATCH 114/126] mtk: hostapd: Add bandwidth indication IE
5
6Move punct_bitmap from csa_settings to hostapd_freq_params for
7filling bandwidth indication IE while channel switch occurs.
8Handle bitmap change in hostapd_set_freq_params.
9
10Signed-off-by: Allen Ye <allen.ye@mediatek.com>
11---
12 hostapd/ctrl_iface.c | 18 +++---
13 src/ap/ctrl_iface_ap.c | 12 +---
14 src/ap/dfs.c | 1 -
15 src/ap/drv_callbacks.c | 1 -
16 src/ap/hostapd.c | 14 +---
17 src/ap/ieee802_11.c | 110 +++++++++++++++++++++++++++++---
18 src/ap/ieee802_11.h | 2 +
19 src/common/hw_features_common.c | 1 +
20 src/common/ieee802_11_defs.h | 30 +++++++++
21 src/drivers/driver.h | 10 ++-
22 src/drivers/driver_nl80211.c | 6 +-
23 11 files changed, 156 insertions(+), 49 deletions(-)
24
25diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
26index 337261f8f..c8456513e 100644
27--- a/hostapd/ctrl_iface.c
28+++ b/hostapd/ctrl_iface.c
29@@ -2621,8 +2621,7 @@ static int hostapd_ctrl_register_frame(struct hostapd_data *hapd,
30
31
32 #ifdef NEED_AP_MLME
33-static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params,
34- u16 punct_bitmap)
35+static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params)
36 {
37 u32 start_freq;
38
39@@ -2673,14 +2672,14 @@ static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params,
40 if (params->center_freq2 || params->sec_channel_offset)
41 return -1;
42
43- if (punct_bitmap)
44+ if (params->punct_bitmap)
45 return -1;
46 break;
47 case 40:
48 if (params->center_freq2 || !params->sec_channel_offset)
49 return -1;
50
51- if (punct_bitmap)
52+ if (params->punct_bitmap)
53 return -1;
54
55 if (!params->center_freq1)
56@@ -2717,7 +2716,7 @@ static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params,
57 return -1;
58 }
59
60- if (params->center_freq2 && punct_bitmap)
61+ if (params->center_freq2 && params->punct_bitmap)
62 return -1;
63
64 /* Adjacent and overlapped are not allowed for 80+80 */
65@@ -2784,7 +2783,7 @@ static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params,
66 return -1;
67 }
68
69- if (!punct_bitmap)
70+ if (!params->punct_bitmap)
71 return 0;
72
73 if (!params->eht_enabled) {
74@@ -2802,7 +2801,7 @@ static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params,
75 start_freq = params->center_freq1 - (params->bandwidth / 2);
76 if (!is_punct_bitmap_valid(params->bandwidth,
77 (params->freq - start_freq) / 20,
78- punct_bitmap)) {
79+ params->punct_bitmap)) {
80 wpa_printf(MSG_ERROR, "Invalid preamble puncturing bitmap");
81 return -1;
82 }
83@@ -2843,8 +2842,7 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
84 return -1;
85 }
86
87- ret = hostapd_ctrl_check_freq_params(&settings.freq_params,
88- settings.punct_bitmap);
89+ ret = hostapd_ctrl_check_freq_params(&settings.freq_params);
90 if (ret) {
91 wpa_printf(MSG_INFO,
92 "chanswitch: invalid frequency settings provided");
93@@ -2917,7 +2915,7 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
94
95 #ifdef CONFIG_IEEE80211BE
96 hapd = iface->bss[0];
97- if (hapd->iconf->punct_bitmap != settings.punct_bitmap &&
98+ if (hapd->iconf->punct_bitmap != settings.freq_params.punct_bitmap &&
99 hapd->iconf->pp_mode != PP_USR_MODE) {
100 hapd->iconf->pp_mode = PP_USR_MODE;
101 ret = hostapd_drv_pp_mode_set(hapd);
102diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
103index b0ee00b90..e1722620d 100644
104--- a/src/ap/ctrl_iface_ap.c
105+++ b/src/ap/ctrl_iface_ap.c
106@@ -1125,20 +1125,11 @@ int hostapd_parse_csa_settings(const char *pos,
107 } \
108 } while (0)
109
110-#define SET_CSA_SETTING_EXT(str) \
111- do { \
112- const char *pos2 = os_strstr(pos, " " #str "="); \
113- if (pos2) { \
114- pos2 += sizeof(" " #str "=") - 1; \
115- settings->str = atoi(pos2); \
116- } \
117- } while (0)
118-
119 SET_CSA_SETTING(center_freq1);
120 SET_CSA_SETTING(center_freq2);
121 SET_CSA_SETTING(bandwidth);
122 SET_CSA_SETTING(sec_channel_offset);
123- SET_CSA_SETTING_EXT(punct_bitmap);
124+ SET_CSA_SETTING(punct_bitmap);
125 settings->freq_params.ht_enabled = !!os_strstr(pos, " ht");
126 settings->freq_params.vht_enabled = !!os_strstr(pos, " vht");
127 settings->freq_params.he_enabled = !!os_strstr(pos, " he");
128@@ -1146,7 +1137,6 @@ int hostapd_parse_csa_settings(const char *pos,
129 settings->freq_params.radar_background = !!os_strstr(pos, " skip_cac");
130 settings->block_tx = !!os_strstr(pos, " blocktx");
131 #undef SET_CSA_SETTING
132-#undef SET_CSA_SETTING_EXT
133
134 return 0;
135 }
136diff --git a/src/ap/dfs.c b/src/ap/dfs.c
137index 5e9a2a4ce..5a3112d40 100644
138--- a/src/ap/dfs.c
139+++ b/src/ap/dfs.c
140@@ -1081,7 +1081,6 @@ static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
141 os_memset(&csa_settings, 0, sizeof(csa_settings));
142 csa_settings.cs_count = 5;
143 csa_settings.block_tx = 1;
144- csa_settings.punct_bitmap = hostapd_get_punct_bitmap(iface->bss[0]);
145 csa_settings.link_id = -1;
146 #ifdef CONFIG_IEEE80211BE
147 if (iface->bss[0]->conf->mld_ap)
148diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
149index 420d156c8..96b8e856e 100644
150--- a/src/ap/drv_callbacks.c
151+++ b/src/ap/drv_callbacks.c
152@@ -2481,7 +2481,6 @@ static void hostapd_event_pp_bitmap_update(struct hostapd_data *hapd,
153 os_memset(&csa_settings, 0, sizeof(csa_settings));
154 csa_settings.cs_count = 5;
155 csa_settings.block_tx = 0;
156- csa_settings.punct_bitmap = ch_switch->punct_bitmap;
157 csa_settings.link_id = ch_switch->link_id;
158
159 err = hostapd_set_freq_params(&csa_settings.freq_params,
160diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
161index 257849536..73378053b 100644
162--- a/src/ap/hostapd.c
163+++ b/src/ap/hostapd.c
164@@ -4487,6 +4487,8 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
165 hostapd_set_oper_centr_freq_seg0_idx(conf, seg0);
166 hostapd_set_oper_centr_freq_seg1_idx(conf, seg1);
167
168+ conf->punct_bitmap = params->punct_bitmap;
169+
170 /* TODO: maybe call here hostapd_config_check here? */
171
172 return 0;
173@@ -4499,9 +4501,6 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
174 struct hostapd_iface *iface = hapd->iface;
175 struct hostapd_freq_params old_freq;
176 int ret;
177-#ifdef CONFIG_IEEE80211BE
178- u16 old_punct_bitmap;
179-#endif /* CONFIG_IEEE80211BE */
180 u8 chan, bandwidth;
181
182 os_memset(&old_freq, 0, sizeof(old_freq));
183@@ -4550,19 +4549,11 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
184 if (ret)
185 return ret;
186
187-#ifdef CONFIG_IEEE80211BE
188- old_punct_bitmap = iface->conf->punct_bitmap;
189- iface->conf->punct_bitmap = settings->punct_bitmap;
190-#endif /* CONFIG_IEEE80211BE */
191-
192 /* Another CU in the new channel due to OP element modification */
193 ieee802_11_set_bss_critical_update(hapd, BSS_CRIT_UPDATE_EVENT_EHT_OPERATION);
194 ret = hostapd_build_beacon_data(hapd, &settings->beacon_after);
195
196 /* change back the configuration */
197-#ifdef CONFIG_IEEE80211BE
198- iface->conf->punct_bitmap = old_punct_bitmap;
199-#endif /* CONFIG_IEEE80211BE */
200 hostapd_change_config_freq(iface->bss[0], iface->conf,
201 &old_freq, NULL);
202
203@@ -4739,7 +4730,6 @@ int hostapd_update_aff_link_beacon(struct hostapd_data *hapd, u8 cs_count)
204 settings.link_id = cs_link_id;
205 settings.freq_params.link_id = link_id;
206 settings.cs_count = cs_count;
207- settings.punct_bitmap = conf->punct_bitmap;
208 ret = hostapd_drv_switch_channel(h, &settings);
209 free_beacon_data(&settings.beacon_csa);
210 free_beacon_data(&settings.beacon_after);
211diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
212index 10b7587a0..93bd8255c 100644
213--- a/src/ap/ieee802_11.c
214+++ b/src/ap/ieee802_11.c
215@@ -7368,10 +7368,95 @@ u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid)
216 tx_pwr);
217 }
218
219+#define DISABLED_SUBCHANNEL_BITMAP_BYTES_SIZE 2
220+u8 *hostapd_eid_bw_indication(struct hostapd_data *hapd, u8 *eid, u8 ccfs0, u8 ccfs1)
221+{
222+ u8 *pos = eid, *length_pos;
223+ struct ieee80211_bw_ind_element *bw_ind_elem;
224+ int bw_ind_status = false;
225+ size_t fixed_eid_len;
226+
227+ if (hapd->cs_freq_params.bandwidth > 160 ||
228+ hapd->cs_freq_params.punct_bitmap)
229+ bw_ind_status = true;
230+
231+ if (!bw_ind_status)
232+ return eid;
233+
234+ if (!hapd->cs_freq_params.channel || !hapd->cs_freq_params.eht_enabled)
235+ return eid;
236+
237+ *pos++ = WLAN_EID_EXTENSION;
238+ length_pos = pos++;
239+ *pos++ = WLAN_EID_EXT_BW_IND;
240+
241+ fixed_eid_len = (sizeof(struct ieee80211_bw_ind_element) -
242+ DISABLED_SUBCHANNEL_BITMAP_BYTES_SIZE);
243+
244+ bw_ind_elem = (struct ieee80211_bw_ind_element *) pos;
245+ os_memset(bw_ind_elem, 0, sizeof(struct ieee80211_bw_ind_element));
246+
247+ if (hapd->cs_freq_params.punct_bitmap) {
248+ bw_ind_elem->bw_ind_params |=
249+ BW_IND_PARAMETER_DISABLED_SUBCHAN_BITMAP_PRESENT;
250+ bw_ind_elem->bw_ind_info.disabled_chan_bitmap =
251+ host_to_le16(hapd->cs_freq_params.punct_bitmap);
252+ pos += DISABLED_SUBCHANNEL_BITMAP_BYTES_SIZE;
253+ } else {
254+ bw_ind_elem->bw_ind_params &=
255+ ~BW_IND_PARAMETER_DISABLED_SUBCHAN_BITMAP_PRESENT;
256+ }
257+
258+ switch (hapd->cs_freq_params.bandwidth) {
259+ case 320:
260+ bw_ind_elem->bw_ind_info.control |=
261+ BW_IND_CHANNEL_WIDTH_320MHZ;
262+ ccfs1 = ccfs0;
263+ if (hapd->cs_freq_params.channel < ccfs0)
264+ ccfs0 -= 16;
265+ else
266+ ccfs0 += 16;
267+ break;
268+ case 160:
269+ bw_ind_elem->bw_ind_info.control |=
270+ BW_IND_CHANNEL_WIDTH_160MHZ;
271+ ccfs1 = ccfs0;
272+ if (hapd->cs_freq_params.channel < ccfs0)
273+ ccfs0 -= 8;
274+ else
275+ ccfs0 += 8;
276+ break;
277+ case 80:
278+ bw_ind_elem->bw_ind_info.control |=
279+ BW_IND_CHANNEL_WIDTH_80MHZ;
280+ break;
281+ case 40:
282+ if (hapd->cs_freq_params.sec_channel_offset == 1)
283+ bw_ind_elem->bw_ind_info.control |=
284+ BW_IND_CHANNEL_WIDTH_40MHZ;
285+ else
286+ bw_ind_elem->bw_ind_info.control |=
287+ BW_IND_CHANNEL_WIDTH_20MHZ;
288+ break;
289+ default:
290+ bw_ind_elem->bw_ind_info.control |=
291+ BW_IND_CHANNEL_WIDTH_20MHZ;
292+ break;
293+ }
294+
295+ bw_ind_elem->bw_ind_info.ccfs0 = ccfs0;
296+ bw_ind_elem->bw_ind_info.ccfs1 = ccfs1;
297+
298+ pos += fixed_eid_len;
299+ *length_pos = pos - (eid + 2);
300+
301+ return pos;
302+}
303+
304
305 u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
306 {
307- u8 bw, chan1 = 0, chan2 = 0;
308+ u8 bw, chan1 = 0, chan2 = 0, ccfs0, ccfs1, *pos = eid, *length_pos;
309 int freq1;
310
311 if (!hapd->cs_freq_params.channel ||
312@@ -7412,11 +7497,14 @@ u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
313 &chan2) != HOSTAPD_MODE_IEEE80211A)
314 return eid;
315
316- *eid++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER;
317- *eid++ = 5; /* Length of Channel Switch Wrapper */
318- *eid++ = WLAN_EID_WIDE_BW_CHSWITCH;
319- *eid++ = 3; /* Length of Wide Bandwidth Channel Switch element */
320- *eid++ = bw; /* New Channel Width */
321+ *pos++ = WLAN_EID_CHANNEL_SWITCH_WRAPPER;
322+ length_pos = pos++; /* Length of Channel Switch Wrapper */
323+ *pos++ = WLAN_EID_WIDE_BW_CHSWITCH;
324+ *pos++ = 3; /* Length of Wide Bandwidth Channel Switch element */
325+ *pos++ = bw; /* New Channel Width */
326+
327+ ccfs0 = chan1;
328+ ccfs1 = chan2;
329 if (hapd->cs_freq_params.bandwidth == 160) {
330 /* Update the CCFS0 and CCFS1 values in the element based on
331 * IEEE P802.11-REVme/D4.0, Table 9-314 */
332@@ -7432,10 +7520,14 @@ u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid)
333 else
334 chan1 += 8;
335 }
336- *eid++ = chan1; /* New Channel Center Frequency Segment 0 */
337- *eid++ = chan2; /* New Channel Center Frequency Segment 1 */
338+ *pos++ = chan1; /* New Channel Center Frequency Segment 0 */
339+ *pos++ = chan2; /* New Channel Center Frequency Segment 1 */
340
341- return eid;
342+#ifdef CONFIG_IEEE80211BE
343+ pos = hostapd_eid_bw_indication(hapd, pos, ccfs0, ccfs1);
344+#endif /* CONFIG_IEEE80211BE */
345+ *length_pos = pos - (eid + 2);
346+ return pos;
347 }
348
349
350diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
351index 2d9adb910..40301bce9 100644
352--- a/src/ap/ieee802_11.h
353+++ b/src/ap/ieee802_11.h
354@@ -64,6 +64,8 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts);
355 u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
356 u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
357 u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
358+u8 * hostapd_eid_bw_indication(struct hostapd_data *hapd, u8 *eid,
359+ u8 ccfs0, u8 ccfs1);
360 u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
361 u8 * hostapd_eid_he_capab(struct hostapd_data *hapd, u8 *eid,
362 enum ieee80211_op_mode opmode);
363diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
364index 8bd6e994d..99106c277 100644
365--- a/src/common/hw_features_common.c
366+++ b/src/common/hw_features_common.c
367@@ -481,6 +481,7 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
368 data->sec_channel_offset = sec_channel_offset;
369 data->center_freq1 = freq + sec_channel_offset * 10;
370 data->center_freq2 = 0;
371+ data->punct_bitmap = punct_bitmap;
372 if (oper_chwidth == CONF_OPER_CHWIDTH_80MHZ)
373 data->bandwidth = 80;
374 else if (oper_chwidth == CONF_OPER_CHWIDTH_160MHZ ||
375diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
376index fb481b8b2..d93fa6660 100644
377--- a/src/common/ieee802_11_defs.h
378+++ b/src/common/ieee802_11_defs.h
379@@ -525,6 +525,7 @@
380 #define WLAN_EID_EXT_MULTI_LINK_TRAFFIC_INDICATION 110
381 #define WLAN_EID_EXT_QOS_CHARACTERISTICS 113
382 #define WLAN_EID_EXT_AKM_SUITE_SELECTOR 114
383+#define WLAN_EID_EXT_BW_IND 135
384
385 /* Extended Capabilities field */
386 #define WLAN_EXT_CAPAB_20_40_COEX 0
387@@ -3088,6 +3089,35 @@ enum dscp_policy_request_type {
388 #define WFA_CAPA_QM_UNSOLIC_DSCP BIT(1)
389 #define WFA_CAPA_QM_NON_EHT_SCS_TRAFFIC_DESC BIT(2)
390
391+/* IEEE P802.11be/D3.0, 9.4.2.319 - Bandwidth Indication element */
392+
393+/* Figure 9-1002ba: Bandwidth Indication Parameters field subfields */
394+#define BW_IND_PARAMETER_RESERVED BIT(0)
395+#define BW_IND_PARAMETER_DISABLED_SUBCHAN_BITMAP_PRESENT BIT(1)
396+
397+/* Table 9-467: Control subfield: Channel Width subfield; */
398+#define BW_IND_CHANNEL_WIDTH_20MHZ 0
399+#define BW_IND_CHANNEL_WIDTH_40MHZ 1
400+#define BW_IND_CHANNEL_WIDTH_80MHZ 2
401+#define BW_IND_CHANNEL_WIDTH_160MHZ 3
402+#define BW_IND_CHANNEL_WIDTH_320MHZ 4
403+
404+/* Figure 9-1002c: Bandwidth Indication information
405+ * field format similar to EHT Operation Information field format
406+ */
407+struct ieee80211_bw_ind_info {
408+ u8 control; /* B0..B2: Channel Width */
409+ u8 ccfs0;
410+ u8 ccfs1;
411+ le16 disabled_chan_bitmap; /* 0 or 2 octets */
412+} STRUCT_PACKED;
413+
414+/* Figure 9-1002ba—Bandwidth Indication element format */
415+struct ieee80211_bw_ind_element {
416+ u8 bw_ind_params; /* Bandwidth Indication Parameters */
417+ struct ieee80211_bw_ind_info bw_ind_info; /* 3 or 5 octets */
418+} STRUCT_PACKED;
419+
420 struct ieee80211_neighbor_ap_info {
421 u8 tbtt_info_hdr;
422 u8 tbtt_info_len;
423diff --git a/src/drivers/driver.h b/src/drivers/driver.h
424index 5e65d9e0b..498eff91f 100644
425--- a/src/drivers/driver.h
426+++ b/src/drivers/driver.h
427@@ -876,6 +876,14 @@ struct hostapd_freq_params {
428 */
429 bool eht_enabled;
430
431+ /**
432+ * punct_bitmap - puncturing bitmap
433+ * Each bit corresponds to a 20 MHz subchannel, lowest bit for the
434+ * channel with the lowest frequency. Bit set to 1 indicates that the
435+ * subchannel is punctured, otherwise active.
436+ */
437+ u16 punct_bitmap;
438+
439 /**
440 * link_id: If >=0 indicates the link of the AP MLD to configure
441 */
442@@ -2750,7 +2758,6 @@ struct beacon_data {
443 * @beacon_after: Next beacon/probe resp/asooc resp info
444 * @counter_offset_beacon: Offset to the count field in beacon's tail
445 * @counter_offset_presp: Offset to the count field in probe resp.
446- * @punct_bitmap - Preamble puncturing bitmap
447 * @link_id: Link ID to determine the link for MLD; -1 for non-MLD
448 * @ubpr: Unsolicited broadcast Probe Response frame data
449 */
450@@ -2766,7 +2773,6 @@ struct csa_settings {
451 u16 counter_offset_presp[2];
452 u16 counter_offset_sta_prof[MAX_NUM_MLD_LINKS][2];
453
454- u16 punct_bitmap;
455 int link_id;
456
457 struct unsol_bcast_probe_resp ubpr;
458diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
459index 5d97317f7..639c5e7e1 100644
460--- a/src/drivers/driver_nl80211.c
461+++ b/src/drivers/driver_nl80211.c
462@@ -11467,7 +11467,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
463 settings->freq_params.bandwidth,
464 settings->freq_params.center_freq1,
465 settings->freq_params.center_freq2,
466- settings->punct_bitmap,
467+ settings->freq_params.punct_bitmap,
468 settings->freq_params.link_id,
469 settings->freq_params.ht_enabled ? " ht" : "",
470 settings->freq_params.vht_enabled ? " vht" : "",
471@@ -11545,9 +11545,9 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings)
472 (ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
473 (settings->block_tx &&
474 nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)) ||
475- (settings->punct_bitmap &&
476+ (settings->freq_params.punct_bitmap &&
477 nla_put_u32(msg, NL80211_ATTR_PUNCT_BITMAP,
478- settings->punct_bitmap)) ||
479+ settings->freq_params.punct_bitmap)) ||
480 (settings->freq_params.link_id != NL80211_DRV_LINK_ID_NA &&
481 nla_put_u8(msg, NL80211_ATTR_MLO_LINK_ID, settings->freq_params.link_id)))
482 goto error;
483--
4842.18.0
485