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