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