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(&param->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(&param->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