1 /** @file mlan_11k.c
2 *
3 * @brief This file provides functions for process 11k(RRM) feature
4 *
5 * Copyright 2022-2024 NXP
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 */
10
11 /********************************************************
12 Change log:
13 08/24/2022: initial version
14 ********************************************************/
15
16 #include <mlan_api.h>
17
18 #if CONFIG_11K
19 #define LINK_MSR_REPORT_BUF_SIZE 64U
20 #define NEIGHBOR_REQUEST_BUF_SIZE 64U
21 #define rrm_bits_max 255U
22
23 /********************************************************
24 Local Variables
25 ********************************************************/
26
27 /********************************************************
28 Global Variables
29 ********************************************************/
30 static uint8_t broadcast_mac_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
31 /********************************************************
32 Local Functions
33 ********************************************************/
wlan_rrm_rssi_to_rcpi(int rssi)34 static t_u8 wlan_rrm_rssi_to_rcpi(int rssi)
35 {
36 t_u8 ret_rcpi = 0;
37 int rcpi = 0;
38
39 if (rssi == 0)
40 {
41 return (t_u8)255U;
42 }
43 else if (rssi > 0)
44 {
45 return (t_u8)220U;
46 }
47 else if (rssi < -110)
48 {
49 return (t_u8)0U;
50 }
51 else
52 {
53 rcpi = (rssi + 110) * 2;
54 ret_rcpi = (t_u8)rcpi;
55 return ret_rcpi;
56 }
57 }
58
wlan_rrm_put_le64(t_u8 * a,t_u64 val)59 static void wlan_rrm_put_le64(t_u8 *a, t_u64 val)
60 {
61 a[7] = (t_u8)(val >> 56);
62 a[6] = (t_u8)(val >> 48);
63 a[5] = (t_u8)(val >> 40);
64 a[4] = (t_u8)(val >> 32);
65 a[3] = (t_u8)(val >> 24);
66 a[2] = (t_u8)(val >> 16);
67 a[1] = (t_u8)(val >> 8);
68 a[0] = (t_u8)(val & 0xffULL);
69 }
70
wlan_rrm_put_le16(t_u8 * a,t_u16 val)71 static void wlan_rrm_put_le16(t_u8 *a, t_u16 val)
72 {
73 a[1] = (t_u8)(val >> 8);
74 a[0] = (t_u8)(val & (t_u16)0xff);
75 }
76
wlan_rrm_bit_field_set(t_u8 * bits_field,t_u8 bit)77 static void wlan_rrm_bit_field_set(t_u8 *bits_field, t_u8 bit)
78 {
79 if (bit >= (t_u8)rrm_bits_max)
80 {
81 return;
82 }
83
84 bits_field[bit / 8U] |= BIT(bit % 8U);
85 }
86
wlan_rrm_bit_field_is_set(t_u8 * bit_field,t_u8 bit)87 static bool wlan_rrm_bit_field_is_set(t_u8 *bit_field, t_u8 bit)
88 {
89 if (bit >= (t_u8)rrm_bits_max)
90 {
91 return 0;
92 }
93
94 return ((bit_field[bit / (t_u8)8U] & (t_u8)(BIT((bit % 8U)))) != (t_u8)0U);
95 }
96
97 /* mod_group : ModulationGroup\n
98 * 0: CCK (1,2,5.5,11 Mbps)\n
99 * 1: OFDM (6,9,12,18 Mbps)\n
100 */
wlan_link_measurement_get_tx_power(wifi_txpwrlimit_t * txpwrlimit,t_u8 ModulationGroup,t_u32 channel)101 static t_u8 wlan_link_measurement_get_tx_power(wifi_txpwrlimit_t *txpwrlimit, t_u8 ModulationGroup, t_u32 channel)
102 {
103 t_u8 i;
104 t_u8 tx_power = 20;
105
106 for (i = 0; i < txpwrlimit->num_chans; i++)
107 {
108 if (txpwrlimit->txpwrlimit_config[i].chan_desc.chan_num == channel)
109 {
110 tx_power = txpwrlimit->txpwrlimit_config[i].txpwrlimit_entry[ModulationGroup].tx_power;
111 return tx_power;
112 }
113 }
114 return tx_power;
115 }
116
wlan_process_rm_beacon_req_subelement(wlan_rrm_beacon_report_data * rep_data,t_u8 sub_id,t_u8 sub_len,t_u8 * sub_elem)117 static int wlan_process_rm_beacon_req_subelement(wlan_rrm_beacon_report_data *rep_data,
118 t_u8 sub_id,
119 t_u8 sub_len,
120 t_u8 *sub_elem)
121 {
122 t_u8 i;
123
124 switch (sub_id)
125 {
126 case WLAN_RRM_BEACON_REQUEST_SUBELEMENT_SSID:
127 if (sub_len == (t_u8)0U)
128 {
129 break;
130 }
131
132 if (sub_len > MLAN_MAX_SSID_LENGTH)
133 {
134 wifi_d("Wrong SSID sub_element len: %u", sub_len);
135 return -1;
136 }
137
138 rep_data->ssid_length = sub_len;
139 (void)memcpy(rep_data->ssid, sub_elem, rep_data->ssid_length);
140 break;
141 case WLAN_RRM_BEACON_REQUEST_SUBELEMENT_REPORTING_INFO:
142 if (sub_len != 2U)
143 {
144 wifi_d("Wrong reporting info sub_element len: %u", sub_len);
145 return -1;
146 }
147
148 break;
149 case WLAN_RRM_BEACON_REQUEST_SUBELEMENT_REPORTING_DETAIL:
150 if (sub_len != 1U)
151 {
152 wifi_d("Wrong reporting datail sub_element len: %u", sub_len);
153 return -1;
154 }
155
156 if (rep_data->report_detail > WLAN_RRM_REPORTING_DETAIL_ALL_FIELDS_AND_ELEMENTS)
157 {
158 wifi_d("Wrong reporting datail value: %u", rep_data->report_detail);
159 return -1;
160 }
161 rep_data->report_detail = (enum wlan_rrm_beacon_reporting_detail)sub_elem[0];
162
163 break;
164 case WLAN_RRM_BEACON_REQUEST_SUBELEMENT_REQUEST:
165 if (rep_data->report_detail != WLAN_RRM_REPORTING_DETAIL_AS_REQUEST)
166 {
167 wifi_d("Sub_lement request is present with wrong report detail: %u", rep_data->report_detail);
168 return -1;
169 }
170
171 if (sub_len == (t_u8)0U)
172 {
173 wifi_d("wrong request sub_element len: %u", sub_len);
174 return -1;
175 }
176
177 for (i = 0; i < sub_len; i++)
178 {
179 wlan_rrm_bit_field_set(rep_data->bits_field, sub_elem[i]);
180 }
181 break;
182 case WLAN_RRM_BEACON_REQUEST_SUBELEMENT_AP_CHANNEL:
183 if (rep_data->channel_num + sub_len - 1U > (t_u8)MAX_CHANNEL_LIST)
184 {
185 return 0;
186 }
187
188 for (i = 0; i < (t_u8)(sub_len - 1U); i++)
189 {
190 rep_data->channel[rep_data->channel_num + i] = sub_elem[i + 1U];
191 }
192
193 rep_data->channel_num += sub_len - 1U;
194 break;
195 case WLAN_RRM_BEACON_REQUEST_SUBELEMENT_LAST_INDICATION:
196 if (sub_len != 1U)
197 {
198 wifi_d("wrong last indication sub_element len: %u", sub_len);
199 return -1;
200 }
201
202 rep_data->last_ind = sub_elem[0];
203 break;
204 default:
205 wifi_d("Sub element id: %u is not handled for beacon request", sub_id);
206 break;
207 }
208
209 return 0;
210 }
211
wlan_process_rm_beacon_report_table(wlan_rrm_beacon_report_data * rep_data,t_u8 dialog_tok,t_u8 * dest_addr,t_u8 * src_addr,bool protect)212 static void wlan_process_rm_beacon_report_table(
213 wlan_rrm_beacon_report_data *rep_data, t_u8 dialog_tok, t_u8 *dest_addr, t_u8 *src_addr, bool protect)
214 {
215 t_u16 i;
216 t_u8 *rep_buf = NULL;
217 t_u8 *buf_pos = NULL;
218 /* The sufficient size is the length including reporting frame body */
219 t_u16 suffi_len = 250;
220 t_u32 pos_last_indication = 0;
221 bool match_ap_found = false;
222 int meas_rep_len = 0;
223
224 #if !CONFIG_MEM_POOLS
225 rep_buf = (t_u8 *)OSA_MemoryAllocate(BEACON_REPORT_BUF_SIZE);
226 #else
227 rep_buf = (t_u8 *)OSA_MemoryPoolAllocate(buf_1536_MemoryPool);
228 #endif
229
230 if (rep_buf == NULL)
231 {
232 wifi_e("Cannot allocate memory for report buffer");
233 return;
234 }
235
236 (void)memset(rep_buf, 0, BEACON_REPORT_BUF_SIZE);
237 buf_pos = rep_buf;
238 for (i = 0; i < mlan_adap->num_in_scan_table; i++)
239 {
240 if (wlan_rrm_matched_ap_found(rep_data, &mlan_adap->pscan_table[i]))
241 {
242 wlan_add_rm_beacon_report(rep_data, &mlan_adap->pscan_table[i], &buf_pos,
243 BEACON_REPORT_BUF_SIZE - (buf_pos - rep_buf), &pos_last_indication);
244 }
245
246 /* If current rep_buf is not enough and still have AP not added, just send the report */
247 if ((buf_pos + suffi_len - rep_buf > BEACON_REPORT_BUF_SIZE) &&
248 (i < (t_u16)(mlan_adap->num_in_scan_table - 1U)) &&
249 wlan_rrm_matched_ap_found(rep_data, &mlan_adap->pscan_table[i + 1U]))
250 {
251 match_ap_found = 1;
252 meas_rep_len = buf_pos - rep_buf;
253 /* send beacon report, not the last one */
254 wlan_send_mgmt_rm_beacon_report(dialog_tok, dest_addr, src_addr, rep_buf, (t_u32)(meas_rep_len), protect);
255 /* Prepare for the next beacon report */
256 (void)memset(rep_buf, 0, BEACON_REPORT_BUF_SIZE);
257 buf_pos = rep_buf;
258 }
259
260 /* Last AP in scan table, and matched AP found */
261 if ((i == mlan_adap->num_in_scan_table - 1U) && (buf_pos > rep_buf))
262 {
263 match_ap_found = 1;
264 /* Update last indication, the last one */
265 if (rep_data->last_ind > (t_u8)0U && pos_last_indication > 0U)
266 {
267 *(char *)pos_last_indication = (char)1U;
268 }
269 meas_rep_len = buf_pos - rep_buf;
270 /* send beacon report, the last one */
271 wlan_send_mgmt_rm_beacon_report(dialog_tok, dest_addr, src_addr, rep_buf, (t_u32)(meas_rep_len), protect);
272 }
273 }
274
275 /* If no matched AP found, no beacon report detail */
276 if (!match_ap_found)
277 {
278 *buf_pos++ = (t_u8)MEASURE_REPORT;
279 /* Tag length */
280 *buf_pos++ = 3;
281 *buf_pos++ = rep_data->token;
282 *buf_pos++ = WLAN_RRM_REPORT_MODE_ACCEPT;
283 *buf_pos++ = WLAN_RRM_MEASURE_TYPE_BEACON;
284 meas_rep_len = buf_pos - rep_buf;
285 /* send beacon report */
286 wlan_send_mgmt_rm_beacon_report(dialog_tok, dest_addr, src_addr, rep_buf, (t_u32)(meas_rep_len), protect);
287 }
288 #if !CONFIG_MEM_POOLS
289 OSA_MemoryFree(rep_buf);
290 #else
291 OSA_MemoryPoolFree(buf_1536_MemoryPool, rep_buf);
292 #endif
293 }
294
wlan_rrm_matched_ap_found(wlan_rrm_beacon_report_data * rep_data,BSSDescriptor_t * bss_entry)295 bool wlan_rrm_matched_ap_found(wlan_rrm_beacon_report_data *rep_data, BSSDescriptor_t *bss_entry)
296 {
297 if (memcmp(rep_data->bssid, broadcast_mac_addr, IEEEtypes_ADDRESS_SIZE) != 0 &&
298 memcmp(rep_data->bssid, bss_entry->mac_address, IEEEtypes_ADDRESS_SIZE) != 0)
299 {
300 return 0;
301 }
302
303 if (rep_data->ssid_length > 0U && (rep_data->ssid_length != bss_entry->ssid.ssid_len ||
304 memcmp(rep_data->ssid, bss_entry->ssid.ssid, bss_entry->ssid.ssid_len) != 0))
305 {
306 return 0;
307 }
308
309 return 1;
310 }
311
wlan_process_rm_beacon_req(t_u8 * req,t_u32 len,t_u8 element_token,t_u8 dialog_tok,t_u8 * dest_addr,t_u8 * src_addr,bool protect,bool duration_mandatory)312 static void wlan_process_rm_beacon_req(t_u8 *req,
313 t_u32 len,
314 t_u8 element_token,
315 t_u8 dialog_tok,
316 t_u8 *dest_addr,
317 t_u8 *src_addr,
318 bool protect,
319 bool duration_mandatory)
320 {
321 mgmt_rrm_meas_beacon_request *beacon_req = (mgmt_rrm_meas_beacon_request *)(void *)req;
322 t_u8 *sub_element;
323 int element_len;
324 int ret = 0, i;
325 wlan_scan_params_v2_t wlan_scan_param;
326 wlan_rrm_scan_cb_param *param = NULL;
327
328 if (beacon_req->mode != (t_u8)WLAN_RRM_MEASUREMENT_MODE_PASSIVE &&
329 beacon_req->mode != (t_u8)WLAN_RRM_MEASUREMENT_MODE_ACTIVE &&
330 beacon_req->mode != (t_u8)WLAN_RRM_MEASUREMENT_MODE_TABLE)
331 {
332 return;
333 }
334
335 sub_element = beacon_req->variable;
336 element_len = (int)len - ((int)sizeof(mgmt_rrm_meas_beacon_request) - 1);
337
338 #if !CONFIG_MEM_POOLS
339 param = (wlan_rrm_scan_cb_param *)OSA_MemoryAllocate(sizeof(wlan_rrm_scan_cb_param));
340 #else
341 param = (wlan_rrm_scan_cb_param *)OSA_MemoryPoolAllocate(buf_256_MemoryPool);
342 #endif
343 if (param == NULL)
344 {
345 wifi_e("Cannot allocate memory for rm scan param");
346 return;
347 }
348 (void)memset(param, 0, sizeof(wlan_rrm_scan_cb_param));
349 param->rep_data.token = element_token;
350 param->rep_data.report_detail = WLAN_RRM_REPORTING_DETAIL_ALL_FIELDS_AND_ELEMENTS;
351 param->rep_data.duration = wlan_le16_to_cpu(beacon_req->duration);
352 (void)memcpy(param->rep_data.bssid, beacon_req->bssid, IEEEtypes_ADDRESS_SIZE);
353
354 while (element_len >= 2)
355 {
356 ret = wlan_process_rm_beacon_req_subelement(¶m->rep_data, sub_element[0], sub_element[1], &sub_element[2]);
357 if (ret < 0)
358 {
359 goto output;
360 }
361
362 element_len -= 2 + (int)sub_element[1];
363 sub_element += 2U + sub_element[1];
364 }
365
366 /* Measurement mode: Beacon Table */
367 if (beacon_req->mode == (t_u8)WLAN_RRM_MEASUREMENT_MODE_TABLE)
368 {
369 wlan_process_rm_beacon_report_table(¶m->rep_data, dialog_tok, dest_addr, src_addr, protect);
370 goto output;
371 }
372
373 /* Measurement mode: Passive or Active, need to scan first */
374 (void)memset(&wlan_scan_param, 0, sizeof(wlan_scan_params_v2_t));
375 if (beacon_req->channel > 0U && beacon_req->channel != 255U)
376 {
377 wlan_scan_param.num_channels = 1;
378 wlan_scan_param.chan_list[0].chan_number = beacon_req->channel;
379 if (beacon_req->mode == (t_u8)WLAN_RRM_MEASUREMENT_MODE_ACTIVE)
380 {
381 wlan_scan_param.chan_list[0].scan_type = MLAN_SCAN_TYPE_ACTIVE;
382 }
383 else
384 {
385 wlan_scan_param.chan_list[0].scan_type = MLAN_SCAN_TYPE_PASSIVE;
386 }
387
388 if (duration_mandatory)
389 {
390 wlan_scan_param.chan_list[0].scan_time = beacon_req->duration;
391 }
392 }
393 else if (beacon_req->channel == 255U && param->rep_data.channel_num > (t_u8)0U)
394 {
395 wlan_scan_param.num_channels = param->rep_data.channel_num;
396 for (i = 0; i < (int)param->rep_data.channel_num && i < MAX_CHANNEL_LIST; i++)
397 {
398 wlan_scan_param.chan_list[i].chan_number = param->rep_data.channel[i];
399 if (beacon_req->mode == (t_u8)WLAN_RRM_MEASUREMENT_MODE_ACTIVE)
400 {
401 wlan_scan_param.chan_list[i].scan_type = MLAN_SCAN_TYPE_ACTIVE;
402 }
403 else
404 {
405 wlan_scan_param.chan_list[i].scan_type = MLAN_SCAN_TYPE_PASSIVE;
406 }
407
408 if (duration_mandatory)
409 {
410 wlan_scan_param.chan_list[i].scan_time = beacon_req->duration;
411 }
412 }
413 }
414 else
415 {
416 /* Do nothing */
417 }
418
419 if (param->rep_data.ssid_length > (t_u8)0U)
420 {
421 (void)memcpy((void *)&wlan_scan_param.ssid[0], (const void *)param->rep_data.ssid,
422 (size_t)param->rep_data.ssid_length);
423 }
424
425 param->dialog_tok = dialog_tok;
426 param->protect = (t_u8)protect;
427 (void)memcpy(param->dst_addr, src_addr, IEEEtypes_ADDRESS_SIZE);
428 wlan_scan_param.cb = _wlan_rrm_scan_cb;
429
430 /* After scanning done, will send beacon report */
431 wlan_rrm_request_scan(&wlan_scan_param, param);
432 output:
433 #if !CONFIG_MEM_POOLS
434 OSA_MemoryFree(param);
435 #else
436 OSA_MemoryPoolFree(buf_256_MemoryPool, param);
437 #endif
438
439 return;
440 }
441
442 /********************************************************
443 Global functions
444 ********************************************************/
wlan_add_rm_beacon_report(wlan_rrm_beacon_report_data * rep_data,BSSDescriptor_t * bss_entry,t_u8 ** buf_pos,t_s32 remained_len,t_u32 * pos_last_indication)445 void wlan_add_rm_beacon_report(wlan_rrm_beacon_report_data *rep_data,
446 BSSDescriptor_t *bss_entry,
447 t_u8 **buf_pos,
448 t_s32 remained_len,
449 t_u32 *pos_last_indication)
450 {
451 mgmt_rrm_meas_beacon_report report;
452 t_u8 *pos = *buf_pos;
453 t_u8 *pos_tag_len = NULL;
454 t_u8 *pos_sub_len = NULL;
455 t_u16 cap_info = (t_u16)0U;
456 int meas_tag_len = 0;
457 int meas_sub_len = 0;
458
459 (void)memset(&report, 0, sizeof(mgmt_rrm_meas_beacon_report) - 1U);
460 (void)wlan_get_curr_global_oper_class(mlan_adap->priv[0], (t_u8)bss_entry->channel, bss_entry->curr_bandwidth,
461 &report.op_class);
462
463 /* Measurement report */
464 *pos++ = (t_u8)MEASURE_REPORT;
465 /* The length will be filled below */
466 pos_tag_len = pos;
467 pos++;
468 *pos++ = rep_data->token;
469 *pos++ = WLAN_RRM_REPORT_MODE_ACCEPT;
470 *pos++ = WLAN_RRM_MEASURE_TYPE_BEACON;
471
472 /* Beacon report element */
473 report.channel = bss_entry->channel;
474 /* Start time is not verified in CERT, to be done */
475 report.m_start_time = 0;
476 report.duration = wlan_cpu_to_le16(rep_data->duration);
477 report.rcpi = wlan_rrm_rssi_to_rcpi(-(bss_entry->rssi));
478 report.rsni = 255;
479 (void)memcpy(report.bssid, bss_entry->mac_address, IEEEtypes_ADDRESS_SIZE);
480 report.ant_id = 0;
481 /* Parent tsf is not verified in CERT, to be done */
482 report.parent_tsf = 0;
483 if (bss_entry->pvht_cap != MNULL)
484 {
485 report.report_info = (t_u8)WLAN_PHY_TYPE_VHT;
486 }
487 else if (bss_entry->pht_cap != MNULL)
488 {
489 report.report_info = (t_u8)WLAN_PHY_TYPE_HT;
490 }
491 else
492 {
493 /* Do nothing */
494 }
495
496 (void)memcpy((void *)pos, (const void *)&report, sizeof(mgmt_rrm_meas_beacon_report) - 1U);
497 pos += sizeof(mgmt_rrm_meas_beacon_report) - 1U;
498
499 /* Start adding reported frame body */
500 if (rep_data->report_detail == WLAN_RRM_REPORTING_DETAIL_NONE)
501 {
502 goto without_subelem;
503 }
504 /* The min length of reported frame body is 14 */
505 if (pos + 14 - *buf_pos > remained_len)
506 {
507 goto without_subelem;
508 }
509
510 *pos++ = WLAN_RRM_BEACON_REP_SUBELEM_FRAME_BODY;
511 /* The length will be filled below */
512 pos_sub_len = pos;
513 pos++;
514 /* TSF to be done */
515 wlan_rrm_put_le64(pos, bss_entry->network_tsf);
516 pos += 8;
517 wlan_rrm_put_le16(pos, bss_entry->beacon_period);
518 pos += 2;
519 (void)memcpy((void *)&cap_info, (const void *)&bss_entry->cap_info, sizeof(t_u16));
520 wlan_rrm_put_le16(pos, cap_info);
521 pos += 2;
522 /* SSID tag */
523 if (rep_data->report_detail == WLAN_RRM_REPORTING_DETAIL_ALL_FIELDS_AND_ELEMENTS ||
524 wlan_rrm_bit_field_is_set(rep_data->bits_field, (t_u8)SSID))
525 {
526 if (pos + sizeof(IEEEtypes_Header_t) + bss_entry->ssid.ssid_len - *buf_pos > remained_len)
527 {
528 goto part_subelem;
529 }
530
531 *pos++ = (t_u8)SSID;
532 *pos++ = (t_u8)bss_entry->ssid.ssid_len;
533 if (bss_entry->ssid.ssid_len > 0U)
534 {
535 (void)memcpy(pos, &(bss_entry->ssid.ssid), bss_entry->ssid.ssid_len);
536 pos += bss_entry->ssid.ssid_len;
537 }
538 }
539 /* RSN tag */
540 if (rep_data->report_detail == WLAN_RRM_REPORTING_DETAIL_ALL_FIELDS_AND_ELEMENTS ||
541 wlan_rrm_bit_field_is_set(rep_data->bits_field, (t_u8)RSN_IE))
542 {
543 if (bss_entry->rsn_ie_buff_len > (size_t)0U)
544 {
545 if (pos + bss_entry->rsn_ie_buff_len - *buf_pos > remained_len)
546 {
547 goto part_subelem;
548 }
549
550 (void)memcpy(pos, bss_entry->rsn_ie_buff, bss_entry->rsn_ie_buff_len);
551 pos += bss_entry->rsn_ie_buff_len;
552 }
553 }
554 /* Mobility Domain tag */
555 if (rep_data->report_detail == WLAN_RRM_REPORTING_DETAIL_ALL_FIELDS_AND_ELEMENTS ||
556 wlan_rrm_bit_field_is_set(rep_data->bits_field, (t_u8)MOBILITY_DOMAIN))
557 {
558 if (pos + sizeof(IEEEtypes_MobilityDomain_t) - *buf_pos > remained_len)
559 {
560 goto part_subelem;
561 }
562
563 if (bss_entry->mob_domain_exist)
564 {
565 (void)memcpy((void *)pos, (const void *)bss_entry->md_ie_buff, sizeof(IEEEtypes_MobilityDomain_t));
566 pos += sizeof(IEEEtypes_MobilityDomain_t);
567 }
568 }
569 /* RM Enable Capabilities tag */
570 if (rep_data->report_detail == WLAN_RRM_REPORTING_DETAIL_ALL_FIELDS_AND_ELEMENTS ||
571 wlan_rrm_bit_field_is_set(rep_data->bits_field, (t_u8)RRM_ENABLED_CAP))
572 {
573 if (pos + sizeof(bss_entry->rm_cap_saved) - *buf_pos > remained_len)
574 {
575 goto part_subelem;
576 }
577
578 if (bss_entry->rm_cap_exist)
579 {
580 (void)memcpy((void *)pos, (const void *)&bss_entry->rm_cap_saved, sizeof(bss_entry->rm_cap_saved));
581 pos += sizeof(bss_entry->rm_cap_saved);
582 }
583 }
584 /* Vendor Specific tag */
585 if (rep_data->report_detail == WLAN_RRM_REPORTING_DETAIL_ALL_FIELDS_AND_ELEMENTS ||
586 wlan_rrm_bit_field_is_set(rep_data->bits_field, (t_u8)VENDOR_SPECIFIC_221))
587 {
588 /* wpa */
589 if (bss_entry->wpa_ie_buff_len > 0U)
590 {
591 if (pos + bss_entry->wpa_ie_buff_len - *buf_pos > remained_len)
592 {
593 goto part_subelem;
594 }
595
596 (void)memcpy(pos, bss_entry->wpa_ie_buff, bss_entry->wpa_ie_buff_len);
597 pos += bss_entry->wpa_ie_buff_len;
598 }
599 /* wmm */
600 if (pos + sizeof(bss_entry->wmm_ie) - *buf_pos > remained_len)
601 {
602 goto part_subelem;
603 }
604
605 if (wlan_strlen((char *)(&bss_entry->wmm_ie)) > 0U)
606 {
607 (void)memcpy((void *)pos, (const void *)&bss_entry->wmm_ie, sizeof(bss_entry->wmm_ie));
608 pos += sizeof(bss_entry->wmm_ie);
609 }
610 /* Others */
611 if (bss_entry->vendor_ie_len > (t_u8)0U)
612 {
613 if (pos + bss_entry->vendor_ie_len - *buf_pos > remained_len)
614 {
615 goto part_subelem;
616 }
617
618 (void)memcpy(pos, bss_entry->vendor_ie_buff, bss_entry->vendor_ie_len);
619 pos += bss_entry->vendor_ie_len;
620 }
621 }
622
623 if (rep_data->last_ind > 0U)
624 {
625 if (pos + WLAN_RRM_BEACON_REP_FRAME_BODY_FRAGMENT_SUB_LEN + WLAN_RRM_BEACON_REP_LAST_INDICATION_SUB_LEN -
626 *buf_pos >
627 remained_len)
628 {
629 goto part_subelem;
630 }
631
632 /* Frame body fragment id subelement */
633 pos[0] = WLAN_RRM_BEACON_REP_SUBELEM_FRAME_BODY_FRAGMENT_ID;
634 pos[1] = 2; /* Length */
635 pos[2] = 1; /* Beacon report id */
636 pos[3] = 0; /* Fragment id number */
637 pos += WLAN_RRM_BEACON_REP_FRAME_BODY_FRAGMENT_SUB_LEN;
638 /* Last indication subelement */
639 pos[0] = WLAN_RRM_BEACON_REP_SUBELEM_LAST_INDICATION;
640 pos[1] = 1; /* Length */
641 pos[2] = 0; /* Temporarily, not the last packet */
642 *pos_last_indication = (t_u32)&pos[2];
643 pos += WLAN_RRM_BEACON_REP_LAST_INDICATION_SUB_LEN;
644 }
645 /* Fill the length */
646 part_subelem:
647 meas_sub_len = pos - pos_sub_len - 1;
648 *pos_sub_len = (t_u8)meas_sub_len;
649 without_subelem:
650 meas_tag_len = pos - pos_tag_len - 1;
651 *pos_tag_len = (t_u8)meas_tag_len;
652 *buf_pos = pos;
653 }
654
wlan_send_mgmt_rm_beacon_report(t_u8 dialog_tok,t_u8 * src_addr,t_u8 * dst_addr,t_u8 * rep,t_u32 rep_len,bool protect)655 void wlan_send_mgmt_rm_beacon_report(
656 t_u8 dialog_tok, t_u8 *src_addr, t_u8 *dst_addr, t_u8 *rep, t_u32 rep_len, bool protect)
657 {
658 wlan_mgmt_pkt *pmgmt_pkt_hdr = MNULL;
659 IEEEtypes_FrameCtl_t *mgmt_fc_p = MNULL;
660 t_u8 *pos = MNULL;
661 t_u16 pkt_len = 0;
662 int meas_pkt_len = 0;
663
664 pmgmt_pkt_hdr = wifi_PrepDefaultMgtMsg(
665 SUBTYPE_ACTION, (mlan_802_11_mac_addr *)(void *)dst_addr, (mlan_802_11_mac_addr *)(void *)src_addr,
666 (mlan_802_11_mac_addr *)(void *)dst_addr, sizeof(wlan_mgmt_pkt) + (t_u32)BEACON_REPORT_BUF_SIZE);
667 if (pmgmt_pkt_hdr == MNULL)
668 {
669 wifi_d("No memory available for beacon report");
670 return;
671 }
672
673 mgmt_fc_p = (IEEEtypes_FrameCtl_t *)(void *)&pmgmt_pkt_hdr->wlan_header.frm_ctl;
674 if (protect)
675 {
676 mgmt_fc_p->wep = 1;
677 }
678
679 /* 802.11 management body */
680 pos = (t_u8 *)pmgmt_pkt_hdr + sizeof(wlan_mgmt_pkt);
681 pos[0] = (t_u8)IEEE_MGMT_ACTION_CATEGORY_RADIO_RSRC;
682 pos[1] = (t_u8)IEEE_MGMT_RRM_RADIO_MEASUREMENT_REPORT;
683 pos[2] = dialog_tok;
684
685 pos += 3;
686 if (rep != MNULL && rep_len > 0U)
687 {
688 (void)memcpy(pos, rep, rep_len);
689 pos += rep_len;
690 }
691 meas_pkt_len = pos - (t_u8 *)pmgmt_pkt_hdr;
692 pkt_len = (t_u16)(meas_pkt_len);
693 pmgmt_pkt_hdr->frm_len = (t_u16)pkt_len - (t_u16)sizeof(t_u16);
694
695 /* Send packet */
696 (void)wifi_inject_frame(WLAN_BSS_TYPE_STA, (t_u8 *)pmgmt_pkt_hdr, pkt_len);
697 #if !CONFIG_MEM_POOLS
698 OSA_MemoryFree(pmgmt_pkt_hdr);
699 #else
700 OSA_MemoryPoolFree(buf_1536_MemoryPool, pmgmt_pkt_hdr);
701 #endif
702 }
703
wlan_process_radio_measurement_request(t_u8 * frame,t_u32 len,t_u8 * dest_addr,t_u8 * src_addr,bool protect)704 void wlan_process_radio_measurement_request(t_u8 *frame, t_u32 len, t_u8 *dest_addr, t_u8 *src_addr, bool protect)
705 {
706 t_u8 *pos = frame;
707 t_u8 dialog_tok;
708 bool duration_mandatory;
709
710 if (len < 3U)
711 {
712 wifi_d("Ignoring too short radio measurement request");
713 return;
714 }
715
716 dialog_tok = *pos;
717 /* Bypass dialog token and repetitions */
718 pos += 3;
719 len -= 3U;
720
721 /* Start process measurement quest */
722 mgmt_rrm_radio_meas_request *request = (mgmt_rrm_radio_meas_request *)(void *)pos;
723 if (request->ele_id != (t_u8)MEASURE_REQUEST)
724 {
725 wifi_d("eid %u is not radio measure request element", request->ele_id);
726 return;
727 }
728 if (request->length < 3U)
729 {
730 wifi_d("radio measure request element length too short");
731 return;
732 }
733 if (request->length > len - 2U)
734 {
735 wifi_d("radio measure request element length too long");
736 return;
737 }
738
739 duration_mandatory = !!((request->mode & WLAN_RRM_MEAS_REQUEST_MODE_DURATION_MANDATORY) != 0U);
740
741 switch (request->type)
742 {
743 /* Now only support beacon request */
744 case WLAN_RRM_MEASURE_TYPE_BEACON:
745 wlan_process_rm_beacon_req(request->variable, (t_u32)request->length - (t_u32)3, request->token, dialog_tok,
746 dest_addr, src_addr, protect, duration_mandatory);
747 break;
748 default:
749 wifi_d("radio measure request type %u is not supported", request->type);
750 break;
751 }
752 }
753
wlan_send_mgmt_link_measurement_report(t_u8 * src_addr,t_u8 * dst_addr,t_u8 * rep,t_u32 rep_len,bool protect)754 static void wlan_send_mgmt_link_measurement_report(
755 t_u8 *src_addr, t_u8 *dst_addr, t_u8 *rep, t_u32 rep_len, bool protect)
756 {
757 wlan_mgmt_pkt *pmgmt_pkt_hdr = MNULL;
758 IEEEtypes_FrameCtl_t *mgmt_fc_p = MNULL;
759 t_u8 *pos = MNULL;
760 t_u16 pkt_len = 0;
761 int meas_pkt_len = 0;
762
763 pmgmt_pkt_hdr = wifi_PrepDefaultMgtMsg(
764 SUBTYPE_ACTION, (mlan_802_11_mac_addr *)(void *)dst_addr, (mlan_802_11_mac_addr *)(void *)src_addr,
765 (mlan_802_11_mac_addr *)(void *)dst_addr, sizeof(wlan_mgmt_pkt) + LINK_MSR_REPORT_BUF_SIZE);
766 if (pmgmt_pkt_hdr == MNULL)
767 {
768 wifi_d("No memory available for beacon report");
769 return;
770 }
771
772 mgmt_fc_p = (IEEEtypes_FrameCtl_t *)(void *)&pmgmt_pkt_hdr->wlan_header.frm_ctl;
773 if (protect)
774 {
775 mgmt_fc_p->wep = 1;
776 }
777
778 /* 802.11 management body */
779 pos = (t_u8 *)pmgmt_pkt_hdr + sizeof(wlan_mgmt_pkt);
780 pos[0] = (t_u8)IEEE_MGMT_ACTION_CATEGORY_RADIO_RSRC;
781 pos[1] = (t_u8)IEEE_MGMT_RRM_LINK_MEASUREMENT_REPORT;
782 pos += 2;
783
784 if (rep != MNULL && rep_len > 0U)
785 {
786 (void)memcpy(pos, rep, rep_len);
787 pos += rep_len;
788 }
789 meas_pkt_len = pos - (t_u8 *)pmgmt_pkt_hdr;
790 pkt_len = (t_u16)meas_pkt_len;
791 pmgmt_pkt_hdr->frm_len = (t_u16)pkt_len - (t_u16)sizeof(t_u16);
792
793 /* Send packet */
794 (void)wifi_inject_frame(WLAN_BSS_TYPE_STA, (t_u8 *)pmgmt_pkt_hdr, pkt_len);
795 #if !CONFIG_MEM_POOLS
796 OSA_MemoryFree(pmgmt_pkt_hdr);
797 #else
798 OSA_MemoryPoolFree(buf_1536_MemoryPool, pmgmt_pkt_hdr);
799 #endif
800 }
801
wlan_process_link_measurement_request(t_u8 * frame,t_u32 len,t_u8 * dest_addr,t_u8 * src_addr,bool protect,RxPD * rxpd)802 void wlan_process_link_measurement_request(
803 t_u8 *frame, t_u32 len, t_u8 *dest_addr, t_u8 *src_addr, bool protect, RxPD *rxpd)
804 {
805 mgmt_rrm_link_meas_request *request = (mgmt_rrm_link_meas_request *)(void *)frame;
806 mgmt_rrm_link_meas_report report;
807 t_u32 channel;
808 wifi_SubBand_t subband;
809 wlan_txpwrlimit_t *txpwrlimit = NULL;
810 t_u8 ModulationGroup = 1; /* Default use OFDM modulation */
811 int meas_link_margin = 0;
812 int meas_noise = 0;
813
814 if (len < sizeof(mgmt_rrm_link_meas_request) - 1U)
815 {
816 wifi_d("Link measurement request too short");
817 return;
818 }
819
820 (void)memset(&report, 0, sizeof(report));
821 report.dialog_tok = request->dialog_tok;
822 meas_noise = -((int)rxpd->nf + (int)rxpd->snr);
823 report.rsni = (t_u8)(meas_noise);
824 report.rcpi = wlan_rrm_rssi_to_rcpi((int)report.rsni);
825
826 /* TPC Report */
827 channel = mlan_adap->priv[0]->curr_bss_params.bss_descriptor.channel;
828 if (channel <= 14U)
829 {
830 subband = SubBand_2_4_GHz;
831 /* use CCK modulation */
832 ModulationGroup = 0;
833 }
834 else if (channel < 100U)
835 {
836 subband = SubBand_5_GHz_0;
837 }
838 else if (channel < 149U)
839 {
840 subband = SubBand_5_GHz_1;
841 }
842 else if (channel < 183U)
843 {
844 subband = SubBand_5_GHz_2;
845 }
846 else
847 {
848 subband = SubBand_5_GHz_3;
849 }
850
851 #if !CONFIG_MEM_POOLS
852 txpwrlimit = OSA_MemoryAllocate(sizeof(wlan_txpwrlimit_t));
853 #else
854 txpwrlimit = OSA_MemoryPoolAllocate(buf_2048_MemoryPool);
855 #endif
856
857 if (txpwrlimit == NULL)
858 {
859 wifi_e("Cannot allocate memory for txpwrlimit");
860 return;
861 }
862
863 int rv = wlan_get_txpwrlimit(subband, txpwrlimit);
864 if (rv != WM_SUCCESS)
865 {
866 wifi_d("Unable to get TX PWR Limit configuration");
867 }
868 else
869 {
870 report.tpc_report.tx_power = (t_s8)wlan_link_measurement_get_tx_power(txpwrlimit, ModulationGroup, channel);
871 }
872
873 #if !CONFIG_MEM_POOLS
874 OSA_MemoryFree(txpwrlimit);
875 #else
876 OSA_MemoryPoolFree(buf_2048_MemoryPool, txpwrlimit);
877 #endif
878
879 /* Default use CCK5_5Mbps */
880 meas_link_margin = 78 - (int)report.rsni;
881 report.tpc_report.link_margin = (t_s8)meas_link_margin;
882 report.tpc_report.element_id = TPC_REPORT;
883 report.tpc_report.len = 2;
884
885 wlan_send_mgmt_link_measurement_report(dest_addr, src_addr, (t_u8 *)&report, sizeof(mgmt_rrm_link_meas_report) - 1U,
886 protect);
887 }
888
wifi_find_in_channels(t_u8 * channels,t_u8 entry_num,t_u8 chan)889 static bool wifi_find_in_channels(t_u8 *channels, t_u8 entry_num, t_u8 chan)
890 {
891 t_u8 i;
892 for (i = 0; i < entry_num; i++)
893 {
894 if (channels[i] == chan)
895 {
896 return true;
897 }
898 }
899 return false;
900 }
901
wlan_process_neighbor_report_response(t_u8 * frame,t_u32 len,t_u8 * dest_addr,t_u8 * src_addr,bool protect)902 void wlan_process_neighbor_report_response(t_u8 *frame, t_u32 len, t_u8 *dest_addr, t_u8 *src_addr, bool protect)
903 {
904 t_u8 *pos = frame;
905 t_u8 entry_num = 0, chan;
906 #if !CONFIG_MEM_POOLS
907 wlan_nlist_report_param *pnlist_rep_param =
908 (wlan_nlist_report_param *)OSA_MemoryAllocate(sizeof(wlan_nlist_report_param));
909 #else
910 wlan_nlist_report_param *pnlist_rep_param = (wlan_nlist_report_param *)OSA_MemoryPoolAllocate(buf_128_MemoryPool);
911 #endif
912
913 wifi_d("Neighbor report event");
914 #if CONFIG_WIFI_EXTRA_DEBUG
915 dump_hex(frame, len);
916 #endif
917 if (pnlist_rep_param == MNULL)
918 {
919 wifi_e("11k nlist report param buffer alloc failed %d", sizeof(wlan_nlist_report_param));
920 return;
921 }
922
923 if (len < 3U)
924 {
925 wifi_d("Ignoring too short radio measurement request");
926 #if !CONFIG_MEM_POOLS
927 OSA_MemoryFree((void *)pnlist_rep_param);
928 #else
929 OSA_MemoryPoolFree(buf_128_MemoryPool, pnlist_rep_param);
930 #endif
931 return;
932 }
933
934 memset(pnlist_rep_param, 0, sizeof(wlan_nlist_report_param));
935 /* Bypass dialog token */
936 pos += 1;
937 len -= 1U;
938
939 /* Start process neighbor report response */
940
941 #define NR_IE_MIN_LEN (IEEEtypes_ADDRESS_SIZE + 4 + 1 + 1 + 1)
942 #define WLAN_EID_NEIGHBOR_REPORT 52
943
944 while (len >= 2 + NR_IE_MIN_LEN)
945 {
946 t_u8 nr_len = pos[1];
947
948 if (pos[0] != WLAN_EID_NEIGHBOR_REPORT || nr_len < NR_IE_MIN_LEN)
949 {
950 wifi_d("Invalid Neighbor Report element: id=%u len=%u", pos[0], nr_len);
951 goto out;
952 }
953
954 if (2U + nr_len > len)
955 {
956 wifi_d("Invalid Neighbor Report element: id=%u len=%zu nr_len=%u", pos[0], len, nr_len);
957 goto out;
958 }
959 pos += 2;
960
961 chan = pos[IEEEtypes_ADDRESS_SIZE + 5];
962
963 wifi_d("channel = %d", chan);
964 if (!wifi_find_in_channels(pnlist_rep_param->channels, entry_num, chan))
965 {
966 pnlist_rep_param->channels[entry_num] = chan;
967 entry_num++;
968 }
969
970 pos += nr_len;
971 len -= 2 + nr_len;
972 }
973
974 if (entry_num == 0U)
975 {
976 goto out;
977 }
978
979 pnlist_rep_param->nlist_mode = WLAN_NLIST_11K;
980 pnlist_rep_param->num_channels = entry_num;
981
982 if (wifi_event_completion(WIFI_EVENT_NLIST_REPORT, WIFI_EVENT_REASON_SUCCESS, pnlist_rep_param) != WM_SUCCESS)
983 {
984 /* If fail to send message on queue, free allocated memory ! */
985 #if !CONFIG_MEM_POOLS
986 OSA_MemoryFree((void *)pnlist_rep_param);
987 #else
988 OSA_MemoryPoolFree(buf_128_MemoryPool, pnlist_rep_param);
989 #endif
990 }
991 return;
992
993 out:
994 #if !CONFIG_MEM_POOLS
995 OSA_MemoryFree((void *)pnlist_rep_param);
996 #else
997 OSA_MemoryPoolFree(buf_128_MemoryPool, pnlist_rep_param);
998 #endif
999 }
1000
1001 /**
1002 * @brief This function sets up the RRM Enabled Capabilites IE.
1003 *
1004 * @param pRrmCapIe A pointer to Rrm Enabled Capabilities element structure
1005 * @param bcnInterval Beacon interval
1006 *
1007 * @return void
1008 */
wlan_dot11k_formatRrmCapabilities(IEEEtypes_RrmEnabledCapabilities_t * pRrmCapIe,t_u16 bcnInterval)1009 void wlan_dot11k_formatRrmCapabilities(IEEEtypes_RrmEnabledCapabilities_t *pRrmCapIe, t_u16 bcnInterval)
1010 {
1011 (void)memset((void *)pRrmCapIe, 0x00, sizeof(IEEEtypes_RrmEnabledCapabilities_t));
1012
1013 pRrmCapIe->LinkMeas = 1;
1014 pRrmCapIe->NborRpt = 1;
1015 pRrmCapIe->BcnPassiveMeas = 1;
1016 pRrmCapIe->BcnActiveMeas = 1;
1017 pRrmCapIe->BcnTableMeas = 1;
1018 pRrmCapIe->TxStreamMeas = 1;
1019
1020 pRrmCapIe->OpChanMaxMeas = 4; /* TBD: copy the result from fw dot11k_getRmMeasMax() */
1021 pRrmCapIe->NonOpChanMaxMeas = 2; /* TBD: copy the result from fw dot11k_getRmMeasMax() */
1022
1023 pRrmCapIe->ParallelMeas = 0;
1024 pRrmCapIe->RepeatMeas = 0;
1025 }
1026
wlan_send_mgmt_rm_neighbor_request(mlan_private * pmpriv,t_u8 * ssid,t_u8 ssid_len)1027 int wlan_send_mgmt_rm_neighbor_request(mlan_private *pmpriv, t_u8 *ssid, t_u8 ssid_len)
1028 {
1029 t_u16 pkt_len;
1030 mlan_802_11_mac_addr *da = MNULL;
1031 mlan_802_11_mac_addr *sa = MNULL;
1032 wlan_mgmt_pkt *pmgmt_pkt_hdr = MNULL;
1033 t_u8 *pos = MNULL;
1034 int meas_pkt_len = 0;
1035
1036 if (pmpriv->bss_index != (t_u8)MLAN_BSS_ROLE_STA || pmpriv->media_connected != MTRUE)
1037 {
1038 wifi_d("invalid interface %d for sending neighbor report request", pmpriv->bss_index);
1039 return (int)MLAN_STATUS_FAILURE;
1040 }
1041
1042 da = &pmpriv->curr_bss_params.bss_descriptor.mac_address;
1043 sa = (mlan_802_11_mac_addr *)(void *)(&pmpriv->curr_addr[0]);
1044 pmgmt_pkt_hdr =
1045 wifi_PrepDefaultMgtMsg(SUBTYPE_ACTION, da, sa, da, sizeof(wlan_mgmt_pkt) + NEIGHBOR_REQUEST_BUF_SIZE);
1046 if (pmgmt_pkt_hdr == MNULL)
1047 {
1048 wifi_e("No memory for neighbor report request");
1049 return (int)MLAN_STATUS_FAILURE;
1050 }
1051
1052 /* 802.11 management body */
1053 pos = (t_u8 *)pmgmt_pkt_hdr + sizeof(wlan_mgmt_pkt);
1054 pos[0] = (t_u8)IEEE_MGMT_ACTION_CATEGORY_RADIO_RSRC;
1055 pos[1] = (t_u8)IEEE_MGMT_RRM_NEIGHBOR_REPORT_REQUEST;
1056 pos[2] = pmpriv->neighbor_rep_token++;
1057
1058 if (pmpriv->neighbor_rep_token == (t_u8)255U)
1059 {
1060 pmpriv->neighbor_rep_token = (t_u8)1U;
1061 }
1062
1063 pos += 3;
1064
1065 /* SSID Tag */
1066 if (ssid_len > (t_u8)0U)
1067 {
1068 pos[0] = (t_u8)SSID;
1069 pos[1] = ssid_len;
1070 (void)memcpy(&pos[2], ssid, ssid_len);
1071 pos += ssid_len + 2U;
1072 }
1073
1074 meas_pkt_len = pos - (t_u8 *)pmgmt_pkt_hdr;
1075 pkt_len = (t_u16)meas_pkt_len;
1076 pmgmt_pkt_hdr->frm_len = pkt_len - (t_u16)sizeof(pmgmt_pkt_hdr->frm_len);
1077
1078 (void)wifi_inject_frame(WLAN_BSS_TYPE_STA, (t_u8 *)pmgmt_pkt_hdr, pkt_len);
1079
1080 #if !CONFIG_MEM_POOLS
1081 OSA_MemoryFree(pmgmt_pkt_hdr);
1082 #else
1083 OSA_MemoryPoolFree(buf_1536_MemoryPool, pmgmt_pkt_hdr);
1084 #endif
1085
1086 return (int)MLAN_STATUS_SUCCESS;
1087 }
1088 #endif /* CONFIG_11K */
1089