xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/mvl88w8977/mlan/mlan_11d.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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, &region_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 				       &region_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 		       &region_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, &region_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, &region_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, &region_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