1 /** @file mlan_11d.c
2  *
3  *  @brief  This file provides functions for 802.11D
4  *
5  *  Copyright 2008-2024 NXP
6  *
7  *  SPDX-License-Identifier: BSD-3-Clause
8  *
9  */
10 
11 /********************************************************
12 Change log:
13     10/21/2008: initial version
14 ********************************************************/
15 
16 #include <mlan_api.h>
17 
18 /* Additional WMSDK header files */
19 #include <wmerrno.h>
20 #include <osa.h>
21 
22 /* Always keep this include at the end of all include files */
23 #include <mlan_remap_mem_operations.h>
24 /********************************************************
25                 Local Variables
26 ********************************************************/
27 
28 /** Region code mapping */
29 typedef struct _region_code_mapping
30 {
31     /** Region */
32     t_u8 region[COUNTRY_CODE_LEN];
33     /** Code */
34     t_u8 code;
35 } region_code_mapping_t;
36 
37 /** Region code mapping table */
38 static const region_code_mapping_t region_code_mapping[] = {
39     {"WW ", 0x00}, /* World Wide Safe */
40     {"US ", 0x10}, /* US FCC */
41     {"CA ", 0x20}, /* IC Canada */
42     {"SG ", 0x10}, /* Singapore */
43     {"EU ", 0x30}, /* ETSI */
44     {"AU ", 0x30}, /* Australia */
45     {"KR ", 0x30}, /* Republic Of Korea */
46     {"FR ", 0x32}, /* France */
47     {"JP ", 0xFF}, /* Japan */
48     {"CN ", 0x50}, /* China */
49 };
50 
51 #ifdef STA_SUPPORT
52 /** Default Tx power */
53 #define TX_PWR_DEFAULT 10
54 
55 /** Universal region code */
56 #define UNIVERSAL_REGION_CODE 0xff
57 
58 #define EU_REGION_CODE 0x30
59 
60 /* Following two structures define the supported channels */
61 /** Channels for 802.11b/g */
62 static const chan_freq_power_t channel_freq_power_UN_BG[] = {
63     {1, 2412, TX_PWR_DEFAULT},  {2, 2417, TX_PWR_DEFAULT},  {3, 2422, TX_PWR_DEFAULT},  {4, 2427, TX_PWR_DEFAULT},
64     {5, 2432, TX_PWR_DEFAULT},  {6, 2437, TX_PWR_DEFAULT},  {7, 2442, TX_PWR_DEFAULT},  {8, 2447, TX_PWR_DEFAULT},
65     {9, 2452, TX_PWR_DEFAULT},  {10, 2457, TX_PWR_DEFAULT}, {11, 2462, TX_PWR_DEFAULT}, {12, 2467, TX_PWR_DEFAULT},
66     {13, 2472, TX_PWR_DEFAULT}, {14, 2484, TX_PWR_DEFAULT}};
67 
68 #if CONFIG_5GHz_SUPPORT
69 /** Channels for 802.11a/j */
70 static chan_freq_power_t channel_freq_power_UN_AJ[] = {
71     {8, 5040, TX_PWR_DEFAULT},   {12, 5060, TX_PWR_DEFAULT},  {16, 5080, TX_PWR_DEFAULT},  {34, 5170, TX_PWR_DEFAULT},
72     {38, 5190, TX_PWR_DEFAULT},  {42, 5210, TX_PWR_DEFAULT},  {46, 5230, TX_PWR_DEFAULT},  {36, 5180, TX_PWR_DEFAULT},
73     {40, 5200, TX_PWR_DEFAULT},  {44, 5220, TX_PWR_DEFAULT},  {48, 5240, TX_PWR_DEFAULT},  {52, 5260, TX_PWR_DEFAULT},
74     {56, 5280, TX_PWR_DEFAULT},  {60, 5300, TX_PWR_DEFAULT},  {64, 5320, TX_PWR_DEFAULT},  {100, 5500, TX_PWR_DEFAULT},
75     {104, 5520, TX_PWR_DEFAULT}, {108, 5540, TX_PWR_DEFAULT}, {112, 5560, TX_PWR_DEFAULT}, {116, 5580, TX_PWR_DEFAULT},
76     {120, 5600, TX_PWR_DEFAULT}, {124, 5620, TX_PWR_DEFAULT}, {128, 5640, TX_PWR_DEFAULT}, {132, 5660, TX_PWR_DEFAULT},
77     {136, 5680, TX_PWR_DEFAULT}, {140, 5700, TX_PWR_DEFAULT}, {144, 5720, TX_PWR_DEFAULT}, {149, 5745, TX_PWR_DEFAULT},
78     {153, 5765, TX_PWR_DEFAULT}, {157, 5785, TX_PWR_DEFAULT}, {161, 5805, TX_PWR_DEFAULT},
79 #if CONFIG_UNII4_BAND_SUPPORT
80     {165, 5825, TX_PWR_DEFAULT}, {169, 5845, TX_PWR_DEFAULT}, {173, 5865, TX_PWR_DEFAULT}, {177, 5885, TX_PWR_DEFAULT},
81 #else
82     {165, 5825, TX_PWR_DEFAULT}
83 #endif
84     /*  {240, 4920, TX_PWR_DEFAULT},
85         {244, 4940, TX_PWR_DEFAULT},
86         {248, 4960, TX_PWR_DEFAULT},
87         {252, 4980, TX_PWR_DEFAULT},
88     channels for 11J JP 10M channel gap */
89 };
90 #endif /* CONFIG_5GHz_SUPPORT */
91 #endif /* STA_SUPPORT */
92 /********************************************************
93                 Global Variables
94 ********************************************************/
95 
96 /********************************************************
97                 Local Functions
98 ********************************************************/
99 
100 /**
101  *  @brief This function converts region string to region code
102  *
103  *  @param region_string    Region string
104  *
105  *  @return                 Region code
106  */
region_string_2_region_code(t_u8 * region_string)107 t_u8 region_string_2_region_code(t_u8 *region_string)
108 {
109     t_u8 i;
110 
111     ENTER();
112 
113     for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++)
114     {
115         if (memcmp(region_string, region_code_mapping[i].region, COUNTRY_CODE_LEN - 1) == 0)
116         {
117             LEAVE();
118             return region_code_mapping[i].code;
119         }
120     }
121 
122     if (wlan_is_etsi_country(NULL, region_string))
123     {
124         LEAVE();
125         return EU_REGION_CODE;
126     }
127 
128     /* Default is WW */
129     LEAVE();
130     return region_code_mapping[0].code;
131 }
132 
133 /**
134  *  @brief This function converts region string to integer code
135  *
136  *  @param pmadapter    A pointer to mlan_adapter structure
137  *  @param region       Region string
138  *  @param code         [output] Region code
139  *
140  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
141  */
wlan_11d_region_2_code(pmlan_adapter pmadapter,t_u8 * region,OUT t_u8 * code)142 mlan_status wlan_11d_region_2_code(pmlan_adapter pmadapter, t_u8 *region, OUT t_u8 *code)
143 {
144     t_u8 i;
145     t_u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
146 
147     ENTER();
148 
149     if (wlan_is_etsi_country(pmadapter, region))
150     {
151         *code = EU_REGION_CODE;
152         LEAVE();
153         return MLAN_STATUS_SUCCESS;
154     }
155 
156     /* Look for code in mapping table */
157     for (i = 0; i < size; i++)
158     {
159         if (!__memcmp(pmadapter, region_code_mapping[i].region, region, COUNTRY_CODE_LEN))
160         {
161             *code = region_code_mapping[i].code;
162             LEAVE();
163             return MLAN_STATUS_SUCCESS;
164         }
165     }
166 
167     LEAVE();
168     return MLAN_STATUS_FAILURE;
169 }
170 
171 /**
172  *  @brief This function converts country index to country string
173  *
174  *  @param code         Country index
175  *
176  *  @return             Country string
177  */
wlan_11d_country_index_2_string(int country)178 const uint8_t *wlan_11d_country_index_2_string(int country)
179 {
180     if (country < 1 || country > 9)
181     {
182         return ((const uint8_t *)region_code_mapping[0].region);
183     }
184     return ((const uint8_t *)region_code_mapping[country - 1].region);
185 }
186 
187 /**
188  *  @brief This function converts integer code to region string
189  *
190  *  @param pmadapter    A pointer to mlan_adapter structure
191  *  @param code         Region code
192  *
193  *  @return             Region string
194  */
wlan_11d_code_2_region(pmlan_adapter pmadapter,t_u8 code)195 const t_u8 *wlan_11d_code_2_region(pmlan_adapter pmadapter, t_u8 code)
196 {
197     t_u8 i;
198     t_u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t);
199 
200     ENTER();
201 
202     /* Look for code in mapping table */
203     for (i = 0; i < size; i++)
204     {
205         if (region_code_mapping[i].code == code)
206         {
207             LEAVE();
208             return ((const t_u8 *)region_code_mapping[i].region);
209         }
210     }
211 
212     LEAVE();
213     /* Default is WW */
214     return ((const t_u8 *)region_code_mapping[0].region);
215 }
216 
217 #ifdef STA_SUPPORT
218 /**
219  *  @brief This function Checks if channel txpwr is learned from AP/IBSS
220  *
221  *  @param pmadapter            A pointer to mlan_adapter structure
222  *  @param band                 Band number
223  *  @param chan                 Channel number
224  *  @param parsed_region_chan   Pointer to parsed_region_chan_11d_t
225  *
226  *  @return                     MTRUE or MFALSE
227  */
wlan_11d_channel_known(pmlan_adapter pmadapter,t_u16 band,t_u8 chan,parsed_region_chan_11d_t * parsed_region_chan)228 static t_u8 wlan_11d_channel_known(pmlan_adapter pmadapter,
229                                    t_u16 band,
230                                    t_u8 chan,
231                                    parsed_region_chan_11d_t *parsed_region_chan)
232 {
233     chan_power_11d_t *pchan_pwr = parsed_region_chan->chan_pwr;
234     t_u8 no_of_chan             = parsed_region_chan->no_of_chan;
235     t_u8 i                      = 0;
236     t_u8 ret                    = MFALSE;
237     mlan_private *pmpriv;
238 
239     ENTER();
240 
241     HEXDUMP("11D: parsed_region_chan", (t_u8 *)pchan_pwr, sizeof(chan_power_11d_t) * no_of_chan);
242 
243     /* Search channel */
244     for (i = 0; i < no_of_chan; i++)
245     {
246         if (chan == pchan_pwr[i].chan && band == pchan_pwr[i].band)
247         {
248             PRINTM(MINFO, "11D: Found channel:%d (band:%d)\n", chan, band);
249             ret = MTRUE;
250 
251             if ((band & BAND_A) != 0U)
252             {
253                 /* If chan is a DFS channel, we need to see an AP on it */
254                 pmpriv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA);
255                 if (pmpriv != MNULL && wlan_11h_radar_detect_required(pmpriv, chan))
256                 {
257                     PRINTM(MINFO, "11H: DFS channel %d, and ap_seen=%d\n", chan, pchan_pwr[i].ap_seen);
258                     ret = pchan_pwr[i].ap_seen;
259                 }
260             }
261 
262             LEAVE();
263             return ret;
264         }
265     }
266 
267     PRINTM(MINFO, "11D: Could not find channel:%d (band:%d)\n", chan, band);
268     LEAVE();
269     return ret;
270 }
271 
272 /**
273  *  @brief This function generates parsed_region_chan from Domain Info
274  *           learned from AP/IBSS
275  *
276  *  @param pmadapter            Pointer to mlan_adapter structure
277  *  @param region_chan          Pointer to region_chan_t
278  *  @param parsed_region_chan   Pointer to parsed_region_chan_11d_t
279  *
280  *  @return                     N/A
281  */
wlan_11d_generate_parsed_region_chan(pmlan_adapter pmadapter,region_chan_t * region_chan,parsed_region_chan_11d_t * parsed_region_chan)282 static t_void wlan_11d_generate_parsed_region_chan(pmlan_adapter pmadapter,
283                                                    region_chan_t *region_chan,
284                                                    parsed_region_chan_11d_t *parsed_region_chan)
285 {
286     const chan_freq_power_t *cfp;
287     t_u8 i;
288 
289     ENTER();
290 
291     /* Region channel must be provided */
292     if (region_chan == MNULL)
293     {
294         PRINTM(MWARN, "11D: region_chan is MNULL\n");
295         LEAVE();
296         return;
297     }
298 
299     /* Get channel-frequency-power trio */
300     cfp = region_chan->pcfp;
301     if (cfp == MNULL)
302     {
303         PRINTM(MWARN, "11D: cfp equal MNULL\n");
304         LEAVE();
305         return;
306     }
307 
308     /* Set channel, band and power */
309     for (i = 0; i < region_chan->num_cfp; i++)
310     {
311         parsed_region_chan->chan_pwr[i].chan = (t_u8)cfp->channel;
312         parsed_region_chan->chan_pwr[i].band = (t_u8)region_chan->band;
313         parsed_region_chan->chan_pwr[i].pwr  = (t_u8)cfp->max_tx_power;
314         PRINTM(MINFO, "11D: Chan[%d] Band[%d] Pwr[%d]\n", parsed_region_chan->chan_pwr[i].chan,
315                parsed_region_chan->chan_pwr[i].band, parsed_region_chan->chan_pwr[i].pwr);
316         cfp++;
317     }
318     parsed_region_chan->no_of_chan = region_chan->num_cfp;
319 
320     PRINTM(MINFO, "11D: no_of_chan[%d]\n", parsed_region_chan->no_of_chan);
321 
322     LEAVE();
323     return;
324 }
325 
326 /**
327  *  @brief This function generates domain_info from parsed_region_chan
328  *
329  *  @param pmadapter            Pointer to mlan_adapter structure
330  *  @param parsed_region_chan   Pointer to parsed_region_chan_11d_t
331  *
332  *  @return                     MLAN_STATUS_SUCCESS
333  */
wlan_11d_generate_domain_info(pmlan_adapter pmadapter,parsed_region_chan_11d_t * parsed_region_chan)334 static mlan_status wlan_11d_generate_domain_info(pmlan_adapter pmadapter, parsed_region_chan_11d_t *parsed_region_chan)
335 {
336     t_u8 no_of_sub_band    = 0;
337     t_u8 no_of_chan        = parsed_region_chan->no_of_chan;
338     t_u8 no_of_parsed_chan = 0;
339     t_u8 first_chan = 0, next_chan = 0, max_pwr = 0;
340     t_u8 i, flag = MFALSE;
341     wlan_802_11d_domain_reg_t *domain_info = &pmadapter->domain_reg;
342 
343     ENTER();
344 
345     /* Should be only place that clear domain_reg (besides init) */
346     (void)__memset(pmadapter, domain_info, 0, sizeof(wlan_802_11d_domain_reg_t));
347 
348     /* Set country code */
349     (void)__memcpy(pmadapter, domain_info->country_code,
350                    wlan_11d_code_2_region(pmadapter, (t_u8)pmadapter->region_code), COUNTRY_CODE_LEN);
351 
352     PRINTM(MINFO, "11D: Number of channel = %d\n", no_of_chan);
353     HEXDUMP("11D: parsed_region_chan", (t_u8 *)parsed_region_chan, sizeof(parsed_region_chan_11d_t));
354 
355     /* Set channel and power */
356     for (i = 0; i < no_of_chan; i++)
357     {
358         if (!flag)
359         {
360             flag      = MTRUE;
361             next_chan = first_chan = parsed_region_chan->chan_pwr[i].chan;
362             max_pwr                = parsed_region_chan->chan_pwr[i].pwr;
363             no_of_parsed_chan      = 1;
364             continue;
365         }
366 
367         if (parsed_region_chan->chan_pwr[i].chan == next_chan + 1U && parsed_region_chan->chan_pwr[i].pwr == max_pwr)
368         {
369             next_chan++;
370             no_of_parsed_chan++;
371         }
372         else
373         {
374             domain_info->sub_band[no_of_sub_band].first_chan = first_chan;
375             domain_info->sub_band[no_of_sub_band].no_of_chan = no_of_parsed_chan;
376             domain_info->sub_band[no_of_sub_band].max_tx_pwr = max_pwr;
377             no_of_sub_band++;
378             no_of_parsed_chan = 1;
379             next_chan = first_chan = parsed_region_chan->chan_pwr[i].chan;
380             max_pwr                = parsed_region_chan->chan_pwr[i].pwr;
381         }
382     }
383 
384     if (flag != 0U)
385     {
386         domain_info->sub_band[no_of_sub_band].first_chan = first_chan;
387         domain_info->sub_band[no_of_sub_band].no_of_chan = no_of_parsed_chan;
388         domain_info->sub_band[no_of_sub_band].max_tx_pwr = max_pwr;
389         no_of_sub_band++;
390     }
391     domain_info->no_of_sub_band = no_of_sub_band;
392 
393     PRINTM(MINFO, "11D: Number of sub-band =0x%x\n", domain_info->no_of_sub_band);
394     HEXDUMP("11D: domain_info", (t_u8 *)domain_info,
395             COUNTRY_CODE_LEN + 1 + sizeof(IEEEtypes_SubbandSet_t) * no_of_sub_band);
396     LEAVE();
397     return MLAN_STATUS_SUCCESS;
398 }
399 
400 /**
401  *  @brief This function updates the channel power table with the channel
402  *            present in BSSDescriptor.
403  *
404  *  @param pmpriv       A pointer to mlan_private structure
405  *  @param pbss_desc    A pointer to BSSDescriptor_t
406  *
407  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
408  */
wlan_11d_update_chan_pwr_table(mlan_private * pmpriv,BSSDescriptor_t * pbss_desc)409 static mlan_status wlan_11d_update_chan_pwr_table(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc)
410 {
411     mlan_adapter *pmadapter                      = pmpriv->adapter;
412     parsed_region_chan_11d_t *parsed_region_chan = &pmadapter->parsed_region_chan;
413     t_u16 i;
414     t_u8 tx_power = 0;
415     t_u8 chan;
416 
417     ENTER();
418 
419     chan = pbss_desc->phy_param_set.ds_param_set.current_chan;
420 
421     tx_power = wlan_get_txpwr_of_chan_from_cfp(pmpriv, chan);
422 
423     if (!tx_power)
424     {
425         PRINTM(MMSG, "11D: Invalid channel\n");
426         LEAVE();
427         return MLAN_STATUS_FAILURE;
428     }
429 
430     /* Check whether the channel already exists in channel power table of
431        parsed region */
432     for (i = 0; ((i < parsed_region_chan->no_of_chan) && (i < MAX_NO_OF_CHAN)); i++)
433     {
434         if (parsed_region_chan->chan_pwr[i].chan == chan && parsed_region_chan->chan_pwr[i].band == pbss_desc->bss_band)
435         {
436             /* Channel already exists, use minimum of existing and tx_power */
437             parsed_region_chan->chan_pwr[i].pwr     = MIN(parsed_region_chan->chan_pwr[i].pwr, tx_power);
438             parsed_region_chan->chan_pwr[i].ap_seen = MTRUE;
439             break;
440         }
441     }
442 
443     if (i == parsed_region_chan->no_of_chan && i < MAX_NO_OF_CHAN)
444     {
445         /* Channel not found. Update the channel in the channel-power table */
446         parsed_region_chan->chan_pwr[i].chan    = chan;
447         parsed_region_chan->chan_pwr[i].band    = (t_u8)pbss_desc->bss_band;
448         parsed_region_chan->chan_pwr[i].pwr     = tx_power;
449         parsed_region_chan->chan_pwr[i].ap_seen = MTRUE;
450         parsed_region_chan->no_of_chan++;
451     }
452 
453     LEAVE();
454     return MLAN_STATUS_SUCCESS;
455 }
456 
457 /**
458  *  @brief This function finds the no_of_chan-th chan after the first_chan
459  *
460  *  @param pmadapter  A pointer to mlan_adapter structure
461  *  @param band       Band
462  *  @param first_chan First channel number
463  *  @param no_of_chan Number of channels
464  *  @param chan       Pointer to the returned no_of_chan-th chan number
465  *
466  *  @return           MTRUE or MFALSE
467  */
wlan_11d_get_chan(pmlan_adapter pmadapter,t_u16 band,t_u8 first_chan,t_u8 no_of_chan,t_u8 * chan)468 static t_u8 wlan_11d_get_chan(pmlan_adapter pmadapter, t_u16 band, t_u8 first_chan, t_u8 no_of_chan, t_u8 *chan)
469 {
470     const chan_freq_power_t *cfp = MNULL;
471     t_u8 i;
472     t_u8 cfp_no = 0;
473 
474     ENTER();
475     if ((band & (BAND_B | BAND_G | BAND_GN)) != 0U)
476     {
477         cfp    = (const chan_freq_power_t *)channel_freq_power_UN_BG;
478         cfp_no = sizeof(channel_freq_power_UN_BG) / sizeof(chan_freq_power_t);
479     }
480 #if CONFIG_5GHz_SUPPORT
481     else if ((band & (BAND_A | BAND_AN)) != 0U)
482     {
483         cfp    = channel_freq_power_UN_AJ;
484         cfp_no = sizeof(channel_freq_power_UN_AJ) / sizeof(chan_freq_power_t);
485     }
486 #endif /* CONFIG_5GHz_SUPPORT */
487     else
488     {
489         PRINTM(MERROR, "11D: Wrong Band[%d]\n", band);
490         LEAVE();
491         return MFALSE;
492     }
493     /* Locate the first_chan */
494     for (i = 0; i < cfp_no; i++)
495     {
496         if ((cfp + i)->channel == first_chan)
497         {
498             PRINTM(MINFO, "11D: first_chan found\n");
499             break;
500         }
501     }
502 
503     if (i < cfp_no)
504     {
505         /* Check if beyond the boundary */
506         if (i + no_of_chan < cfp_no)
507         {
508             /* Get first_chan + no_of_chan */
509             *chan = (t_u8)(cfp + i + no_of_chan)->channel;
510             LEAVE();
511             return MTRUE;
512         }
513     }
514 
515     LEAVE();
516     return MFALSE;
517 }
518 
519 /**
520  *  @brief This function processes the country info present in BSSDescriptor.
521  *
522  *  @param pmpriv       A pointer to mlan_private structure
523  *  @param pbss_desc     A pointer to BSSDescriptor_t
524  *
525  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
526  */
wlan_11d_process_country_info(mlan_private * pmpriv,BSSDescriptor_t * pbss_desc)527 static mlan_status wlan_11d_process_country_info(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc)
528 {
529     mlan_adapter *pmadapter = pmpriv->adapter;
530     parsed_region_chan_11d_t region_chan;
531     parsed_region_chan_11d_t *parsed_region_chan = &pmadapter->parsed_region_chan;
532     t_u16 i, j, num_chan_added = 0;
533 
534     ENTER();
535 
536     (void)__memset(pmadapter, &region_chan, 0, sizeof(parsed_region_chan_11d_t));
537 
538     /* Parse 11D country info */
539     if (wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info, pbss_desc->bss_band, &region_chan) !=
540         MLAN_STATUS_SUCCESS)
541     {
542         LEAVE();
543         return MLAN_STATUS_FAILURE;
544     }
545 
546     if (parsed_region_chan->no_of_chan != 0U)
547     {
548         /*
549          * Check if the channel number already exists in the
550          * chan-power table of parsed_region_chan
551          */
552         for (i = 0; (i < region_chan.no_of_chan && i < MAX_NO_OF_CHAN); i++)
553         {
554             for (j = 0; (j < parsed_region_chan->no_of_chan && j < MAX_NO_OF_CHAN); j++)
555             {
556                 /*
557                  * Channel already exists, update the tx power with new tx
558                  * power, since country IE is valid here.
559                  */
560                 if (region_chan.chan_pwr[i].chan == parsed_region_chan->chan_pwr[j].chan &&
561                     region_chan.chan_pwr[i].band == parsed_region_chan->chan_pwr[j].band)
562                 {
563                     parsed_region_chan->chan_pwr[j].pwr = region_chan.chan_pwr[i].pwr;
564                     break;
565                 }
566             }
567 
568             if (j == parsed_region_chan->no_of_chan && j < MAX_NO_OF_CHAN)
569             {
570                 if (parsed_region_chan->no_of_chan + num_chan_added >= MAX_NO_OF_CHAN)
571                 {
572                     break;
573                 }
574                 /*
575                  * Channel does not exist in the channel power table,
576                  * update this new chan and tx_power to the channel power table
577                  */
578                 parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan + num_chan_added].chan =
579                     region_chan.chan_pwr[i].chan;
580                 parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan + num_chan_added].band =
581                     region_chan.chan_pwr[i].band;
582                 parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan + num_chan_added].pwr =
583                     region_chan.chan_pwr[i].pwr;
584                 parsed_region_chan->chan_pwr[parsed_region_chan->no_of_chan + num_chan_added].ap_seen = MFALSE;
585                 num_chan_added++;
586             }
587         }
588         parsed_region_chan->no_of_chan += (t_u8)num_chan_added;
589         if (parsed_region_chan->no_of_chan > MAX_NO_OF_CHAN)
590         {
591             parsed_region_chan->no_of_chan = MAX_NO_OF_CHAN;
592         }
593     }
594     else
595     {
596         /* Parsed region is empty, copy the first one */
597         (void)__memcpy(pmadapter, parsed_region_chan, &region_chan, sizeof(parsed_region_chan_11d_t));
598     }
599 
600     LEAVE();
601     return MLAN_STATUS_SUCCESS;
602 }
603 
604 /**
605  *  @brief This helper function copies chan_power_11d_t element
606  *
607  *  @param chan_dst   Pointer to destination of chan_power
608  *  @param chan_src   Pointer to source of chan_power
609  *
610  *  @return           N/A
611  */
wlan_11d_copy_chan_power(chan_power_11d_t * chan_dst,chan_power_11d_t * chan_src)612 static t_void wlan_11d_copy_chan_power(chan_power_11d_t *chan_dst, chan_power_11d_t *chan_src)
613 {
614     ENTER();
615 
616     chan_dst->chan    = chan_src->chan;
617     chan_dst->band    = chan_src->band;
618     chan_dst->pwr     = chan_src->pwr;
619     chan_dst->ap_seen = chan_src->ap_seen;
620 
621     LEAVE();
622     return;
623 }
624 
625 /**
626  *  @brief This function sorts parsed_region_chan in ascending
627  *  channel number.
628  *
629  *  @param parsed_region_chan   Pointer to parsed_region_chan_11d_t
630  *
631  *  @return                     N/A
632  */
wlan_11d_sort_parsed_region_chan(parsed_region_chan_11d_t * parsed_region_chan)633 static t_void wlan_11d_sort_parsed_region_chan(parsed_region_chan_11d_t *parsed_region_chan)
634 {
635     t_u8 i, j;
636     chan_power_11d_t temp;
637     chan_power_11d_t *pchan_power = parsed_region_chan->chan_pwr;
638 
639     ENTER();
640 
641     PRINTM(MINFO, "11D: Number of channel = %d\n", parsed_region_chan->no_of_chan);
642 
643     // Use insertion sort method
644     for (i = 1; i < parsed_region_chan->no_of_chan; i++)
645     {
646         wlan_11d_copy_chan_power(&temp, pchan_power + i);
647         for (j = i; j > 0 && (pchan_power + j - 1)->chan > temp.chan; j--)
648         {
649             wlan_11d_copy_chan_power(pchan_power + j, pchan_power + j - 1);
650         }
651         wlan_11d_copy_chan_power(pchan_power + j, &temp);
652     }
653 
654     HEXDUMP("11D: parsed_region_chan", (t_u8 *)parsed_region_chan, sizeof(parsed_region_chan_11d_t));
655 
656     LEAVE();
657     return;
658 }
659 #endif /* STA_SUPPORT */
660 
661 /**
662  *  @brief This function sends domain info to FW
663  *
664  *  @param pmpriv       A pointer to mlan_private structure
665  *  @param pioctl_buf   A pointer to MLAN IOCTL Request buffer
666  *
667  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
668  */
wlan_11d_send_domain_info(mlan_private * pmpriv,t_void * pioctl_buf,t_bool is_op_special_set)669 static mlan_status wlan_11d_send_domain_info(mlan_private *pmpriv, t_void *pioctl_buf, t_bool is_op_special_set)
670 {
671     mlan_status ret = MLAN_STATUS_SUCCESS;
672 
673     ENTER();
674 
675     /* Send cmd to FW to set domain info */
676     if (is_op_special_set)
677     {
678         ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11D_DOMAIN_INFO, HostCmd_ACT_SPC_SET, 0, (t_void *)pioctl_buf,
679                                MNULL);
680     }
681     else
682     {
683         ret = wlan_prepare_cmd(pmpriv, HostCmd_CMD_802_11D_DOMAIN_INFO, HostCmd_ACT_GEN_SET, 0, (t_void *)pioctl_buf,
684                                MNULL);
685     }
686     if (ret != MLAN_STATUS_SUCCESS)
687     {
688         PRINTM(MERROR, "11D: Failed to download domain Info\n");
689     }
690 
691     LEAVE();
692     return ret;
693 }
694 
695 /**
696  *  @brief This function overwrites domain_info
697  *
698  *  @param pmadapter        Pointer to mlan_adapter structure
699  *  @param band             Intended operating band
700  *  @param country_code     Intended country code
701  *  @param num_sub_band     Count of tuples in list below
702  *  @param sub_band_list    List of sub_band tuples
703  *
704  *  @return                 MLAN_STATUS_SUCCESS
705  */
wlan_11d_set_domain_info(mlan_private * pmpriv,t_u16 band,const t_u8 country_code[COUNTRY_CODE_LEN],t_u8 num_sub_band,IEEEtypes_SubbandSet_t * sub_band_list)706 mlan_status wlan_11d_set_domain_info(mlan_private *pmpriv,
707                                      t_u16 band,
708                                      const t_u8 country_code[COUNTRY_CODE_LEN],
709                                      t_u8 num_sub_band,
710                                      IEEEtypes_SubbandSet_t *sub_band_list)
711 {
712     mlan_adapter *pmadapter            = pmpriv->adapter;
713     wlan_802_11d_domain_reg_t *pdomain = &pmadapter->domain_reg;
714     mlan_status ret                    = MLAN_STATUS_SUCCESS;
715 
716     ENTER();
717 
718     (void)__memset(pmadapter, pdomain, 0, sizeof(wlan_802_11d_domain_reg_t));
719     (void)__memcpy(pmadapter, pdomain->country_code, country_code, COUNTRY_CODE_LEN);
720     pdomain->band           = band;
721     pdomain->no_of_sub_band = num_sub_band;
722     (void)__memcpy(pmadapter, pdomain->sub_band, sub_band_list,
723                    MIN(MRVDRV_MAX_SUBBAND_802_11D, num_sub_band) * sizeof(IEEEtypes_SubbandSet_t));
724 
725     LEAVE();
726     return ret;
727 }
728 
729 /********************************************************
730                 Global functions
731 ********************************************************/
732 
733 /**
734  *  @brief This function gets if priv is a station (STA)
735  *
736  *  @param pmpriv       Pointer to mlan_private structure
737  *
738  *  @return             MTRUE or MFALSE
739  */
wlan_is_station(mlan_private * pmpriv)740 t_bool wlan_is_station(mlan_private *pmpriv)
741 {
742     ENTER();
743     LEAVE();
744     return (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) ? MTRUE : MFALSE;
745 }
746 
747 /**
748  *  @brief This function gets if 11D is enabled
749  *
750  *  @param pmpriv       Pointer to mlan_private structure
751  *
752  *  @return             MTRUE or MFALSE
753  */
wlan_11d_support_is_enabled(mlan_private * pmpriv)754 t_bool wlan_11d_support_is_enabled(mlan_private *pmpriv)
755 {
756     ENTER();
757     LEAVE();
758     return (pmpriv->state_11d.user_enable_11d_support == ENABLE_11D) ? MTRUE : MFALSE;
759 }
760 
761 /**
762  *  @brief This function gets if 11D is enabled
763  *
764  *  @param pmpriv       Pointer to mlan_private structure
765  *
766  *  @return             MTRUE or MFALSE
767  */
wlan_11d_is_enabled(mlan_private * pmpriv)768 t_bool wlan_11d_is_enabled(mlan_private *pmpriv)
769 {
770     ENTER();
771     LEAVE();
772     return (pmpriv->state_11d.enable_11d == ENABLE_11D) ? MTRUE : MFALSE;
773 }
774 
775 static wlan_11d_fn_t wlan_11d_fn = {
776 #ifdef STA_SUPPORT
777     .wlan_11d_prepare_dnld_domain_info_cmd_p = wlan_11d_prepare_dnld_domain_info_cmd,
778     .wlan_11d_create_dnld_countryinfo_p      = wlan_11d_create_dnld_countryinfo,
779     .wlan_11d_parse_dnld_countryinfo_p       = wlan_11d_parse_dnld_countryinfo,
780 #endif
781 };
782 
783 static void *wlan_11d_enable_support = (wlan_11d_fn_t *)&wlan_11d_fn;
784 
785 /**
786  *  @brief This function sets 11D support
787  *
788  *  @param pmpriv       Pointer to mlan_private structure
789  *
790  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
791  */
wlan_enable_11d_support(mlan_private * pmpriv)792 t_u16 wlan_enable_11d_support(mlan_private *pmpriv)
793 {
794     ENTER();
795     LEAVE();
796 
797     pmpriv->state_11d.user_enable_11d_support = ENABLE_11D;
798 
799     pmpriv->support_11d = wlan_11d_enable_support;
800 
801     return (t_u16)MLAN_STATUS_SUCCESS;
802 }
803 
804 static wlan_11d_apis_t wlan_11d_apis = {
805     .wlan_11d_cfg_ioctl_p              = wlan_11d_cfg_ioctl,
806     .wlan_11d_cfg_domain_info_p        = wlan_11d_cfg_domain_info,
807     .wlan_cmd_802_11d_domain_info_p    = wlan_cmd_802_11d_domain_info,
808 #if UAP_SUPPORT
809     .wlan_11d_handle_uap_domain_info_p = wlan_11d_handle_uap_domain_info,
810 #endif
811 };
812 
813 static void *wlan_11d_support_apis = (wlan_11d_apis_t *)&wlan_11d_apis;
814 
815 /**
816  *  @brief This function enables 11D driver APIs
817  *
818  *  @param pmpriv       Pointer to mlan_private structure
819  *
820  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
821  */
wlan_11d_support_APIs(mlan_private * pmpriv)822 t_u16 wlan_11d_support_APIs(mlan_private *pmpriv)
823 {
824     ENTER();
825     LEAVE();
826 
827     pmpriv->support_11d_APIs = wlan_11d_support_apis;
828 
829     return (t_u16)MLAN_STATUS_SUCCESS;
830 }
831 
832 /**
833  *  @brief Initialize interface variable for 11D
834  *
835  *  @param pmpriv       Pointer to mlan_private structure
836  *
837  *  @return             N/A
838  */
wlan_11d_priv_init(mlan_private * pmpriv)839 t_void wlan_11d_priv_init(mlan_private *pmpriv)
840 {
841     wlan_802_11d_state_t *state = &pmpriv->state_11d;
842 
843     ENTER();
844 
845     /* Start in disabled mode */
846     state->enable_11d = DISABLE_11D;
847     if (!pmpriv->adapter->init_para.cfg_11d)
848     {
849         state->user_enable_11d = DEFAULT_11D_STATE;
850     }
851     else
852     {
853         state->user_enable_11d =
854             (pmpriv->adapter->init_para.cfg_11d == MLAN_INIT_PARA_DISABLED) ? DISABLE_11D : ENABLE_11D;
855     }
856 
857     LEAVE();
858     return;
859 }
860 
861 /**
862  *  @brief Initialize device variable for 11D
863  *
864  *  @param pmadapter    Pointer to mlan_adapter structure
865  *
866  *  @return             N/A
867  */
wlan_11d_init(mlan_adapter * pmadapter)868 t_void wlan_11d_init(mlan_adapter *pmadapter)
869 {
870     ENTER();
871 
872 #ifdef STA_SUPPORT
873     (void)__memset(pmadapter, &(pmadapter->parsed_region_chan), 0, sizeof(parsed_region_chan_11d_t));
874     (void)__memset(pmadapter, &(pmadapter->universal_channel), 0, sizeof(region_chan_t));
875 #endif
876     (void)__memset(pmadapter, &(pmadapter->domain_reg), 0, sizeof(wlan_802_11d_domain_reg_t));
877 
878     LEAVE();
879     return;
880 }
881 
882 /**
883  *  @brief This function implements command CMD_802_11D_DOMAIN_INFO
884  *
885  *  @param pmpriv       A pointer to mlan_private structure
886  *  @param pcmd         A pointer to HostCmd_DS_COMMAND structure of
887  *                        command buffer
888  *  @param cmd_action   Command action
889  *
890  *  @return             MLAN_STATUS_SUCCESS
891  */
wlan_cmd_802_11d_domain_info(mlan_private * pmpriv,HostCmd_DS_COMMAND * pcmd,t_u16 cmd_action)892 mlan_status wlan_cmd_802_11d_domain_info(mlan_private *pmpriv, HostCmd_DS_COMMAND *pcmd, t_u16 cmd_action)
893 {
894     mlan_adapter *pmadapter                      = pmpriv->adapter;
895     HostCmd_DS_802_11D_DOMAIN_INFO *pdomain_info = &pcmd->params.domain_info;
896     MrvlIEtypes_DomainParamSet_t *domain         = &pdomain_info->domain;
897     t_u8 no_of_sub_band                          = pmadapter->domain_reg.no_of_sub_band;
898 
899     ENTER();
900 
901     PRINTM(MINFO, "11D: number of sub-band=0x%x\n", no_of_sub_band);
902 
903     pcmd->command        = wlan_cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
904     pdomain_info->action = wlan_cpu_to_le16(cmd_action);
905     if (cmd_action == HostCmd_ACT_GEN_GET)
906     {
907         /* Dump domain info */
908         pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) + S_DS_GEN);
909         HEXDUMP("11D: 802_11D_DOMAIN_INFO", (t_u8 *)pcmd, wlan_le16_to_cpu(pcmd->size));
910         LEAVE();
911         return MLAN_STATUS_SUCCESS;
912     }
913 
914     /* Set domain info fields */
915     domain->header.type = wlan_cpu_to_le16(TLV_TYPE_DOMAIN);
916     (void)__memcpy(pmadapter, domain->country_code, pmadapter->domain_reg.country_code, sizeof(domain->country_code));
917 
918     domain->header.len = (t_u16)(((no_of_sub_band * sizeof(IEEEtypes_SubbandSet_t)) + sizeof(domain->country_code)));
919 
920     if (no_of_sub_band != 0U)
921     {
922         (void)__memcpy(pmadapter, domain->sub_band, pmadapter->domain_reg.sub_band,
923                        MIN(MRVDRV_MAX_SUBBAND_802_11D, no_of_sub_band) * sizeof(IEEEtypes_SubbandSet_t));
924 
925         pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) + domain->header.len + sizeof(MrvlIEtypesHeader_t) +
926                                       S_DS_GEN);
927     }
928     else
929     {
930         pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) + S_DS_GEN);
931     }
932     domain->header.len = wlan_cpu_to_le16(domain->header.len);
933 
934     HEXDUMP("11D: 802_11D_DOMAIN_INFO", (t_u8 *)pcmd, wlan_le16_to_cpu(pcmd->size));
935 
936     LEAVE();
937     return MLAN_STATUS_SUCCESS;
938 }
939 
940 #ifdef STA_SUPPORT
941 
942 /** Region code mapping */
943 typedef struct _region_code_t
944 {
945     /** Region */
946     t_u8 region[COUNTRY_CODE_LEN];
947 } region_code_t;
948 
949 /**
950  *  @brief This function check cfg80211 special region code.
951  *
952  *  @param region_string         Region string
953  *
954  *  @return     MTRUE/MFALSE
955  */
is_special_region_code(t_u8 * region_string)956 t_u8 is_special_region_code(t_u8 *region_string)
957 {
958     t_u8 i;
959     region_code_t special_region_code[] = {{"00 "}, {"99 "}, {"98 "}, {"97 "}};
960 
961     for (i = 0; i < COUNTRY_CODE_LEN && region_string[i]; i++)
962         region_string[i] = toupper(region_string[i]);
963 
964     for (i = 0; i < ARRAY_SIZE(special_region_code); i++)
965     {
966         if (!memcmp(region_string, special_region_code[i].region, COUNTRY_CODE_LEN))
967         {
968             PRINTM(MINFO, "special region code=%s\n", region_string);
969             return MTRUE;
970         }
971     }
972     return MFALSE;
973 }
974 
975 /**
976  *  @brief This function parses country information for region channel
977  *
978  *  @param pmadapter            Pointer to mlan_adapter structure
979  *  @param country_info         Country information
980  *  @param band                 Chan band
981  *  @param parsed_region_chan   Pointer to parsed_region_chan_11d_t
982  *
983  *  @return                     MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
984  */
wlan_11d_parse_domain_info(pmlan_adapter pmadapter,IEEEtypes_CountryInfoFullSet_t * country_info,t_u16 band,parsed_region_chan_11d_t * parsed_region_chan)985 mlan_status wlan_11d_parse_domain_info(pmlan_adapter pmadapter,
986                                        IEEEtypes_CountryInfoFullSet_t *country_info,
987                                        t_u16 band,
988                                        parsed_region_chan_11d_t *parsed_region_chan)
989 {
990     t_u8 no_of_sub_band, no_of_chan;
991     t_u8 last_chan, first_chan, cur_chan = 0;
992     t_u8 idx = 0;
993     t_u8 j, i;
994 
995     ENTER();
996 
997     /*
998      * Validation Rules:
999      *    1. Valid Region Code
1000      *    2. First Chan increment
1001      *    3. Channel range no overlap
1002      *    4. Channel is valid?
1003      *    5. Channel is supported by Region?
1004      *    6. Others
1005      */
1006 
1007     HEXDUMP("country_info", (t_u8 *)country_info, 30);
1008     /* Step 1: Check region_code */
1009     if (!(*(country_info->country_code)) || (country_info->len <= COUNTRY_CODE_LEN))
1010     {
1011         /* No region info or wrong region info: treat as no 11D info */
1012         LEAVE();
1013         return MLAN_STATUS_FAILURE;
1014     }
1015 
1016     no_of_sub_band = (t_u8)((country_info->len - COUNTRY_CODE_LEN) / sizeof(IEEEtypes_SubbandSet_t));
1017 
1018     last_chan = 0;
1019     for (j = 0; j < no_of_sub_band; j++)
1020     {
1021         if (country_info->sub_band[j].first_chan <= last_chan)
1022         {
1023             /* Step2&3: Check First Chan Num increment and no overlap */
1024             PRINTM(MINFO, "11D: Chan[%d>%d] Overlap\n", country_info->sub_band[j].first_chan, last_chan);
1025             continue;
1026         }
1027 
1028         first_chan = country_info->sub_band[j].first_chan;
1029         no_of_chan = country_info->sub_band[j].no_of_chan;
1030 
1031         i = 0;
1032         while (idx < MAX_NO_OF_CHAN && i < no_of_chan)
1033         {
1034             /* Step 4 : Channel is supported? */
1035             if (wlan_11d_get_chan(pmadapter, band, first_chan, i, &cur_chan) == MFALSE)
1036             {
1037                 /* Chan is not found in UN table */
1038                 PRINTM(MWARN, "11D: channel is not supported: %d\n", i);
1039                 break;
1040             }
1041 
1042             last_chan = cur_chan;
1043 
1044             /* Step 5: We don't need to check if cur_chan is supported by mrvl
1045                in region */
1046             parsed_region_chan->chan_pwr[idx].chan = cur_chan;
1047             parsed_region_chan->chan_pwr[idx].band = (t_u8)band;
1048             parsed_region_chan->chan_pwr[idx].pwr  = country_info->sub_band[j].max_tx_pwr;
1049             idx++;
1050             i++;
1051         }
1052 
1053         /* Step 6: Add other checking if any */
1054     }
1055 
1056     parsed_region_chan->no_of_chan = idx;
1057 
1058     PRINTM(MINFO, "11D: number of channel=0x%x\n", parsed_region_chan->no_of_chan);
1059     HEXDUMP("11D: parsed_region_chan", (t_u8 *)parsed_region_chan->chan_pwr, sizeof(chan_power_11d_t) * idx);
1060 
1061     LEAVE();
1062     return MLAN_STATUS_SUCCESS;
1063 }
1064 
1065 /**
1066  *  @brief This function converts channel to frequency
1067  *
1068  *  @param pmadapter    A pointer to mlan_adapter structure
1069  *  @param chan         Channel number
1070  *  @param band         Band
1071  *
1072  *  @return             Channel frequency
1073  */
wlan_11d_chan_2_freq(pmlan_adapter pmadapter,t_u8 chan,t_u16 band)1074 t_u32 wlan_11d_chan_2_freq(pmlan_adapter pmadapter, t_u8 chan, t_u16 band)
1075 {
1076     const chan_freq_power_t *cf;
1077     t_u16 cnt;
1078     t_u16 i;
1079     t_u32 freq = 0;
1080 
1081     ENTER();
1082 
1083 #if CONFIG_5GHz_SUPPORT
1084     /* Get channel-frequency-power trios */
1085     if ((band & (BAND_A | BAND_AN)) != 0)
1086     {
1087         cf  = channel_freq_power_UN_AJ;
1088         cnt = sizeof(channel_freq_power_UN_AJ) / sizeof(chan_freq_power_t);
1089     }
1090     else
1091     {
1092 #endif /* CONFIG_5GHz_SUPPORT */
1093         cf  = (const chan_freq_power_t *)channel_freq_power_UN_BG;
1094         cnt = sizeof(channel_freq_power_UN_BG) / sizeof(chan_freq_power_t);
1095 #if CONFIG_5GHz_SUPPORT
1096     }
1097 #endif /* CONFIG_5GHz_SUPPORT */
1098 
1099     /* Locate channel and return corresponding frequency */
1100     for (i = 0; i < cnt; i++)
1101     {
1102         if (chan == cf[i].channel)
1103         {
1104             freq = cf[i].freq;
1105         }
1106     }
1107 
1108     LEAVE();
1109     return freq;
1110 }
1111 
1112 /**
1113  *  @brief This function setups scan channels
1114  *
1115  *  @param pmpriv       Pointer to mlan_private structure
1116  *  @param band         Band
1117  *
1118  *  @return             MLAN_STATUS_SUCCESS
1119  */
wlan_11d_set_universaltable(mlan_private * pmpriv,t_u16 band)1120 mlan_status wlan_11d_set_universaltable(mlan_private *pmpriv, t_u16 band)
1121 {
1122     mlan_adapter *pmadapter = pmpriv->adapter;
1123     t_u16 size              = (t_u16)sizeof(chan_freq_power_t);
1124     t_u16 i                 = 0;
1125 
1126     ENTER();
1127 
1128     (void)__memset(pmadapter, pmadapter->universal_channel, 0, sizeof(pmadapter->universal_channel));
1129 
1130     if ((band & (BAND_B | BAND_G | BAND_GN)) != 0U)
1131     /* If band B, G or N */
1132     {
1133         /* Set channel-frequency-power */
1134         pmadapter->universal_channel[i].num_cfp = (t_u8)(sizeof(channel_freq_power_UN_BG) / size);
1135         PRINTM(MINFO, "11D: BG-band num_cfp=%d\n", pmadapter->universal_channel[i].num_cfp);
1136 
1137         pmadapter->universal_channel[i].pcfp  = (const chan_freq_power_t *)channel_freq_power_UN_BG;
1138         pmadapter->universal_channel[i].valid = MTRUE;
1139 
1140         /* Set region code */
1141         pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
1142 
1143         /* Set band */
1144         if ((band & BAND_GN) != 0U)
1145         {
1146             pmadapter->universal_channel[i].band = BAND_G;
1147         }
1148         else
1149         {
1150             pmadapter->universal_channel[i].band = (band & BAND_G) ? BAND_G : BAND_B;
1151         }
1152         i++;
1153     }
1154 
1155 #if CONFIG_5GHz_SUPPORT
1156 #if CONFIG_11AC
1157     if ((band & (BAND_A | BAND_AN | BAND_AAC)) != 0U)
1158     {
1159 #else
1160     if ((band & (BAND_A | BAND_AN)) != 0U)
1161     {
1162 #endif
1163         /* If band A */
1164 
1165         /* Set channel-frequency-power */
1166         pmadapter->universal_channel[i].num_cfp = (t_u8)(sizeof(channel_freq_power_UN_AJ) / size);
1167         PRINTM(MINFO, "11D: AJ-band num_cfp=%d\n", pmadapter->universal_channel[i].num_cfp);
1168 
1169         pmadapter->universal_channel[i].pcfp = channel_freq_power_UN_AJ;
1170 
1171         pmadapter->universal_channel[i].valid = MTRUE;
1172 
1173         /* Set region code */
1174         pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
1175 
1176         /* Set band */
1177         pmadapter->universal_channel[i].band = BAND_A;
1178     }
1179 #endif /* CONFIG_5GHz_SUPPORT */
1180 
1181     LEAVE();
1182     return MLAN_STATUS_SUCCESS;
1183 }
1184 
1185 /**
1186  *  @brief This function calculates the scan type for channels
1187  *
1188  *  @param pmadapter            A pointer to mlan_adapter structure
1189  *  @param band                 Band number
1190  *  @param chan                 Chan number
1191  *  @param parsed_region_chan   Pointer to parsed_region_chan_11d_t
1192  *
1193  *  @return                     PASSIVE if chan is unknown; ACTIVE if chan is known
1194  */
1195 mlan_scan_type wlan_11d_get_scan_type(mlan_private *pmpriv,
1196                                       t_u16 band,
1197                                       t_u8 chan,
1198                                       parsed_region_chan_11d_t *parsed_region_chan)
1199 {
1200     mlan_adapter *pmadapter = pmpriv->adapter;
1201 
1202     mlan_scan_type scan_type = MLAN_SCAN_TYPE_PASSIVE;
1203 
1204     ENTER();
1205 
1206     if (wlan_11d_channel_known(pmadapter, band, chan, parsed_region_chan) != 0U)
1207     {
1208         /* Channel found */
1209         PRINTM(MINFO, "11D: Channel found and doing Active Scan\n");
1210         scan_type = MLAN_SCAN_TYPE_ACTIVE;
1211     }
1212     else
1213     {
1214         PRINTM(MINFO, "11D: Channel not found and doing Passive Scan\n");
1215     }
1216 
1217     LEAVE();
1218     return scan_type;
1219 }
1220 
1221 /**
1222  *  @brief This function clears the parsed region table, if 11D is enabled
1223  *
1224  *  @param pmpriv       A pointer to mlan_private structure
1225  *
1226  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1227  */
1228 mlan_status wlan_11d_clear_parsedtable(mlan_private *pmpriv)
1229 {
1230     mlan_adapter *pmadapter = pmpriv->adapter;
1231     mlan_status ret         = MLAN_STATUS_SUCCESS;
1232 
1233     ENTER();
1234 
1235     if (wlan_11d_is_enabled(pmpriv))
1236     {
1237         (void)__memset(pmadapter, &(pmadapter->parsed_region_chan), 0, sizeof(parsed_region_chan_11d_t));
1238     }
1239     else
1240     {
1241         ret = MLAN_STATUS_FAILURE;
1242     }
1243 
1244     LEAVE();
1245     return ret;
1246 }
1247 
1248 /**
1249  *  @brief This function generates 11D info from user specified regioncode
1250  *         and download to FW
1251  *
1252  *  @param pmpriv       A pointer to mlan_private structure
1253  *  @param band         Band to create
1254  *
1255  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1256  */
1257 mlan_status wlan_11d_create_dnld_countryinfo(mlan_private *pmpriv, t_u16 band)
1258 {
1259     mlan_status ret         = MLAN_STATUS_SUCCESS;
1260     mlan_adapter *pmadapter = pmpriv->adapter;
1261     region_chan_t *region_chan;
1262     parsed_region_chan_11d_t parsed_region_chan;
1263     t_u8 j;
1264 
1265     ENTER();
1266 
1267     /* Only valid if 11D is enabled */
1268     if (wlan_11d_is_enabled(pmpriv))
1269     {
1270         PRINTM(MINFO, "11D: Band[%d]\n", band);
1271 
1272         /* Update parsed_region_chan; download domain info to FW */
1273 
1274         /* Find region channel */
1275         for (j = 0; j < MAX_REGION_CHANNEL_NUM; j++)
1276         {
1277             bool continue_loop = MFALSE;
1278             region_chan        = &pmadapter->region_channel[j];
1279 
1280             PRINTM(MINFO, "11D: [%d] region_chan->Band[%d]\n", j, region_chan->band);
1281 
1282             if (region_chan == MNULL || !region_chan->valid || region_chan->pcfp == MNULL)
1283             {
1284                 continue;
1285             }
1286             switch (region_chan->band)
1287             {
1288 #if CONFIG_5GHz_SUPPORT
1289                 case BAND_A:
1290                     switch (band)
1291                     {
1292                         case BAND_A:
1293                         case BAND_AN:
1294                         case BAND_A | BAND_AN:
1295 #if CONFIG_11AC
1296                         case BAND_A | BAND_AN | BAND_AAC:
1297 #endif
1298 #if CONFIG_11AX
1299                         case BAND_A | BAND_AN | BAND_AAC | BAND_AAX:
1300 #endif
1301                             break;
1302                         default:
1303                             continue_loop = MTRUE;
1304                             break;
1305                     }
1306                     break;
1307 #endif /* CONFIG_5GHz_SUPPORT */
1308                 case BAND_B:
1309                 case BAND_G:
1310                     switch (band)
1311                     {
1312                         case BAND_B:
1313                         case BAND_G:
1314                         case BAND_G | BAND_B:
1315                         case BAND_GN:
1316                         case BAND_G | BAND_GN:
1317                         case BAND_B | BAND_G | BAND_GN:
1318 #if CONFIG_11AC
1319                         case BAND_B | BAND_G | BAND_GN | BAND_GAC:
1320 #endif
1321 #if CONFIG_11AX
1322                         case BAND_B | BAND_G | BAND_GN | BAND_GAC | BAND_GAX:
1323 #endif
1324                             break;
1325                         default:
1326                             continue_loop = MTRUE;
1327                             break;
1328                     }
1329                     break;
1330                 default:
1331                     continue_loop = MTRUE;
1332                     break;
1333             }
1334 
1335             if (continue_loop == MTRUE)
1336             {
1337                 continue;
1338             }
1339             else
1340             {
1341                 break;
1342             }
1343         }
1344 
1345         /* Check if region channel found */
1346         if (j >= MAX_REGION_CHANNEL_NUM)
1347         {
1348             PRINTM(MERROR, "11D: region_chan not found. Band[%d]\n", band);
1349             LEAVE();
1350             return MLAN_STATUS_FAILURE;
1351         }
1352 
1353         /* Generate parsed region channel info from region channel */
1354         (void)__memset(pmadapter, &parsed_region_chan, 0, sizeof(parsed_region_chan_11d_t));
1355         wlan_11d_generate_parsed_region_chan(pmadapter, region_chan, &parsed_region_chan);
1356 
1357         /* Generate domain info from parsed region channel info */
1358         (void)wlan_11d_generate_domain_info(pmadapter, &parsed_region_chan);
1359 
1360         /* Set domain info */
1361         ret = wlan_11d_send_domain_info(pmpriv, MNULL, MFALSE);
1362         if (ret != MLAN_STATUS_SUCCESS)
1363         {
1364             PRINTM(MERROR, "11D: Error sending domain info to FW\n");
1365         }
1366     }
1367 
1368     LEAVE();
1369     return ret;
1370 }
1371 
1372 void wlan_filter_domain_channel(mlan_private *pmpriv,
1373                                 parsed_region_chan_11d_t *origin_region_chan,
1374                                 parsed_region_chan_11d_t *filtered_region_chan)
1375 {
1376     t_u32 i;
1377 
1378     for (i = 0; (i < origin_region_chan->no_of_chan) && (i < MAX_NO_OF_CHAN); i++)
1379     {
1380         if(MTRUE == wlan_check_channel_by_region_table(pmpriv, origin_region_chan->chan_pwr[i].chan))
1381         {
1382             (void)__memcpy(pmpriv->adapter, &filtered_region_chan->chan_pwr[filtered_region_chan->no_of_chan],
1383                            &origin_region_chan->chan_pwr[i], sizeof(chan_power_11d_t));
1384             filtered_region_chan->no_of_chan++;
1385         }
1386     }
1387 }
1388 /**
1389  *  @brief This function parses country info from AP and
1390  *           download country info to FW
1391  *
1392  *  @param pmpriv       A pointer to mlan_private structure
1393  *  @param pbss_desc     A pointer to BSS descriptor
1394  *
1395  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1396  */
1397 mlan_status wlan_11d_parse_dnld_countryinfo(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc)
1398 {
1399     mlan_status ret         = MLAN_STATUS_SUCCESS;
1400     mlan_adapter *pmadapter = pmpriv->adapter;
1401     parsed_region_chan_11d_t region_chan;
1402     parsed_region_chan_11d_t bssdesc_region_chan;
1403     parsed_region_chan_11d_t filtered_region_chan;
1404     t_u32 i, j;
1405 
1406     ENTER();
1407 
1408     /* Only valid if 11D is enabled */
1409     if (wlan_11d_is_enabled(pmpriv))
1410     {
1411         (void)__memset(pmadapter, &region_chan, 0, sizeof(parsed_region_chan_11d_t));
1412         (void)__memset(pmadapter, &bssdesc_region_chan, 0, sizeof(parsed_region_chan_11d_t));
1413         (void)__memset(pmadapter, &filtered_region_chan, 0, sizeof(parsed_region_chan_11d_t));
1414 
1415         (void)__memcpy(pmadapter, &region_chan, &pmadapter->parsed_region_chan, sizeof(parsed_region_chan_11d_t));
1416 
1417         if (pbss_desc != MNULL)
1418         {
1419             /** Country code */
1420             t_u8 country_code[COUNTRY_CODE_LEN];
1421             country_code[0] = pbss_desc->country_info.country_code[0];
1422             country_code[1] = pbss_desc->country_info.country_code[1];
1423             country_code[2] = ' ';
1424 
1425             if (is_special_region_code(country_code))
1426             {
1427                 PRINTM(MINFO, "Skip special region code in CountryIE");
1428                 LEAVE();
1429                 return MLAN_STATUS_SUCCESS;
1430             }
1431             /* Parse domain info if available */
1432             ret = wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info, pbss_desc->bss_band,
1433                                              &bssdesc_region_chan);
1434             if (ret == MLAN_STATUS_SUCCESS)
1435             {
1436                 /* Update the channel-power table */
1437                 for (i = 0; ((i < bssdesc_region_chan.no_of_chan) && (i < MAX_NO_OF_CHAN)); i++)
1438                 {
1439                     for (j = 0; ((j < region_chan.no_of_chan) && (j < MAX_NO_OF_CHAN)); j++)
1440                     {
1441                         /*
1442                          * Channel already exists, use minimum of existing
1443                          * tx power and tx_power received from
1444                          * country info of the current AP
1445                          */
1446                         if (region_chan.chan_pwr[i].chan == bssdesc_region_chan.chan_pwr[j].chan &&
1447                             region_chan.chan_pwr[i].band == bssdesc_region_chan.chan_pwr[j].band)
1448                         {
1449                             region_chan.chan_pwr[j].pwr =
1450                                 MIN(region_chan.chan_pwr[j].pwr, bssdesc_region_chan.chan_pwr[i].pwr);
1451                             break;
1452                         }
1453                     }
1454                 }
1455             }
1456         }
1457 
1458         /* Filter out channel list of current region code, then generate domain info */
1459         (void)wlan_filter_domain_channel(pmpriv, &region_chan, &filtered_region_chan);
1460 
1461         /* Generate domain info */
1462         (void)wlan_11d_generate_domain_info(pmadapter, &filtered_region_chan);
1463 
1464         /* Set domain info */
1465         ret = wlan_11d_send_domain_info(pmpriv, MNULL, MFALSE);
1466         if (ret != MLAN_STATUS_SUCCESS)
1467         {
1468             PRINTM(MERROR, "11D: Error sending domain info to FW\n");
1469         }
1470     }
1471 
1472     LEAVE();
1473     return ret;
1474 }
1475 
1476 /**
1477  *  @brief This function prepares domain info from scan table and
1478  *         downloads the domain info command to the FW.
1479  *
1480  *  @param pmpriv       A pointer to mlan_private structure
1481  *
1482  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1483  */
1484 mlan_status wlan_11d_prepare_dnld_domain_info_cmd(mlan_private *pmpriv)
1485 {
1486     mlan_status ret                               = MLAN_STATUS_SUCCESS;
1487     mlan_adapter *pmadapter                       = pmpriv->adapter;
1488     IEEEtypes_CountryInfoFullSet_t *pcountry_full = MNULL;
1489     t_u32 idx;
1490 
1491     ENTER();
1492 
1493     /* Only valid if 11D is enabled */
1494     if (wlan_11d_is_enabled(pmpriv) && pmadapter->num_in_scan_table != 0U)
1495     {
1496         for (idx = 0; idx < pmadapter->num_in_scan_table; idx++)
1497         {
1498             pcountry_full = &pmadapter->pscan_table[idx].country_info;
1499 
1500             ret = wlan_11d_update_chan_pwr_table(pmpriv, &pmadapter->pscan_table[idx]);
1501 
1502             if (*(pcountry_full->country_code) != 0U && (pcountry_full->len > COUNTRY_CODE_LEN))
1503             {
1504                 /* Country info found in the BSS Descriptor */
1505                 ret = wlan_11d_process_country_info(pmpriv, &pmadapter->pscan_table[idx]);
1506             }
1507         }
1508 
1509         /* Sort parsed_region_chan in ascending channel number */
1510         wlan_11d_sort_parsed_region_chan(&pmadapter->parsed_region_chan);
1511 
1512 #if 0
1513         /* Check if connected */
1514         if (pmpriv->media_connected == MTRUE)
1515         {
1516             ret = wlan_11d_parse_dnld_countryinfo(pmpriv, &pmpriv->curr_bss_params.bss_descriptor);
1517         }
1518         else
1519         {
1520             ret = wlan_11d_parse_dnld_countryinfo(pmpriv, MNULL);
1521         }
1522 #endif
1523     }
1524 
1525     LEAVE();
1526     return ret;
1527 }
1528 
1529 /**
1530  *  @brief This function sets up domain_reg and downloads CMD to FW
1531  *
1532  *  @param pmadapter    A pointer to mlan_adapter structure
1533  *  @param pioctl_req   Pointer to the IOCTL request buffer
1534  *
1535  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1536  */
1537 mlan_status wlan_11d_cfg_domain_info(IN pmlan_adapter pmadapter, IN mlan_ioctl_req *pioctl_req)
1538 {
1539     mlan_status ret                      = MLAN_STATUS_SUCCESS;
1540     mlan_private *pmpriv                 = pmadapter->priv[pioctl_req->bss_index];
1541     mlan_ds_11d_domain_info *domain_info = MNULL;
1542     mlan_ds_11d_cfg *cfg_11d             = MNULL;
1543     t_u8 region_code                     = 0;
1544 
1545     ENTER();
1546 
1547     cfg_11d     = (mlan_ds_11d_cfg *)(void *)pioctl_req->pbuf;
1548     domain_info = &cfg_11d->param.domain_info;
1549 
1550 #ifdef OTP_CHANINFO
1551     if ((pmadapter->otp_region != MNULL) && (pmadapter->otp_region->force_reg != 0U))
1552     {
1553         (void)PRINTF("ForceRegionRule is set in the on-chip OTP memory\r\n");
1554         ret = MLAN_STATUS_FAILURE;
1555         goto done;
1556     }
1557 #endif
1558 
1559     /* Update region code and table based on country code */
1560     if (wlan_11d_region_2_code(pmadapter, domain_info->country_code, &region_code) == MLAN_STATUS_SUCCESS)
1561     {
1562         pmadapter->region_code = region_code;
1563         ret                    = wlan_set_regiontable(pmpriv, region_code, pmadapter->fw_bands);
1564         if (ret != MLAN_STATUS_SUCCESS)
1565         {
1566             goto done;
1567         }
1568     }
1569 
1570     (void)wlan_11d_set_domain_info(pmpriv, domain_info->band, domain_info->country_code, domain_info->no_of_sub_band,
1571                                    (IEEEtypes_SubbandSet_t *)(void *)domain_info->sub_band);
1572     ret = wlan_11d_send_domain_info(pmpriv, pioctl_req, MFALSE);
1573 
1574     if (ret == MLAN_STATUS_SUCCESS)
1575     {
1576         ret = MLAN_STATUS_PENDING;
1577     }
1578 
1579 done:
1580     LEAVE();
1581     return ret;
1582 }
1583 #endif /* STA_SUPPORT */
1584 
1585 #if UAP_SUPPORT
1586 /**
1587  *  @brief This function handles domain info data from UAP interface.
1588  *         Checks conditions, sets up domain_reg, then downloads CMD.
1589  *
1590  *  @param pmpriv       A pointer to mlan_private structure
1591  *  @param band         Band interface is operating on
1592  *  @param domain_tlv   Pointer to domain_info tlv
1593  *  @param pioctl_buf   Pointer to the IOCTL buffer
1594  *
1595  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1596  */
1597 mlan_status wlan_11d_handle_uap_domain_info(mlan_private *pmpriv, t_u16 band, t_u8 *domain_tlv, t_void *pioctl_buf)
1598 {
1599     mlan_status ret         = MLAN_STATUS_SUCCESS;
1600     mlan_adapter *pmadapter = pmpriv->adapter;
1601     MrvlIEtypes_DomainParamSet_t *pdomain_tlv;
1602     t_u8 num_sub_band = 0;
1603     t_u8 region_code  = 0;
1604 
1605     ENTER();
1606 
1607     pdomain_tlv = (MrvlIEtypes_DomainParamSet_t *)(void *)domain_tlv;
1608 
1609     // update region code & table based on country string
1610     if (wlan_11d_region_2_code(pmadapter, pdomain_tlv->country_code, &region_code) == MLAN_STATUS_SUCCESS)
1611     {
1612         pmadapter->region_code = region_code;
1613         ret                    = wlan_set_regiontable(pmpriv, region_code, pmadapter->fw_bands);
1614     }
1615 
1616     num_sub_band = (t_u8)((pdomain_tlv->header.len - COUNTRY_CODE_LEN) / sizeof(IEEEtypes_SubbandSet_t));
1617 
1618     // TODO: don't just clobber pmadapter->domain_reg.
1619     // Add some checking or merging between STA & UAP domain_info
1620 
1621     (void)wlan_11d_set_domain_info(pmpriv, band, pdomain_tlv->country_code, num_sub_band, pdomain_tlv->sub_band);
1622 
1623     /* wmsdk: We do not yet have mechanism in wlan_prepare_cmd() to
1624        separate uao and sta commands. Hence we have to call uap cmd send
1625        function here manually */
1626     /* ret = wlan_11d_send_domain_info(pmpriv, pioctl_buf); */
1627     int rv = wifi_uap_prepare_and_send_cmd(pmpriv, HostCmd_CMD_802_11D_DOMAIN_INFO, HostCmd_ACT_GEN_SET, 0,
1628                                            (t_void *)pioctl_buf, MNULL, MLAN_BSS_TYPE_UAP, NULL);
1629     if (rv != 0)
1630     {
1631         wuap_w("Unable to send uap domain info");
1632         ret = MLAN_STATUS_FAILURE;
1633     }
1634 
1635     LEAVE();
1636     return ret;
1637 }
1638 #endif
1639