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