1 /** @file mlan_11v.c
2 *
3 * @brief This file provides functions for process 11v(BTM) frames
4 *
5 * Copyright 2022-2024 NXP
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 */
10
11 /********************************************************
12 Change log:
13 08/11/2022: initial version
14 ********************************************************/
15
16 #include <mlan_api.h>
17 #ifndef RW610
18 #include "wifi-sdio.h"
19 #endif
20 #if CONFIG_11V
21 #define BTM_RESP_BUF_SIZE 200
22 #define WNM_BTM_QUERY_BUF_SIZE 10U
23 #define WLAN_FC_TYPE_MGMT 0
24
25 /********************************************************
26 Local Variables
27 ********************************************************/
28
29 /********************************************************
30 Global Variables
31 ********************************************************/
32
33 /********************************************************
34 Local Functions
35 ********************************************************/
wlan_wnm_parse_neighbor_report(t_u8 * pos,t_u8 len,struct wnm_neighbor_report * rep)36 static void wlan_wnm_parse_neighbor_report(t_u8 *pos, t_u8 len, struct wnm_neighbor_report *rep)
37 {
38 t_u8 remain_len = 0;
39 if (len < (t_u8)13U)
40 {
41 wifi_d("WNM: This neighbor report is too short");
42 }
43
44 (void)memcpy(rep->bssid, pos, MLAN_MAC_ADDR_LENGTH);
45 rep->bssid_info = wlan_cpu_to_le32(*(t_u32 *)(void *)(pos + MLAN_MAC_ADDR_LENGTH));
46 rep->reg_class = *(pos + 10);
47 rep->channel = *(pos + 11);
48 rep->PhyType = *(pos + 12);
49 pos += 13;
50 remain_len = (t_u8)(len - (t_u8)13U);
51
52 while (remain_len >= (t_u8)2U)
53 {
54 t_u8 e_id, e_len;
55
56 e_id = *pos++;
57 e_len = *pos++;
58 remain_len -= (t_u8)2U;
59 if (e_len > remain_len)
60 {
61 wifi_d("WNM: neighbor report length not matched");
62 break;
63 }
64 switch (e_id)
65 {
66 case MGMT_WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
67 if (e_len < (t_u8)1U)
68 {
69 break;
70 }
71 rep->prefer = pos[0];
72 rep->prefer_select = 1;
73 break;
74 default:
75 (void)PRINTF("UNKNOWN nbor Report e id\r\n");
76 break;
77 }
78
79 remain_len -= e_len;
80 pos += e_len;
81 }
82 }
83
wlan_send_mgmt_wnm_btm_resp(t_u8 dialog_token,enum wnm_btm_status_code status,t_u8 * dst_addr,t_u8 * src_addr,t_u8 * target_bssid,t_u8 * tag_nr,t_u8 tag_len,bool protect)84 void wlan_send_mgmt_wnm_btm_resp(t_u8 dialog_token,
85 enum wnm_btm_status_code status,
86 t_u8 *dst_addr,
87 t_u8 *src_addr,
88 t_u8 *target_bssid,
89 t_u8 *tag_nr,
90 t_u8 tag_len,
91 bool protect)
92 {
93 wlan_mgmt_pkt *pmgmt_pkt_hdr = MNULL;
94 IEEEtypes_FrameCtl_t *mgmt_fc_p = MNULL;
95 t_u8 *pos = MNULL;
96 t_u16 pkt_len = 0;
97
98 pmgmt_pkt_hdr = wifi_PrepDefaultMgtMsg(
99 SUBTYPE_ACTION, (mlan_802_11_mac_addr *)(void *)dst_addr, (mlan_802_11_mac_addr *)(void *)src_addr,
100 (mlan_802_11_mac_addr *)(void *)dst_addr, sizeof(wlan_mgmt_pkt) + (size_t)BTM_RESP_BUF_SIZE);
101 if (pmgmt_pkt_hdr == MNULL)
102 {
103 wifi_d("No memory available for BTM resp");
104 return;
105 }
106
107 mgmt_fc_p = (IEEEtypes_FrameCtl_t *)(void *)&pmgmt_pkt_hdr->wlan_header.frm_ctl;
108 if (protect)
109 {
110 mgmt_fc_p->wep = 1;
111 }
112
113 /* 802.11 management body */
114 pos = (t_u8 *)pmgmt_pkt_hdr + sizeof(wlan_mgmt_pkt);
115 pos[0] = (t_u8)IEEE_MGMT_ACTION_CATEGORY_WNM;
116 pos[1] = (t_u8)IEEE_MGMT_WNM_BTM_RESPONSE;
117 pos[2] = dialog_token;
118 pos[3] = (t_u8)status;
119 pos[4] = 0; /* delay */
120 pos += 5;
121
122 if (target_bssid != NULL)
123 {
124 (void)memcpy((void *)pos, (const void *)target_bssid, (size_t)MLAN_MAC_ADDR_LENGTH);
125 pos += 6;
126 }
127 else if (status == WNM_BTM_ACCEPT)
128 {
129 (void)memcpy((void *)pos, "\0\0\0\0\0\0", (size_t)MLAN_MAC_ADDR_LENGTH);
130 pos += 6;
131 }
132 else
133 {
134 /* Do nothing */
135 }
136
137 if (status == WNM_BTM_ACCEPT && tag_nr != NULL)
138 {
139 (void)memcpy((void *)pos, (const void *)tag_nr, (size_t)tag_len);
140 pos += tag_len;
141 }
142 pkt_len = (t_u16)(pos - (t_u8 *)pmgmt_pkt_hdr);
143 pmgmt_pkt_hdr->frm_len = (t_u16)((t_u16)pkt_len - sizeof(t_u16));
144 (void)wifi_inject_frame(WLAN_BSS_TYPE_STA, (t_u8 *)pmgmt_pkt_hdr, pkt_len);
145 #if !CONFIG_MEM_POOLS
146 OSA_MemoryFree(pmgmt_pkt_hdr);
147 #else
148 OSA_MemoryPoolFree(buf_1536_MemoryPool, pmgmt_pkt_hdr);
149 #endif
150 }
151
wlan_11v_find_in_channels(t_u8 * channels,t_u8 entry_num,t_u8 chan)152 static bool wlan_11v_find_in_channels(t_u8 *channels, t_u8 entry_num, t_u8 chan)
153 {
154 t_u8 i;
155 for (i = 0; i < entry_num; i++)
156 {
157 if (channels[i] == chan)
158 {
159 return true;
160 }
161 }
162 return false;
163 }
164 /********************************************************
165 Global functions
166 ********************************************************/
167 /**
168 * @brief This function process BTM request frame
169 *
170 * @param pos BTM request frame head
171 * @param end end of frame
172 * @param src_addr source address
173 *
174 */
wlan_process_mgmt_wnm_btm_req(t_u8 * pos,t_u8 * end,t_u8 * src_addr,t_u8 * dest_addr,bool protect)175 void wlan_process_mgmt_wnm_btm_req(t_u8 *pos, t_u8 *end, t_u8 *src_addr, t_u8 *dest_addr, bool protect)
176 {
177 t_u8 dialog_token;
178 t_u8 wnm_num_neighbor_report = 0, neighbor_index = 0;
179 t_u8 btm_mode;
180 t_u8 prefer_old = 0, prefer_select = 0;
181 t_u8 *ptagnr = NULL;
182 t_u8 tagnr_len = 0;
183 wlan_nlist_report_param *pnlist_rep_param = MNULL;
184 t_u8 entry_num = 0;
185
186 if (end - pos < 5)
187 {
188 return;
189 }
190
191 #if !CONFIG_MEM_POOLS
192 pnlist_rep_param = (wlan_nlist_report_param *)OSA_MemoryAllocate(sizeof(wlan_nlist_report_param));
193 #else
194 pnlist_rep_param = (wlan_nlist_report_param *)OSA_MemoryPoolAllocate(buf_128_MemoryPool);
195 #endif
196
197 if (pnlist_rep_param == MNULL)
198 {
199 wifi_e("11v nlist report param buffer alloc failed %d", sizeof(wlan_nlist_report_param));
200 return;
201 }
202
203 (void)memset(pnlist_rep_param, 0, sizeof(wlan_nlist_report_param));
204
205 dialog_token = pos[0];
206 btm_mode = pos[1];
207 pos += 5;
208
209 if ((btm_mode & IEEE_WNM_BTM_REQUEST_BSS_TERMINATION_INCLUDED) != 0U)
210 {
211 pos += 12; /* BSS Termination Duration */
212 }
213
214 if ((btm_mode & IEEE_WNM_BTM_REQUEST_PREFERENCE_CAND_LIST_INCLUDED) != 0U)
215 {
216 #if !CONFIG_MEM_POOLS
217 struct wnm_neighbor_report *preport =
218 OSA_MemoryAllocate((size_t)WLAN_WNM_MAX_NEIGHBOR_REPORT * sizeof(struct wnm_neighbor_report));
219 #else
220 struct wnm_neighbor_report *preport = OSA_MemoryPoolAllocate(buf_128_MemoryPool);
221 #endif
222 if (preport == NULL)
223 {
224 wifi_e("No memory available for neighbor report.");
225 #if !CONFIG_MEM_POOLS
226 OSA_MemoryFree((void *)pnlist_rep_param);
227 #else
228 OSA_MemoryPoolFree(buf_128_MemoryPool, pnlist_rep_param);
229 #endif
230 return;
231 }
232
233 while (end - pos >= 2 && wnm_num_neighbor_report < (t_u8)WLAN_WNM_MAX_NEIGHBOR_REPORT)
234 {
235 t_u8 tag = *pos++;
236 t_u8 len = *pos++;
237
238 if ((int)len > (end - pos))
239 {
240 wifi_d("WNM: Truncated BTM request");
241 #if !CONFIG_MEM_POOLS
242 OSA_MemoryFree((void *)preport);
243 OSA_MemoryFree((void *)pnlist_rep_param);
244 #else
245 OSA_MemoryPoolFree(buf_128_MemoryPool, preport);
246 OSA_MemoryPoolFree(buf_128_MemoryPool, pnlist_rep_param);
247 #endif
248 return;
249 }
250
251 if (tag == (t_u8)NEIGHBOR_REPORT)
252 {
253 struct wnm_neighbor_report *rep;
254 rep = &preport[wnm_num_neighbor_report];
255 wlan_wnm_parse_neighbor_report(pos, len, rep);
256 if (!wlan_11v_find_in_channels(pnlist_rep_param->channels, entry_num, rep->channel))
257 {
258 pnlist_rep_param->channels[entry_num] = rep->channel;
259 entry_num++;
260 }
261 if (rep->prefer_select != (t_u8)0U && (rep->prefer > prefer_old))
262 {
263 ptagnr = pos - 2;
264 tagnr_len = len + (t_u8)2U;
265 prefer_old = (t_u8)rep->prefer;
266 prefer_select = 1;
267 neighbor_index = wnm_num_neighbor_report;
268 }
269 wnm_num_neighbor_report++;
270 }
271 pos += len;
272 }
273
274 if (wnm_num_neighbor_report == (t_u8)0U)
275 {
276 wlan_send_mgmt_wnm_btm_resp(dialog_token, WNM_BTM_REJECT_NO_SUITABLE_CANDIDATES, dest_addr, src_addr, NULL,
277 ptagnr, tagnr_len, protect);
278 #if !CONFIG_MEM_POOLS
279 OSA_MemoryFree((void *)preport);
280 OSA_MemoryFree((void *)pnlist_rep_param);
281 #else
282 OSA_MemoryPoolFree(buf_128_MemoryPool, preport);
283 OSA_MemoryPoolFree(buf_128_MemoryPool, pnlist_rep_param);
284 #endif
285
286 return;
287 }
288
289 if (prefer_select == (t_u8)1U)
290 {
291 wlan_send_mgmt_wnm_btm_resp(dialog_token, WNM_BTM_ACCEPT, dest_addr, src_addr,
292 preport[neighbor_index].bssid, ptagnr, tagnr_len, protect);
293
294 /* disconnect and re-assocate with AP2 */
295 pnlist_rep_param->nlist_mode = WLAN_NLIST_11V_PREFERRED;
296 pnlist_rep_param->num_channels = 1;
297 pnlist_rep_param->channels[0] = preport[neighbor_index].channel;
298 pnlist_rep_param->btm_mode = btm_mode;
299 (void)memcpy((void *)pnlist_rep_param->bssid, (const void *)preport[neighbor_index].bssid,
300 (size_t)MLAN_MAC_ADDR_LENGTH);
301 }
302 else
303 {
304 pnlist_rep_param->nlist_mode = WLAN_NLIST_11V;
305 pnlist_rep_param->num_channels = entry_num;
306 pnlist_rep_param->btm_mode = btm_mode;
307 pnlist_rep_param->dialog_token = dialog_token;
308 pnlist_rep_param->protect = protect;
309 (void)memcpy((void *)pnlist_rep_param->dst_addr, (const void *)dest_addr, (size_t)MLAN_MAC_ADDR_LENGTH);
310 }
311
312 if (wifi_event_completion(WIFI_EVENT_NLIST_REPORT, WIFI_EVENT_REASON_SUCCESS, (void *)pnlist_rep_param) !=
313 WM_SUCCESS)
314 {
315 /* If fail to send message on queue, free allocated memory ! */
316 #if !CONFIG_MEM_POOLS
317 OSA_MemoryFree((void *)pnlist_rep_param);
318 #else
319 OSA_MemoryPoolFree(buf_128_MemoryPool, pnlist_rep_param);
320 #endif
321 }
322 #if !CONFIG_MEM_POOLS
323 OSA_MemoryFree(preport);
324 #else
325 OSA_MemoryPoolFree(buf_128_MemoryPool, preport);
326 #endif
327 }
328 else
329 {
330 enum wnm_btm_status_code status;
331 if ((btm_mode & IEEE_WNM_BTM_REQUEST_ESS_DISASSOC_IMMINENT) != 0U)
332 {
333 status = WNM_BTM_ACCEPT;
334 }
335 else
336 {
337 status = WNM_BTM_REJECT_UNSPECIFIED;
338 }
339
340 wlan_send_mgmt_wnm_btm_resp(dialog_token, status, dest_addr, src_addr, NULL, ptagnr, tagnr_len, protect);
341 /* If don't use variable pnlist_rep_param, free allocated memory ! */
342 #if !CONFIG_MEM_POOLS
343 OSA_MemoryFree((void *)pnlist_rep_param);
344 #else
345 OSA_MemoryPoolFree(buf_128_MemoryPool, pnlist_rep_param);
346 #endif
347 }
348 }
349
wlan_send_mgmt_bss_trans_query(mlan_private * pmpriv,t_u8 query_reason)350 int wlan_send_mgmt_bss_trans_query(mlan_private *pmpriv, t_u8 query_reason)
351 {
352 t_u16 pkt_len;
353 mlan_802_11_mac_addr *da = MNULL;
354 mlan_802_11_mac_addr *sa = MNULL;
355 wlan_mgmt_pkt *pmgmt_pkt_hdr = MNULL;
356 t_u8 *pos = MNULL;
357 int meas_pkt_len = 0;
358
359 if (pmpriv->bss_index != (t_u8)MLAN_BSS_ROLE_STA || pmpriv->media_connected != MTRUE)
360 {
361 wifi_d("invalid interface %d for sending neighbor report request", pmpriv->bss_index);
362 return (int)MLAN_STATUS_FAILURE;
363 }
364
365 da = &pmpriv->curr_bss_params.bss_descriptor.mac_address;
366 sa = (mlan_802_11_mac_addr *)(void *)(&pmpriv->curr_addr[0]);
367 pmgmt_pkt_hdr = wifi_PrepDefaultMgtMsg(SUBTYPE_ACTION, da, sa, da, sizeof(wlan_mgmt_pkt) + WNM_BTM_QUERY_BUF_SIZE);
368 if (pmgmt_pkt_hdr == MNULL)
369 {
370 wifi_e("No memory for bss transition management query");
371 return (int)MLAN_STATUS_FAILURE;
372 }
373
374 /* 802.11 management body */
375 pos = (t_u8 *)pmgmt_pkt_hdr + sizeof(wlan_mgmt_pkt);
376 pos[0] = (t_u8)IEEE_MGMT_ACTION_CATEGORY_WNM;
377 pos[1] = (t_u8)IEEE_MGMT_WNM_BTM_QUERY;
378 pos[2] = pmpriv->bss_trans_query_token++;
379
380 if (pmpriv->bss_trans_query_token == (t_u8)255U)
381 {
382 pmpriv->bss_trans_query_token = (t_u8)1U;
383 }
384
385 pos[3] = query_reason;
386 pos += 4;
387
388 meas_pkt_len = pos - (t_u8 *)pmgmt_pkt_hdr;
389 pkt_len = (t_u16)meas_pkt_len;
390 pmgmt_pkt_hdr->frm_len = pkt_len - (t_u16)sizeof(pmgmt_pkt_hdr->frm_len);
391
392 (void)wifi_inject_frame(WLAN_BSS_TYPE_STA, (t_u8 *)pmgmt_pkt_hdr, pkt_len);
393 #if !CONFIG_MEM_POOLS
394 OSA_MemoryFree(pmgmt_pkt_hdr);
395 #else
396 OSA_MemoryPoolFree(buf_1536_MemoryPool, pmgmt_pkt_hdr);
397 #endif
398
399 return (int)MLAN_STATUS_SUCCESS;
400 }
401 #endif /* CONFIG_11V */
402