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     .wlan_11d_handle_uap_domain_info_p = wlan_11d_handle_uap_domain_info,
809 };
810 
811 static void *wlan_11d_support_apis = (wlan_11d_apis_t *)&wlan_11d_apis;
812 
813 /**
814  *  @brief This function enables 11D driver APIs
815  *
816  *  @param pmpriv       Pointer to mlan_private structure
817  *
818  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
819  */
wlan_11d_support_APIs(mlan_private * pmpriv)820 t_u16 wlan_11d_support_APIs(mlan_private *pmpriv)
821 {
822     ENTER();
823     LEAVE();
824 
825     pmpriv->support_11d_APIs = wlan_11d_support_apis;
826 
827     return (t_u16)MLAN_STATUS_SUCCESS;
828 }
829 
830 /**
831  *  @brief Initialize interface variable for 11D
832  *
833  *  @param pmpriv       Pointer to mlan_private structure
834  *
835  *  @return             N/A
836  */
wlan_11d_priv_init(mlan_private * pmpriv)837 t_void wlan_11d_priv_init(mlan_private *pmpriv)
838 {
839     wlan_802_11d_state_t *state = &pmpriv->state_11d;
840 
841     ENTER();
842 
843     /* Start in disabled mode */
844     state->enable_11d = DISABLE_11D;
845     if (!pmpriv->adapter->init_para.cfg_11d)
846     {
847         state->user_enable_11d = DEFAULT_11D_STATE;
848     }
849     else
850     {
851         state->user_enable_11d =
852             (pmpriv->adapter->init_para.cfg_11d == MLAN_INIT_PARA_DISABLED) ? DISABLE_11D : ENABLE_11D;
853     }
854 
855     LEAVE();
856     return;
857 }
858 
859 /**
860  *  @brief Initialize device variable for 11D
861  *
862  *  @param pmadapter    Pointer to mlan_adapter structure
863  *
864  *  @return             N/A
865  */
wlan_11d_init(mlan_adapter * pmadapter)866 t_void wlan_11d_init(mlan_adapter *pmadapter)
867 {
868     ENTER();
869 
870 #ifdef STA_SUPPORT
871     (void)__memset(pmadapter, &(pmadapter->parsed_region_chan), 0, sizeof(parsed_region_chan_11d_t));
872     (void)__memset(pmadapter, &(pmadapter->universal_channel), 0, sizeof(region_chan_t));
873 #endif
874     (void)__memset(pmadapter, &(pmadapter->domain_reg), 0, sizeof(wlan_802_11d_domain_reg_t));
875 
876     LEAVE();
877     return;
878 }
879 
880 /**
881  *  @brief This function implements command CMD_802_11D_DOMAIN_INFO
882  *
883  *  @param pmpriv       A pointer to mlan_private structure
884  *  @param pcmd         A pointer to HostCmd_DS_COMMAND structure of
885  *                        command buffer
886  *  @param cmd_action   Command action
887  *
888  *  @return             MLAN_STATUS_SUCCESS
889  */
wlan_cmd_802_11d_domain_info(mlan_private * pmpriv,HostCmd_DS_COMMAND * pcmd,t_u16 cmd_action)890 mlan_status wlan_cmd_802_11d_domain_info(mlan_private *pmpriv, HostCmd_DS_COMMAND *pcmd, t_u16 cmd_action)
891 {
892     mlan_adapter *pmadapter                      = pmpriv->adapter;
893     HostCmd_DS_802_11D_DOMAIN_INFO *pdomain_info = &pcmd->params.domain_info;
894     MrvlIEtypes_DomainParamSet_t *domain         = &pdomain_info->domain;
895     t_u8 no_of_sub_band                          = pmadapter->domain_reg.no_of_sub_band;
896 
897     ENTER();
898 
899     PRINTM(MINFO, "11D: number of sub-band=0x%x\n", no_of_sub_band);
900 
901     pcmd->command        = wlan_cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
902     pdomain_info->action = wlan_cpu_to_le16(cmd_action);
903     if (cmd_action == HostCmd_ACT_GEN_GET)
904     {
905         /* Dump domain info */
906         pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) + S_DS_GEN);
907         HEXDUMP("11D: 802_11D_DOMAIN_INFO", (t_u8 *)pcmd, wlan_le16_to_cpu(pcmd->size));
908         LEAVE();
909         return MLAN_STATUS_SUCCESS;
910     }
911 
912     /* Set domain info fields */
913     domain->header.type = wlan_cpu_to_le16(TLV_TYPE_DOMAIN);
914     (void)__memcpy(pmadapter, domain->country_code, pmadapter->domain_reg.country_code, sizeof(domain->country_code));
915 
916     domain->header.len = (t_u16)(((no_of_sub_band * sizeof(IEEEtypes_SubbandSet_t)) + sizeof(domain->country_code)));
917 
918     if (no_of_sub_band != 0U)
919     {
920         (void)__memcpy(pmadapter, domain->sub_band, pmadapter->domain_reg.sub_band,
921                        MIN(MRVDRV_MAX_SUBBAND_802_11D, no_of_sub_band) * sizeof(IEEEtypes_SubbandSet_t));
922 
923         pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) + domain->header.len + sizeof(MrvlIEtypesHeader_t) +
924                                       S_DS_GEN);
925     }
926     else
927     {
928         pcmd->size = wlan_cpu_to_le16(sizeof(pdomain_info->action) + S_DS_GEN);
929     }
930     domain->header.len = wlan_cpu_to_le16(domain->header.len);
931 
932     HEXDUMP("11D: 802_11D_DOMAIN_INFO", (t_u8 *)pcmd, wlan_le16_to_cpu(pcmd->size));
933 
934     LEAVE();
935     return MLAN_STATUS_SUCCESS;
936 }
937 
938 #ifdef STA_SUPPORT
939 
940 /** Region code mapping */
941 typedef struct _region_code_t
942 {
943     /** Region */
944     t_u8 region[COUNTRY_CODE_LEN];
945 } region_code_t;
946 
947 /**
948  *  @brief This function check cfg80211 special region code.
949  *
950  *  @param region_string         Region string
951  *
952  *  @return     MTRUE/MFALSE
953  */
is_special_region_code(t_u8 * region_string)954 t_u8 is_special_region_code(t_u8 *region_string)
955 {
956     t_u8 i;
957     region_code_t special_region_code[] = {{"00 "}, {"99 "}, {"98 "}, {"97 "}};
958 
959     for (i = 0; i < COUNTRY_CODE_LEN && region_string[i]; i++)
960         region_string[i] = toupper(region_string[i]);
961 
962     for (i = 0; i < ARRAY_SIZE(special_region_code); i++)
963     {
964         if (!memcmp(region_string, special_region_code[i].region, COUNTRY_CODE_LEN))
965         {
966             PRINTM(MINFO, "special region code=%s\n", region_string);
967             return MTRUE;
968         }
969     }
970     return MFALSE;
971 }
972 
973 /**
974  *  @brief This function parses country information for region channel
975  *
976  *  @param pmadapter            Pointer to mlan_adapter structure
977  *  @param country_info         Country information
978  *  @param band                 Chan band
979  *  @param parsed_region_chan   Pointer to parsed_region_chan_11d_t
980  *
981  *  @return                     MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
982  */
wlan_11d_parse_domain_info(pmlan_adapter pmadapter,IEEEtypes_CountryInfoFullSet_t * country_info,t_u16 band,parsed_region_chan_11d_t * parsed_region_chan)983 mlan_status wlan_11d_parse_domain_info(pmlan_adapter pmadapter,
984                                        IEEEtypes_CountryInfoFullSet_t *country_info,
985                                        t_u16 band,
986                                        parsed_region_chan_11d_t *parsed_region_chan)
987 {
988     t_u8 no_of_sub_band, no_of_chan;
989     t_u8 last_chan, first_chan, cur_chan = 0;
990     t_u8 idx = 0;
991     t_u8 j, i;
992 
993     ENTER();
994 
995     /*
996      * Validation Rules:
997      *    1. Valid Region Code
998      *    2. First Chan increment
999      *    3. Channel range no overlap
1000      *    4. Channel is valid?
1001      *    5. Channel is supported by Region?
1002      *    6. Others
1003      */
1004 
1005     HEXDUMP("country_info", (t_u8 *)country_info, 30);
1006     /* Step 1: Check region_code */
1007     if (!(*(country_info->country_code)) || (country_info->len <= COUNTRY_CODE_LEN))
1008     {
1009         /* No region info or wrong region info: treat as no 11D info */
1010         LEAVE();
1011         return MLAN_STATUS_FAILURE;
1012     }
1013 
1014     no_of_sub_band = (t_u8)((country_info->len - COUNTRY_CODE_LEN) / sizeof(IEEEtypes_SubbandSet_t));
1015 
1016     last_chan = 0;
1017     for (j = 0; j < no_of_sub_band; j++)
1018     {
1019         if (country_info->sub_band[j].first_chan <= last_chan)
1020         {
1021             /* Step2&3: Check First Chan Num increment and no overlap */
1022             PRINTM(MINFO, "11D: Chan[%d>%d] Overlap\n", country_info->sub_band[j].first_chan, last_chan);
1023             continue;
1024         }
1025 
1026         first_chan = country_info->sub_band[j].first_chan;
1027         no_of_chan = country_info->sub_band[j].no_of_chan;
1028 
1029         i = 0;
1030         while (idx < MAX_NO_OF_CHAN && i < no_of_chan)
1031         {
1032             /* Step 4 : Channel is supported? */
1033             if (wlan_11d_get_chan(pmadapter, band, first_chan, i, &cur_chan) == MFALSE)
1034             {
1035                 /* Chan is not found in UN table */
1036                 PRINTM(MWARN, "11D: channel is not supported: %d\n", i);
1037                 break;
1038             }
1039 
1040             last_chan = cur_chan;
1041 
1042             /* Step 5: We don't need to check if cur_chan is supported by mrvl
1043                in region */
1044             parsed_region_chan->chan_pwr[idx].chan = cur_chan;
1045             parsed_region_chan->chan_pwr[idx].band = (t_u8)band;
1046             parsed_region_chan->chan_pwr[idx].pwr  = country_info->sub_band[j].max_tx_pwr;
1047             idx++;
1048             i++;
1049         }
1050 
1051         /* Step 6: Add other checking if any */
1052     }
1053 
1054     parsed_region_chan->no_of_chan = idx;
1055 
1056     PRINTM(MINFO, "11D: number of channel=0x%x\n", parsed_region_chan->no_of_chan);
1057     HEXDUMP("11D: parsed_region_chan", (t_u8 *)parsed_region_chan->chan_pwr, sizeof(chan_power_11d_t) * idx);
1058 
1059     LEAVE();
1060     return MLAN_STATUS_SUCCESS;
1061 }
1062 
1063 /**
1064  *  @brief This function converts channel to frequency
1065  *
1066  *  @param pmadapter    A pointer to mlan_adapter structure
1067  *  @param chan         Channel number
1068  *  @param band         Band
1069  *
1070  *  @return             Channel frequency
1071  */
wlan_11d_chan_2_freq(pmlan_adapter pmadapter,t_u8 chan,t_u16 band)1072 t_u32 wlan_11d_chan_2_freq(pmlan_adapter pmadapter, t_u8 chan, t_u16 band)
1073 {
1074     const chan_freq_power_t *cf;
1075     t_u16 cnt;
1076     t_u16 i;
1077     t_u32 freq = 0;
1078 
1079     ENTER();
1080 
1081 #if CONFIG_5GHz_SUPPORT
1082     /* Get channel-frequency-power trios */
1083     if ((band & (BAND_A | BAND_AN)) != 0)
1084     {
1085         cf  = channel_freq_power_UN_AJ;
1086         cnt = sizeof(channel_freq_power_UN_AJ) / sizeof(chan_freq_power_t);
1087     }
1088     else
1089     {
1090 #endif /* CONFIG_5GHz_SUPPORT */
1091         cf  = (const chan_freq_power_t *)channel_freq_power_UN_BG;
1092         cnt = sizeof(channel_freq_power_UN_BG) / sizeof(chan_freq_power_t);
1093 #if CONFIG_5GHz_SUPPORT
1094     }
1095 #endif /* CONFIG_5GHz_SUPPORT */
1096 
1097     /* Locate channel and return corresponding frequency */
1098     for (i = 0; i < cnt; i++)
1099     {
1100         if (chan == cf[i].channel)
1101         {
1102             freq = cf[i].freq;
1103         }
1104     }
1105 
1106     LEAVE();
1107     return freq;
1108 }
1109 
1110 /**
1111  *  @brief This function setups scan channels
1112  *
1113  *  @param pmpriv       Pointer to mlan_private structure
1114  *  @param band         Band
1115  *
1116  *  @return             MLAN_STATUS_SUCCESS
1117  */
wlan_11d_set_universaltable(mlan_private * pmpriv,t_u16 band)1118 mlan_status wlan_11d_set_universaltable(mlan_private *pmpriv, t_u16 band)
1119 {
1120     mlan_adapter *pmadapter = pmpriv->adapter;
1121     t_u16 size              = (t_u16)sizeof(chan_freq_power_t);
1122     t_u16 i                 = 0;
1123 
1124     ENTER();
1125 
1126     (void)__memset(pmadapter, pmadapter->universal_channel, 0, sizeof(pmadapter->universal_channel));
1127 
1128     if ((band & (BAND_B | BAND_G | BAND_GN)) != 0U)
1129     /* If band B, G or N */
1130     {
1131         /* Set channel-frequency-power */
1132         pmadapter->universal_channel[i].num_cfp = (t_u8)(sizeof(channel_freq_power_UN_BG) / size);
1133         PRINTM(MINFO, "11D: BG-band num_cfp=%d\n", pmadapter->universal_channel[i].num_cfp);
1134 
1135         pmadapter->universal_channel[i].pcfp  = (const chan_freq_power_t *)channel_freq_power_UN_BG;
1136         pmadapter->universal_channel[i].valid = MTRUE;
1137 
1138         /* Set region code */
1139         pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
1140 
1141         /* Set band */
1142         if ((band & BAND_GN) != 0U)
1143         {
1144             pmadapter->universal_channel[i].band = BAND_G;
1145         }
1146         else
1147         {
1148             pmadapter->universal_channel[i].band = (band & BAND_G) ? BAND_G : BAND_B;
1149         }
1150         i++;
1151     }
1152 
1153 #if CONFIG_5GHz_SUPPORT
1154 #if CONFIG_11AC
1155     if ((band & (BAND_A | BAND_AN | BAND_AAC)) != 0U)
1156     {
1157 #else
1158     if ((band & (BAND_A | BAND_AN)) != 0U)
1159     {
1160 #endif
1161         /* If band A */
1162 
1163         /* Set channel-frequency-power */
1164         pmadapter->universal_channel[i].num_cfp = (t_u8)(sizeof(channel_freq_power_UN_AJ) / size);
1165         PRINTM(MINFO, "11D: AJ-band num_cfp=%d\n", pmadapter->universal_channel[i].num_cfp);
1166 
1167         pmadapter->universal_channel[i].pcfp = channel_freq_power_UN_AJ;
1168 
1169         pmadapter->universal_channel[i].valid = MTRUE;
1170 
1171         /* Set region code */
1172         pmadapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
1173 
1174         /* Set band */
1175         pmadapter->universal_channel[i].band = BAND_A;
1176     }
1177 #endif /* CONFIG_5GHz_SUPPORT */
1178 
1179     LEAVE();
1180     return MLAN_STATUS_SUCCESS;
1181 }
1182 
1183 /**
1184  *  @brief This function calculates the scan type for channels
1185  *
1186  *  @param pmadapter            A pointer to mlan_adapter structure
1187  *  @param band                 Band number
1188  *  @param chan                 Chan number
1189  *  @param parsed_region_chan   Pointer to parsed_region_chan_11d_t
1190  *
1191  *  @return                     PASSIVE if chan is unknown; ACTIVE if chan is known
1192  */
1193 mlan_scan_type wlan_11d_get_scan_type(mlan_private *pmpriv,
1194                                       t_u16 band,
1195                                       t_u8 chan,
1196                                       parsed_region_chan_11d_t *parsed_region_chan)
1197 {
1198     mlan_adapter *pmadapter = pmpriv->adapter;
1199 
1200     mlan_scan_type scan_type = MLAN_SCAN_TYPE_PASSIVE;
1201 
1202     ENTER();
1203 
1204     if (wlan_11d_channel_known(pmadapter, band, chan, parsed_region_chan) != 0U)
1205     {
1206         /* Channel found */
1207         PRINTM(MINFO, "11D: Channel found and doing Active Scan\n");
1208         scan_type = MLAN_SCAN_TYPE_ACTIVE;
1209     }
1210     else
1211     {
1212         PRINTM(MINFO, "11D: Channel not found and doing Passive Scan\n");
1213     }
1214 
1215     LEAVE();
1216     return scan_type;
1217 }
1218 
1219 /**
1220  *  @brief This function clears the parsed region table, if 11D is enabled
1221  *
1222  *  @param pmpriv       A pointer to mlan_private structure
1223  *
1224  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1225  */
1226 mlan_status wlan_11d_clear_parsedtable(mlan_private *pmpriv)
1227 {
1228     mlan_adapter *pmadapter = pmpriv->adapter;
1229     mlan_status ret         = MLAN_STATUS_SUCCESS;
1230 
1231     ENTER();
1232 
1233     if (wlan_11d_is_enabled(pmpriv))
1234     {
1235         (void)__memset(pmadapter, &(pmadapter->parsed_region_chan), 0, sizeof(parsed_region_chan_11d_t));
1236     }
1237     else
1238     {
1239         ret = MLAN_STATUS_FAILURE;
1240     }
1241 
1242     LEAVE();
1243     return ret;
1244 }
1245 
1246 /**
1247  *  @brief This function generates 11D info from user specified regioncode
1248  *         and download to FW
1249  *
1250  *  @param pmpriv       A pointer to mlan_private structure
1251  *  @param band         Band to create
1252  *
1253  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1254  */
1255 mlan_status wlan_11d_create_dnld_countryinfo(mlan_private *pmpriv, t_u16 band)
1256 {
1257     mlan_status ret         = MLAN_STATUS_SUCCESS;
1258     mlan_adapter *pmadapter = pmpriv->adapter;
1259     region_chan_t *region_chan;
1260     parsed_region_chan_11d_t parsed_region_chan;
1261     t_u8 j;
1262 
1263     ENTER();
1264 
1265     /* Only valid if 11D is enabled */
1266     if (wlan_11d_is_enabled(pmpriv))
1267     {
1268         PRINTM(MINFO, "11D: Band[%d]\n", band);
1269 
1270         /* Update parsed_region_chan; download domain info to FW */
1271 
1272         /* Find region channel */
1273         for (j = 0; j < MAX_REGION_CHANNEL_NUM; j++)
1274         {
1275             bool continue_loop = MFALSE;
1276             region_chan        = &pmadapter->region_channel[j];
1277 
1278             PRINTM(MINFO, "11D: [%d] region_chan->Band[%d]\n", j, region_chan->band);
1279 
1280             if (region_chan == MNULL || !region_chan->valid || region_chan->pcfp == MNULL)
1281             {
1282                 continue;
1283             }
1284             switch (region_chan->band)
1285             {
1286 #if CONFIG_5GHz_SUPPORT
1287                 case BAND_A:
1288                     switch (band)
1289                     {
1290                         case BAND_A:
1291                         case BAND_AN:
1292                         case BAND_A | BAND_AN:
1293 #if CONFIG_11AC
1294                         case BAND_A | BAND_AN | BAND_AAC:
1295 #endif
1296 #if CONFIG_11AX
1297                         case BAND_A | BAND_AN | BAND_AAC | BAND_AAX:
1298 #endif
1299                             break;
1300                         default:
1301                             continue_loop = MTRUE;
1302                             break;
1303                     }
1304                     break;
1305 #endif /* CONFIG_5GHz_SUPPORT */
1306                 case BAND_B:
1307                 case BAND_G:
1308                     switch (band)
1309                     {
1310                         case BAND_B:
1311                         case BAND_G:
1312                         case BAND_G | BAND_B:
1313                         case BAND_GN:
1314                         case BAND_G | BAND_GN:
1315                         case BAND_B | BAND_G | BAND_GN:
1316 #if CONFIG_11AC
1317                         case BAND_B | BAND_G | BAND_GN | BAND_GAC:
1318 #endif
1319 #if CONFIG_11AX
1320                         case BAND_B | BAND_G | BAND_GN | BAND_GAC | BAND_GAX:
1321 #endif
1322                             break;
1323                         default:
1324                             continue_loop = MTRUE;
1325                             break;
1326                     }
1327                     break;
1328                 default:
1329                     continue_loop = MTRUE;
1330                     break;
1331             }
1332 
1333             if (continue_loop == MTRUE)
1334             {
1335                 continue;
1336             }
1337             else
1338             {
1339                 break;
1340             }
1341         }
1342 
1343         /* Check if region channel found */
1344         if (j >= MAX_REGION_CHANNEL_NUM)
1345         {
1346             PRINTM(MERROR, "11D: region_chan not found. Band[%d]\n", band);
1347             LEAVE();
1348             return MLAN_STATUS_FAILURE;
1349         }
1350 
1351         /* Generate parsed region channel info from region channel */
1352         (void)__memset(pmadapter, &parsed_region_chan, 0, sizeof(parsed_region_chan_11d_t));
1353         wlan_11d_generate_parsed_region_chan(pmadapter, region_chan, &parsed_region_chan);
1354 
1355         /* Generate domain info from parsed region channel info */
1356         (void)wlan_11d_generate_domain_info(pmadapter, &parsed_region_chan);
1357 
1358         /* Set domain info */
1359         ret = wlan_11d_send_domain_info(pmpriv, MNULL, MFALSE);
1360         if (ret != MLAN_STATUS_SUCCESS)
1361         {
1362             PRINTM(MERROR, "11D: Error sending domain info to FW\n");
1363         }
1364     }
1365 
1366     LEAVE();
1367     return ret;
1368 }
1369 
1370 void wlan_filter_domain_channel(mlan_private *pmpriv,
1371                                 parsed_region_chan_11d_t *origin_region_chan,
1372                                 parsed_region_chan_11d_t *filtered_region_chan)
1373 {
1374     t_u32 i;
1375 
1376     for (i = 0; (i < origin_region_chan->no_of_chan) && (i < MAX_NO_OF_CHAN); i++)
1377     {
1378         if(MTRUE == wlan_check_channel_by_region_table(pmpriv, origin_region_chan->chan_pwr[i].chan))
1379         {
1380             (void)__memcpy(pmpriv->adapter, &filtered_region_chan->chan_pwr[filtered_region_chan->no_of_chan],
1381                            &origin_region_chan->chan_pwr[i], sizeof(chan_power_11d_t));
1382             filtered_region_chan->no_of_chan++;
1383         }
1384     }
1385 }
1386 /**
1387  *  @brief This function parses country info from AP and
1388  *           download country info to FW
1389  *
1390  *  @param pmpriv       A pointer to mlan_private structure
1391  *  @param pbss_desc     A pointer to BSS descriptor
1392  *
1393  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1394  */
1395 mlan_status wlan_11d_parse_dnld_countryinfo(mlan_private *pmpriv, BSSDescriptor_t *pbss_desc)
1396 {
1397     mlan_status ret         = MLAN_STATUS_SUCCESS;
1398     mlan_adapter *pmadapter = pmpriv->adapter;
1399     parsed_region_chan_11d_t region_chan;
1400     parsed_region_chan_11d_t bssdesc_region_chan;
1401     parsed_region_chan_11d_t filtered_region_chan;
1402     t_u32 i, j;
1403 
1404     ENTER();
1405 
1406     /* Only valid if 11D is enabled */
1407     if (wlan_11d_is_enabled(pmpriv))
1408     {
1409         (void)__memset(pmadapter, &region_chan, 0, sizeof(parsed_region_chan_11d_t));
1410         (void)__memset(pmadapter, &bssdesc_region_chan, 0, sizeof(parsed_region_chan_11d_t));
1411         (void)__memset(pmadapter, &filtered_region_chan, 0, sizeof(parsed_region_chan_11d_t));
1412 
1413         (void)__memcpy(pmadapter, &region_chan, &pmadapter->parsed_region_chan, sizeof(parsed_region_chan_11d_t));
1414 
1415         if (pbss_desc != MNULL)
1416         {
1417             /** Country code */
1418             t_u8 country_code[COUNTRY_CODE_LEN];
1419             country_code[0] = pbss_desc->country_info.country_code[0];
1420             country_code[1] = pbss_desc->country_info.country_code[1];
1421             country_code[2] = ' ';
1422 
1423             if (is_special_region_code(country_code))
1424             {
1425                 PRINTM(MINFO, "Skip special region code in CountryIE");
1426                 LEAVE();
1427                 return MLAN_STATUS_SUCCESS;
1428             }
1429             /* Parse domain info if available */
1430             ret = wlan_11d_parse_domain_info(pmadapter, &pbss_desc->country_info, pbss_desc->bss_band,
1431                                              &bssdesc_region_chan);
1432             if (ret == MLAN_STATUS_SUCCESS)
1433             {
1434                 /* Update the channel-power table */
1435                 for (i = 0; ((i < bssdesc_region_chan.no_of_chan) && (i < MAX_NO_OF_CHAN)); i++)
1436                 {
1437                     for (j = 0; ((j < region_chan.no_of_chan) && (j < MAX_NO_OF_CHAN)); j++)
1438                     {
1439                         /*
1440                          * Channel already exists, use minimum of existing
1441                          * tx power and tx_power received from
1442                          * country info of the current AP
1443                          */
1444                         if (region_chan.chan_pwr[i].chan == bssdesc_region_chan.chan_pwr[j].chan &&
1445                             region_chan.chan_pwr[i].band == bssdesc_region_chan.chan_pwr[j].band)
1446                         {
1447                             region_chan.chan_pwr[j].pwr =
1448                                 MIN(region_chan.chan_pwr[j].pwr, bssdesc_region_chan.chan_pwr[i].pwr);
1449                             break;
1450                         }
1451                     }
1452                 }
1453             }
1454         }
1455 
1456         /* Filter out channel list of current region code, then generate domain info */
1457         (void)wlan_filter_domain_channel(pmpriv, &region_chan, &filtered_region_chan);
1458 
1459         /* Generate domain info */
1460         (void)wlan_11d_generate_domain_info(pmadapter, &filtered_region_chan);
1461 
1462         /* Set domain info */
1463         ret = wlan_11d_send_domain_info(pmpriv, MNULL, MFALSE);
1464         if (ret != MLAN_STATUS_SUCCESS)
1465         {
1466             PRINTM(MERROR, "11D: Error sending domain info to FW\n");
1467         }
1468     }
1469 
1470     LEAVE();
1471     return ret;
1472 }
1473 
1474 /**
1475  *  @brief This function prepares domain info from scan table and
1476  *         downloads the domain info command to the FW.
1477  *
1478  *  @param pmpriv       A pointer to mlan_private structure
1479  *
1480  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1481  */
1482 mlan_status wlan_11d_prepare_dnld_domain_info_cmd(mlan_private *pmpriv)
1483 {
1484     mlan_status ret                               = MLAN_STATUS_SUCCESS;
1485     mlan_adapter *pmadapter                       = pmpriv->adapter;
1486     IEEEtypes_CountryInfoFullSet_t *pcountry_full = MNULL;
1487     t_u32 idx;
1488 
1489     ENTER();
1490 
1491     /* Only valid if 11D is enabled */
1492     if (wlan_11d_is_enabled(pmpriv) && pmadapter->num_in_scan_table != 0U)
1493     {
1494         for (idx = 0; idx < pmadapter->num_in_scan_table; idx++)
1495         {
1496             pcountry_full = &pmadapter->pscan_table[idx].country_info;
1497 
1498             ret = wlan_11d_update_chan_pwr_table(pmpriv, &pmadapter->pscan_table[idx]);
1499 
1500             if (*(pcountry_full->country_code) != 0U && (pcountry_full->len > COUNTRY_CODE_LEN))
1501             {
1502                 /* Country info found in the BSS Descriptor */
1503                 ret = wlan_11d_process_country_info(pmpriv, &pmadapter->pscan_table[idx]);
1504             }
1505         }
1506 
1507         /* Sort parsed_region_chan in ascending channel number */
1508         wlan_11d_sort_parsed_region_chan(&pmadapter->parsed_region_chan);
1509 
1510 #if 0
1511         /* Check if connected */
1512         if (pmpriv->media_connected == MTRUE)
1513         {
1514             ret = wlan_11d_parse_dnld_countryinfo(pmpriv, &pmpriv->curr_bss_params.bss_descriptor);
1515         }
1516         else
1517         {
1518             ret = wlan_11d_parse_dnld_countryinfo(pmpriv, MNULL);
1519         }
1520 #endif
1521     }
1522 
1523     LEAVE();
1524     return ret;
1525 }
1526 
1527 /**
1528  *  @brief This function sets up domain_reg and downloads CMD to FW
1529  *
1530  *  @param pmadapter    A pointer to mlan_adapter structure
1531  *  @param pioctl_req   Pointer to the IOCTL request buffer
1532  *
1533  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1534  */
1535 mlan_status wlan_11d_cfg_domain_info(IN pmlan_adapter pmadapter, IN mlan_ioctl_req *pioctl_req)
1536 {
1537     mlan_status ret                      = MLAN_STATUS_SUCCESS;
1538     mlan_private *pmpriv                 = pmadapter->priv[pioctl_req->bss_index];
1539     mlan_ds_11d_domain_info *domain_info = MNULL;
1540     mlan_ds_11d_cfg *cfg_11d             = MNULL;
1541     t_u8 region_code                     = 0;
1542 
1543     ENTER();
1544 
1545     cfg_11d     = (mlan_ds_11d_cfg *)(void *)pioctl_req->pbuf;
1546     domain_info = &cfg_11d->param.domain_info;
1547 
1548 #ifdef OTP_CHANINFO
1549     if ((pmadapter->otp_region != MNULL) && (pmadapter->otp_region->force_reg != 0U))
1550     {
1551         (void)PRINTF("ForceRegionRule is set in the on-chip OTP memory\r\n");
1552         ret = MLAN_STATUS_FAILURE;
1553         goto done;
1554     }
1555 #endif
1556 
1557     /* Update region code and table based on country code */
1558     if (wlan_11d_region_2_code(pmadapter, domain_info->country_code, &region_code) == MLAN_STATUS_SUCCESS)
1559     {
1560         pmadapter->region_code = region_code;
1561         ret                    = wlan_set_regiontable(pmpriv, region_code, pmadapter->fw_bands);
1562         if (ret != MLAN_STATUS_SUCCESS)
1563         {
1564             goto done;
1565         }
1566     }
1567 
1568     (void)wlan_11d_set_domain_info(pmpriv, domain_info->band, domain_info->country_code, domain_info->no_of_sub_band,
1569                                    (IEEEtypes_SubbandSet_t *)(void *)domain_info->sub_band);
1570     ret = wlan_11d_send_domain_info(pmpriv, pioctl_req, MFALSE);
1571 
1572     if (ret == MLAN_STATUS_SUCCESS)
1573     {
1574         ret = MLAN_STATUS_PENDING;
1575     }
1576 
1577 done:
1578     LEAVE();
1579     return ret;
1580 }
1581 #endif /* STA_SUPPORT */
1582 
1583 #if defined(UAP_SUPPORT)
1584 /**
1585  *  @brief This function handles domain info data from UAP interface.
1586  *         Checks conditions, sets up domain_reg, then downloads CMD.
1587  *
1588  *  @param pmpriv       A pointer to mlan_private structure
1589  *  @param band         Band interface is operating on
1590  *  @param domain_tlv   Pointer to domain_info tlv
1591  *  @param pioctl_buf   Pointer to the IOCTL buffer
1592  *
1593  *  @return             MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1594  */
1595 mlan_status wlan_11d_handle_uap_domain_info(mlan_private *pmpriv, t_u16 band, t_u8 *domain_tlv, t_void *pioctl_buf)
1596 {
1597     mlan_status ret         = MLAN_STATUS_SUCCESS;
1598     mlan_adapter *pmadapter = pmpriv->adapter;
1599     MrvlIEtypes_DomainParamSet_t *pdomain_tlv;
1600     t_u8 num_sub_band = 0;
1601     t_u8 region_code  = 0;
1602 
1603     ENTER();
1604 
1605     pdomain_tlv = (MrvlIEtypes_DomainParamSet_t *)(void *)domain_tlv;
1606 
1607     // update region code & table based on country string
1608     if (wlan_11d_region_2_code(pmadapter, pdomain_tlv->country_code, &region_code) == MLAN_STATUS_SUCCESS)
1609     {
1610         pmadapter->region_code = region_code;
1611         ret                    = wlan_set_regiontable(pmpriv, region_code, pmadapter->fw_bands);
1612     }
1613 
1614     num_sub_band = (t_u8)((pdomain_tlv->header.len - COUNTRY_CODE_LEN) / sizeof(IEEEtypes_SubbandSet_t));
1615 
1616     // TODO: don't just clobber pmadapter->domain_reg.
1617     // Add some checking or merging between STA & UAP domain_info
1618 
1619     (void)wlan_11d_set_domain_info(pmpriv, band, pdomain_tlv->country_code, num_sub_band, pdomain_tlv->sub_band);
1620 
1621     /* wmsdk: We do not yet have mechanism in wlan_prepare_cmd() to
1622        separate uao and sta commands. Hence we have to call uap cmd send
1623        function here manually */
1624     /* ret = wlan_11d_send_domain_info(pmpriv, pioctl_buf); */
1625     int rv = wifi_uap_prepare_and_send_cmd(pmpriv, HostCmd_CMD_802_11D_DOMAIN_INFO, HostCmd_ACT_GEN_SET, 0,
1626                                            (t_void *)pioctl_buf, MNULL, MLAN_BSS_TYPE_UAP, NULL);
1627     if (rv != 0)
1628     {
1629         wuap_w("Unable to send uap domain info");
1630         ret = MLAN_STATUS_FAILURE;
1631     }
1632 
1633     LEAVE();
1634     return ret;
1635 }
1636 #endif
1637