xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/mvl88w8977/mlan/mlan_11h.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /** @file mlan_11h.c
2  *
3  *  @brief This file contains functions for 802.11H.
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 /*************************************************************
23 Change Log:
24     03/26/2009: 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_ioctl.h"
33 #include "mlan_11h.h"
34 #include "mlan_11n.h"
35 #ifdef UAP_SUPPORT
36 #include "mlan_uap.h"
37 #endif
38 
39 /********************************************************
40 			Local Variables
41 ********************************************************/
42 
43 /** Default IBSS DFS recovery interval (in TBTTs); used for adhoc start */
44 #define WLAN_11H_DEFAULT_DFS_RECOVERY_INTERVAL   100
45 
46 /** Default 11h power constraint used to offset the maximum transmit power */
47 #define WLAN_11H_TPC_POWERCONSTRAINT  0
48 
49 /** 11h TPC Power capability minimum setting, sent in TPC_INFO command to fw */
50 #define WLAN_11H_TPC_POWERCAPABILITY_MIN     5
51 
52 /** 11h TPC Power capability maximum setting, sent in TPC_INFO command to fw */
53 #define WLAN_11H_TPC_POWERCAPABILITY_MAX     20
54 
55 /** Regulatory requirement for the duration of a channel availability check */
56 #define WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION    60000	/* in ms */
57 
58 /** Starting Frequency for 11A band */
59 #define START_FREQ_11A_BAND     5000	/* in MHz */
60 
61 /** DFS Channel Move Time */
62 #define DFS_CHAN_MOVE_TIME  10	/* in sec */
63 
64 /** Regulatory requirement for the duration of a non-occupancy period */
65 #define WLAN_11H_NON_OCCUPANCY_PERIOD    1800	/* in sec (30mins) */
66 
67 /** Maximum allowable age (seconds) on DFS report data */
68 #define MAX_DFS_REPORT_USABLE_AGE_SEC  (120)	/* 2 minutes */
69 
70 /** Minimum delay for CHAN_SW IE to broadcast by FW */
71 #define MIN_RDH_CHAN_SW_IE_PERIOD_MSEC  (400)	/* 4 beacons @ 100ms */
72 
73 /** Maximum delay for CHAN_SW IE to broadcast by FW */
74 #define MAX_RDH_CHAN_SW_IE_PERIOD_MSEC  (3000)	/* 5 beacons @ 600ms */
75 
76 /** Maximum retries on selecting new random channel */
77 #define MAX_RANDOM_CHANNEL_RETRIES  (20)
78 
79 /** Maximum retries on selecting new random non-dfs channel */
80 #define MAX_SWITCH_CHANNEL_RETRIES  (30)
81 
82 /** Value for undetermined priv_curr_idx on first entry to new RDH stage */
83 #define RDH_STAGE_FIRST_ENTRY_PRIV_IDX  (0xff)
84 
85 /** Region codes 0x10, 0x20:  channels 1 thru 11 supported */
86 static const
87 IEEEtypes_SupportChan_Subband_t wlan_11h_2_4G_region_FCC = { 1, 11 };
88 
89 /** Region codes 0x30, 0x32, 0x41, 0x50:  channels 1 thru 13 supported */
90 static const
91 IEEEtypes_SupportChan_Subband_t wlan_11h_2_4G_region_EU = { 1, 13 };
92 
93 /** Region code 0x40:  only channel 14 supported */
94 static const
95 IEEEtypes_SupportChan_Subband_t wlan_11h_2_4G_region_JPN40 = { 14, 1 };
96 
97 /** JPN sub-band config : Start Channel = 8, NumChans = 3 */
98 static const
99 IEEEtypes_SupportChan_Subband_t wlan_11h_JPN_bottom_band = { 8, 3 };
100 
101 /** U-NII sub-band config : Start Channel = 36, NumChans = 4 */
102 static const
103 IEEEtypes_SupportChan_Subband_t wlan_11h_unii_lower_band = { 36, 4 };
104 
105 /** U-NII sub-band config : Start Channel = 52, NumChans = 4 */
106 static const
107 IEEEtypes_SupportChan_Subband_t wlan_11h_unii_middle_band = { 52, 4 };
108 
109 /** U-NII sub-band config : Start Channel = 100, NumChans = 11 */
110 static const
111 IEEEtypes_SupportChan_Subband_t wlan_11h_unii_mid_upper_band = { 100, 11 };
112 
113 /** U-NII sub-band config : Start Channel = 149, NumChans = 5 */
114 static const
115 IEEEtypes_SupportChan_Subband_t wlan_11h_unii_upper_band = { 149, 5 };
116 
117 /** Internally passed structure used to send a CMD_802_11_TPC_INFO command */
118 typedef struct {
119 	t_u8 chan;
120 	       /**< Channel to which the power constraint applies */
121 	t_u8 power_constraint;
122 			   /**< Local power constraint to send to firmware */
123 } wlan_11h_tpc_info_param_t;
124 
125 /********************************************************
126 			Global Variables
127 ********************************************************/
128 
129 /********************************************************
130 			Local Functions
131 ********************************************************/
132 
133 /**
134  *  @brief Utility function to get a random number based on the underlying OS
135  *
136  *  @param pmadapter Pointer to mlan_adapter
137  *  @return random integer
138  */
139 static t_u32
wlan_11h_get_random_num(pmlan_adapter pmadapter)140 wlan_11h_get_random_num(pmlan_adapter pmadapter)
141 {
142 	t_u32 sec, usec;
143 
144 	ENTER();
145 	pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle, &sec,
146 						  &usec);
147 	sec = (sec & 0xFFFF) + (sec >> 16);
148 	usec = (usec & 0xFFFF) + (usec >> 16);
149 
150 	LEAVE();
151 	return (usec << 16) | sec;
152 }
153 
154 /**
155  *  @brief Convert an IEEE formatted IE to 16-bit ID/Len Marvell
156  *         proprietary format
157  *
158  *  @param pmadapter Pointer to mlan_adapter
159  *  @param pout_buf Output parameter: Buffer to output Marvell formatted IE
160  *  @param pin_ie   Pointer to IEEE IE to be converted to Marvell format
161  *
162  *  @return         Number of bytes output to pout_buf parameter return
163  */
164 static t_u32
wlan_11h_convert_ieee_to_mrvl_ie(mlan_adapter * pmadapter,t_u8 * pout_buf,const t_u8 * pin_ie)165 wlan_11h_convert_ieee_to_mrvl_ie(mlan_adapter *pmadapter,
166 				 t_u8 *pout_buf, const t_u8 *pin_ie)
167 {
168 	MrvlIEtypesHeader_t mrvl_ie_hdr;
169 	t_u8 *ptmp_buf = pout_buf;
170 
171 	ENTER();
172 	/* Assign the Element Id and Len to the Marvell struct attributes */
173 	mrvl_ie_hdr.type = wlan_cpu_to_le16(pin_ie[0]);
174 	mrvl_ie_hdr.len = wlan_cpu_to_le16(pin_ie[1]);
175 
176 	/* If the element ID is zero, return without doing any copying */
177 	if (!mrvl_ie_hdr.type) {
178 		LEAVE();
179 		return 0;
180 	}
181 
182 	/* Copy the header to the buffer pointer */
183 	memcpy(pmadapter, ptmp_buf, &mrvl_ie_hdr, sizeof(mrvl_ie_hdr));
184 
185 	/* Increment the temp buffer pointer by the size appended */
186 	ptmp_buf += sizeof(mrvl_ie_hdr);
187 
188 	/* Append the data section of the IE; length given by the IEEE IE length */
189 	memcpy(pmadapter, ptmp_buf, pin_ie + 2, pin_ie[1]);
190 
191 	LEAVE();
192 	/* Return the number of bytes appended to pout_buf */
193 	return sizeof(mrvl_ie_hdr) + pin_ie[1];
194 }
195 
196 #ifdef STA_SUPPORT
197 /**
198  *  @brief Setup the IBSS DFS element passed to the firmware in adhoc start
199  *         and join commands
200  *
201  *  The DFS Owner and recovery fields are set to be our MAC address and
202  *    a predetermined constant recovery value.  If we are joining an adhoc
203  *    network, these values are replaced with the existing IBSS values.
204  *    They are valid only when starting a new IBSS.
205  *
206  *  The IBSS DFS Element is variable in size based on the number of
207  *    channels supported in our current region.
208  *
209  *  @param priv Private driver information structure
210  *  @param pdfs Output parameter: Pointer to the IBSS DFS element setup by
211  *              this function.
212  *
213  *  @return
214  *    - Length of the returned element in pdfs output parameter
215  *    - 0 if returned element is not setup
216  */
217 static t_u32
wlan_11h_set_ibss_dfs_ie(mlan_private * priv,IEEEtypes_IBSS_DFS_t * pdfs)218 wlan_11h_set_ibss_dfs_ie(mlan_private *priv, IEEEtypes_IBSS_DFS_t *pdfs)
219 {
220 	t_u8 num_chans = 0;
221 	MeasRptBasicMap_t initial_map;
222 	mlan_adapter *adapter = priv->adapter;
223 
224 	ENTER();
225 
226 	memset(adapter, pdfs, 0x00, sizeof(IEEEtypes_IBSS_DFS_t));
227 
228 	/*
229 	 * A basic measurement report is included with each channel in the
230 	 *   map field.  Initial value for the map for each supported channel
231 	 *   is with only the unmeasured bit set.
232 	 */
233 	memset(adapter, &initial_map, 0x00, sizeof(initial_map));
234 	initial_map.unmeasured = 1;
235 
236 	/* Set the DFS Owner and recovery interval fields */
237 	memcpy(adapter, pdfs->dfs_owner, priv->curr_addr,
238 	       sizeof(pdfs->dfs_owner));
239 	pdfs->dfs_recovery_interval = WLAN_11H_DEFAULT_DFS_RECOVERY_INTERVAL;
240 
241 	for (; (num_chans < adapter->parsed_region_chan.no_of_chan)
242 	     && (num_chans < WLAN_11H_MAX_IBSS_DFS_CHANNELS); num_chans++) {
243 		pdfs->channel_map[num_chans].channel_number =
244 			adapter->parsed_region_chan.chan_pwr[num_chans].chan;
245 
246 		/*
247 		 * Set the initial map field with a basic measurement
248 		 */
249 		pdfs->channel_map[num_chans].rpt_map = initial_map;
250 	}
251 
252 	/*
253 	 * If we have an established channel map, include it and return
254 	 *   a valid DFS element
255 	 */
256 	if (num_chans) {
257 		PRINTM(MINFO, "11h: Added %d channels to IBSS DFS Map\n",
258 		       num_chans);
259 
260 		pdfs->element_id = IBSS_DFS;
261 		pdfs->len =
262 			(sizeof(pdfs->dfs_owner) +
263 			 sizeof(pdfs->dfs_recovery_interval)
264 			 + num_chans * sizeof(IEEEtypes_ChannelMap_t));
265 
266 		LEAVE();
267 		return pdfs->len + sizeof(pdfs->len) + sizeof(pdfs->element_id);
268 	}
269 
270 	/* Ensure the element is zeroed out for an invalid return */
271 	memset(adapter, pdfs, 0x00, sizeof(IEEEtypes_IBSS_DFS_t));
272 
273 	LEAVE();
274 	return 0;
275 }
276 #endif
277 
278 /**
279  *  @brief Setup the Supported Channel IE sent in association requests
280  *
281  *  The Supported Channels IE is required to be sent when the spectrum
282  *    management capability (11h) is enabled.  The element contains a
283  *    starting channel and number of channels tuple for each sub-band
284  *    the STA supports.  This information is based on the operating region.
285  *
286  *  @param priv      Private driver information structure
287  *  @param band      Band in use
288  *  @param psup_chan Output parameter: Pointer to the Supported Chan element
289  *                   setup by this function.
290  *
291  *  @return
292  *    - Length of the returned element in psup_chan output parameter
293  *    - 0 if returned element is not setup
294  */
295 static
296 	t_u16
wlan_11h_set_supp_channels_ie(mlan_private * priv,t_u8 band,IEEEtypes_SupportedChannels_t * psup_chan)297 wlan_11h_set_supp_channels_ie(mlan_private *priv,
298 			      t_u8 band,
299 			      IEEEtypes_SupportedChannels_t *psup_chan)
300 {
301 	t_u16 num_subbands = 0;
302 	t_u16 ret_len = 0;
303 	t_u8 cfp_bg, cfp_a;
304 
305 	ENTER();
306 	memset(priv->adapter, psup_chan, 0x00,
307 	       sizeof(IEEEtypes_SupportedChannels_t));
308 
309 	cfp_bg = cfp_a = priv->adapter->region_code;
310 	if (!priv->adapter->region_code) {
311 		/* Invalid region code, use CFP code */
312 		cfp_bg = priv->adapter->cfp_code_bg;
313 		cfp_a = priv->adapter->cfp_code_a;
314 	}
315 
316 	if ((band & BAND_B) || (band & BAND_G)) {
317 		/*
318 		 * Channels are contiguous in 2.4GHz, usually only one subband.
319 		 */
320 		switch (cfp_bg) {
321 		case 0x10:	/* USA FCC   */
322 		case 0x20:	/* Canada IC */
323 		default:
324 			psup_chan->subband[num_subbands++] =
325 				wlan_11h_2_4G_region_FCC;
326 			break;
327 		case 0x30:	/* Europe ETSI */
328 		case 0x41:	/* Japan  */
329 		case 0x50:	/* China  */
330 			psup_chan->subband[num_subbands++] =
331 				wlan_11h_2_4G_region_EU;
332 			break;
333 		case 0x40:	/* Japan  */
334 			psup_chan->subband[num_subbands++] =
335 				wlan_11h_2_4G_region_JPN40;
336 			break;
337 		case 0xff:	/* Japan special */
338 			psup_chan->subband[num_subbands++] =
339 				wlan_11h_2_4G_region_EU;
340 			psup_chan->subband[num_subbands++] =
341 				wlan_11h_2_4G_region_JPN40;
342 			break;
343 		}
344 	} else if (band & BAND_A) {
345 		/*
346 		 * Set the supported channel elements based on the region code,
347 		 * incrementing num_subbands for each sub-band we append to the
348 		 * element.
349 		 */
350 		switch (cfp_a) {
351 		case 0x10:	/* USA FCC   */
352 		case 0x20:	/* Canada IC */
353 		case 0x30:	/* Europe ETSI */
354 		default:
355 			psup_chan->subband[num_subbands++] =
356 				wlan_11h_unii_lower_band;
357 			psup_chan->subband[num_subbands++] =
358 				wlan_11h_unii_middle_band;
359 			psup_chan->subband[num_subbands++] =
360 				wlan_11h_unii_mid_upper_band;
361 			psup_chan->subband[num_subbands++] =
362 				wlan_11h_unii_upper_band;
363 			break;
364 		case 0x50:	/* China */
365 			psup_chan->subband[num_subbands++] =
366 				wlan_11h_unii_lower_band;
367 			psup_chan->subband[num_subbands++] =
368 				wlan_11h_unii_middle_band;
369 			psup_chan->subband[num_subbands++] =
370 				wlan_11h_unii_upper_band;
371 			break;
372 		case 0x40:	/* Japan */
373 		case 0x41:	/* Japan */
374 		case 0xff:	/* Japan special */
375 			psup_chan->subband[num_subbands++] =
376 				wlan_11h_JPN_bottom_band;
377 			psup_chan->subband[num_subbands++] =
378 				wlan_11h_unii_lower_band;
379 			psup_chan->subband[num_subbands++] =
380 				wlan_11h_unii_middle_band;
381 			psup_chan->subband[num_subbands++] =
382 				wlan_11h_unii_mid_upper_band;
383 			break;
384 		case 0x1:	/* Low band (5150-5250 MHz) channels */
385 			psup_chan->subband[num_subbands++] =
386 				wlan_11h_unii_lower_band;
387 			break;
388 		case 0x2:	/* Lower middle band (5250-5350 MHz) channels */
389 			psup_chan->subband[num_subbands++] =
390 				wlan_11h_unii_middle_band;
391 			break;
392 		case 0x3:	/* Upper middle band (5470-5725 MHz) channels */
393 			psup_chan->subband[num_subbands++] =
394 				wlan_11h_unii_mid_upper_band;
395 			break;
396 		case 0x4:	/* High band (5725-5850 MHz) channels */
397 			psup_chan->subband[num_subbands++] =
398 				wlan_11h_unii_upper_band;
399 			break;
400 		case 0x5:	/* Low band (5150-5250 MHz) and High band (5725-5850 MHz) channels */
401 			psup_chan->subband[num_subbands++] =
402 				wlan_11h_unii_lower_band;
403 			psup_chan->subband[num_subbands++] =
404 				wlan_11h_unii_upper_band;
405 			break;
406 		case 0x6:	/* Low band (5150-5250 MHz) and Lower middle band (5250-5350 MHz) and High band (5725-5850 MHz) channels */
407 			psup_chan->subband[num_subbands++] =
408 				wlan_11h_unii_lower_band;
409 			psup_chan->subband[num_subbands++] =
410 				wlan_11h_unii_middle_band;
411 			psup_chan->subband[num_subbands++] =
412 				wlan_11h_unii_upper_band;
413 			break;
414 		}
415 	}
416 
417 	/*
418 	 * If we have setup any supported subbands in the element, return a
419 	 *    valid IE along with its size, else return 0.
420 	 */
421 	if (num_subbands) {
422 		psup_chan->element_id = SUPPORTED_CHANNELS;
423 		psup_chan->len =
424 			num_subbands * sizeof(IEEEtypes_SupportChan_Subband_t);
425 
426 		ret_len = (t_u16)(psup_chan->len
427 				  + sizeof(psup_chan->len) +
428 				  sizeof(psup_chan->element_id));
429 
430 		HEXDUMP("11h: SupChan", (t_u8 *)psup_chan, ret_len);
431 	}
432 
433 	LEAVE();
434 	return ret_len;
435 }
436 
437 /**
438  *  @brief Prepare CMD_802_11_TPC_ADAPT_REQ firmware command
439  *
440  *  @param priv      Private driver information structure
441  *  @param pcmd_ptr  Output parameter: Pointer to the command being prepared
442  *                   for the firmware
443  *  @param pinfo_buf HostCmd_DS_802_11_TPC_ADAPT_REQ passed as void data block
444  *
445  *  @return          MLAN_STATUS_SUCCESS
446  */
447 static mlan_status
wlan_11h_cmd_tpc_request(mlan_private * priv,HostCmd_DS_COMMAND * pcmd_ptr,const t_void * pinfo_buf)448 wlan_11h_cmd_tpc_request(mlan_private *priv,
449 			 HostCmd_DS_COMMAND *pcmd_ptr, const t_void *pinfo_buf)
450 {
451 	ENTER();
452 
453 	memcpy(priv->adapter, &pcmd_ptr->params.tpc_req, pinfo_buf,
454 	       sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ));
455 
456 	pcmd_ptr->params.tpc_req.req.timeout =
457 		wlan_cpu_to_le16(pcmd_ptr->params.tpc_req.req.timeout);
458 
459 	/* Converted to little endian in wlan_11h_cmd_process */
460 	pcmd_ptr->size = sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ) + S_DS_GEN;
461 
462 	HEXDUMP("11h: 11_TPC_ADAPT_REQ:", (t_u8 *)pcmd_ptr,
463 		(t_u32)pcmd_ptr->size);
464 
465 	LEAVE();
466 	return MLAN_STATUS_SUCCESS;
467 }
468 
469 /**
470  *  @brief Prepare CMD_802_11_TPC_INFO firmware command
471  *
472  *  @param priv      Private driver information structure
473  *  @param pcmd_ptr  Output parameter: Pointer to the command being prepared
474  *                   for the firmware
475  *  @param pinfo_buf wlan_11h_tpc_info_param_t passed as void data block
476  *
477  *  @return          MLAN_STATUS_SUCCESS
478  */
479 static mlan_status
wlan_11h_cmd_tpc_info(mlan_private * priv,HostCmd_DS_COMMAND * pcmd_ptr,const t_void * pinfo_buf)480 wlan_11h_cmd_tpc_info(mlan_private *priv,
481 		      HostCmd_DS_COMMAND *pcmd_ptr, const t_void *pinfo_buf)
482 {
483 	HostCmd_DS_802_11_TPC_INFO *ptpc_info = &pcmd_ptr->params.tpc_info;
484 	MrvlIEtypes_LocalPowerConstraint_t *pconstraint =
485 		&ptpc_info->local_constraint;
486 	MrvlIEtypes_PowerCapability_t *pcap = &ptpc_info->power_cap;
487 
488 	wlan_11h_device_state_t *pstate = &priv->adapter->state_11h;
489 	const wlan_11h_tpc_info_param_t *ptpc_info_param =
490 		(wlan_11h_tpc_info_param_t *)pinfo_buf;
491 
492 	ENTER();
493 
494 	pcap->min_power = pstate->min_tx_power_capability;
495 	pcap->max_power = pstate->max_tx_power_capability;
496 	pcap->header.len = wlan_cpu_to_le16(2);
497 	pcap->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CAPABILITY);
498 
499 	pconstraint->chan = ptpc_info_param->chan;
500 	pconstraint->constraint = ptpc_info_param->power_constraint;
501 	pconstraint->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CONSTRAINT);
502 	pconstraint->header.len = wlan_cpu_to_le16(2);
503 
504 	/* Converted to little endian in wlan_11h_cmd_process */
505 	pcmd_ptr->size = sizeof(HostCmd_DS_802_11_TPC_INFO) + S_DS_GEN;
506 
507 	HEXDUMP("11h: TPC INFO", (t_u8 *)pcmd_ptr, (t_u32)pcmd_ptr->size);
508 
509 	LEAVE();
510 	return MLAN_STATUS_SUCCESS;
511 }
512 
513 /**
514  *  @brief  Prepare CMD_802_11_CHAN_SW_ANN firmware command
515  *
516  *  @param priv      Private driver information structure
517  *  @param pcmd_ptr  Output parameter: Pointer to the command being
518  *                   prepared to for firmware
519  *  @param pinfo_buf HostCmd_DS_802_11_CHAN_SW_ANN passed as void data block
520  *
521  *  @return          MLAN_STATUS_SUCCESS
522  */
523 static mlan_status
wlan_11h_cmd_chan_sw_ann(mlan_private * priv,HostCmd_DS_COMMAND * pcmd_ptr,const t_void * pinfo_buf)524 wlan_11h_cmd_chan_sw_ann(mlan_private *priv,
525 			 HostCmd_DS_COMMAND *pcmd_ptr, const t_void *pinfo_buf)
526 {
527 	const HostCmd_DS_802_11_CHAN_SW_ANN *pch_sw_ann =
528 		(HostCmd_DS_802_11_CHAN_SW_ANN *)pinfo_buf;
529 
530 	ENTER();
531 
532 	/* Converted to little endian in wlan_11h_cmd_process */
533 	pcmd_ptr->size = sizeof(HostCmd_DS_802_11_CHAN_SW_ANN) + S_DS_GEN;
534 
535 	memcpy(priv->adapter, &pcmd_ptr->params.chan_sw_ann, pch_sw_ann,
536 	       sizeof(HostCmd_DS_802_11_CHAN_SW_ANN));
537 
538 	PRINTM(MINFO, "11h: ChSwAnn: %#x-%u, Seq=%u, Ret=%u\n",
539 	       pcmd_ptr->command, pcmd_ptr->size, pcmd_ptr->seq_num,
540 	       pcmd_ptr->result);
541 	PRINTM(MINFO, "11h: ChSwAnn: Ch=%d, Cnt=%d, Mode=%d\n",
542 	       pch_sw_ann->new_chan, pch_sw_ann->switch_count,
543 	       pch_sw_ann->switch_mode);
544 
545 	LEAVE();
546 	return MLAN_STATUS_SUCCESS;
547 }
548 
549 /**
550  *  @brief  Prepare CMD_CHAN_REPORT_REQUEST firmware command
551  *
552  *  @param priv      Private driver information structure
553  *  @param pcmd_ptr  Output parameter: Pointer to the command being
554  *                   prepared to for firmware
555  *  @param pinfo_buf HostCmd_DS_CHAN_RPT_REQ passed as void data block
556  *
557  *  @return          MLAN_STATUS_SUCCESS or MLAN_STATUS_PENDING
558  */
559 static mlan_status
wlan_11h_cmd_chan_rpt_req(mlan_private * priv,HostCmd_DS_COMMAND * pcmd_ptr,const t_void * pinfo_buf)560 wlan_11h_cmd_chan_rpt_req(mlan_private *priv,
561 			  HostCmd_DS_COMMAND *pcmd_ptr, const t_void *pinfo_buf)
562 {
563 	const HostCmd_DS_CHAN_RPT_REQ *pchan_rpt_req =
564 		(HostCmd_DS_CHAN_RPT_REQ *)pinfo_buf;
565 	wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
566 	MrvlIEtypes_ChanRpt11hBasic_t *ptlv_basic;
567 	t_bool is_cancel_req = MFALSE;
568 
569 	/*
570 	 * pchan_rpt_req->millisec_dwell_time would be zero if the chan_rpt_req
571 	 * is to cancel current ongoing report
572 	 */
573 	if (pchan_rpt_req->millisec_dwell_time == 0)
574 		is_cancel_req = MTRUE;
575 
576 	ENTER();
577 	if (pstate_dfs->dfs_check_pending && !is_cancel_req) {
578 		PRINTM(MERROR,
579 		       "11h: ChanRptReq - previous CMD_CHAN_REPORT_REQUEST has"
580 		       " not returned its result yet (as EVENT_CHANNEL_READY)."
581 		       "  This command will be dropped.\n");
582 		LEAVE();
583 		return MLAN_STATUS_PENDING;
584 	}
585 
586 	/* Converted to little endian in wlan_11h_cmd_process */
587 	pcmd_ptr->size = sizeof(HostCmd_DS_CHAN_RPT_REQ) + S_DS_GEN;
588 
589 	memcpy(priv->adapter, &pcmd_ptr->params.chan_rpt_req, pchan_rpt_req,
590 	       sizeof(HostCmd_DS_CHAN_RPT_REQ));
591 	pcmd_ptr->params.chan_rpt_req.chan_desc.startFreq =
592 		wlan_cpu_to_le16(pchan_rpt_req->chan_desc.startFreq);
593 	pcmd_ptr->params.chan_rpt_req.millisec_dwell_time =
594 		wlan_cpu_to_le32(pchan_rpt_req->millisec_dwell_time);
595 
596 	/* if DFS channel, add BASIC report TLV, and set radar bit */
597 	if (!is_cancel_req &&
598 	    wlan_11h_radar_detect_required(priv,
599 					   pchan_rpt_req->chan_desc.chanNum)) {
600 		ptlv_basic =
601 			(MrvlIEtypes_ChanRpt11hBasic_t *)(((t_u8 *)(pcmd_ptr)) +
602 							  pcmd_ptr->size);
603 		ptlv_basic->Header.type =
604 			wlan_cpu_to_le16(TLV_TYPE_CHANRPT_11H_BASIC);
605 		ptlv_basic->Header.len =
606 			wlan_cpu_to_le16(sizeof(MeasRptBasicMap_t));
607 		memset(priv->adapter, &ptlv_basic->map, 0,
608 		       sizeof(MeasRptBasicMap_t));
609 		ptlv_basic->map.radar = 1;
610 		pcmd_ptr->size += sizeof(MrvlIEtypes_ChanRpt11hBasic_t);
611 	}
612 
613 	/* update dfs sturcture.
614 	 * dfs_check_pending is set when we receive CMD_RESP == SUCCESS */
615 	pstate_dfs->dfs_check_pending = MFALSE;
616 	pstate_dfs->dfs_radar_found = MFALSE;
617 	pstate_dfs->dfs_check_priv = MNULL;
618 
619 	if (!is_cancel_req)
620 		pstate_dfs->dfs_check_channel =
621 			pchan_rpt_req->chan_desc.chanNum;
622 
623 	LEAVE();
624 	return MLAN_STATUS_SUCCESS;
625 }
626 
627 /**
628  *  @brief Set the local power capability and constraint TLV
629  *
630  *  @param ppbuffer                The buffer to add these two TLVs
631  *  @param channel                 Channel to which the power constraint applies
632  *  @param power_constraint        Power constraint to be applied on the channel
633  *  @param min_tx_power_capability Min. Tx Power in Power Capability IE
634  *  @param max_tx_power_capability Max. Tx Power in Power Capability IE
635  *
636  *  @return                        The len increased
637  */
638 static t_u32
wlan_11h_set_local_power_constraint_tlv(t_u8 ** ppbuffer,t_u8 channel,t_u8 power_constraint,t_u8 min_tx_power_capability,t_u8 max_tx_power_capability)639 wlan_11h_set_local_power_constraint_tlv(t_u8 **ppbuffer,
640 					t_u8 channel,
641 					t_u8 power_constraint,
642 					t_u8 min_tx_power_capability,
643 					t_u8 max_tx_power_capability)
644 {
645 	MrvlIEtypes_PowerCapability_t *pcap;
646 	MrvlIEtypes_LocalPowerConstraint_t *pconstraint;
647 	t_u8 *start_ptr = MNULL;
648 
649 	ENTER();
650 
651 	/* Null Checks */
652 	if ((ppbuffer == MNULL) || (((t_u8 *)(*ppbuffer)) == MNULL)) {
653 		LEAVE();
654 		return 0;
655 	}
656 
657 	start_ptr = (t_u8 *)(*ppbuffer);
658 
659 	PRINTM(MINFO,
660 	       "11h: Set local power constraint = %d channel=%d min_tx_pwr=%d max_tx_pwr=%d\n",
661 	       power_constraint, channel, min_tx_power_capability,
662 	       max_tx_power_capability);
663 
664 	pcap = (MrvlIEtypes_PowerCapability_t *)*ppbuffer;
665 	pcap->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CAPABILITY);
666 	pcap->header.len = wlan_cpu_to_le16(2);
667 	pcap->min_power = min_tx_power_capability;
668 	pcap->max_power = max_tx_power_capability;
669 	*ppbuffer += sizeof(MrvlIEtypesHeader_t) + 2;
670 
671 	pconstraint = (MrvlIEtypes_LocalPowerConstraint_t *)*ppbuffer;
672 	pconstraint->header.type = wlan_cpu_to_le16(TLV_TYPE_POWER_CONSTRAINT);
673 	pconstraint->header.len = wlan_cpu_to_le16(2);
674 	pconstraint->chan = channel;
675 	pconstraint->constraint = power_constraint;
676 	*ppbuffer += sizeof(MrvlIEtypesHeader_t) + 2;
677 
678 	LEAVE();
679 	return (t_u32)(*ppbuffer - start_ptr);
680 }
681 
682 /**
683  *  @brief  Utility function to process a join to an infrastructure BSS
684  *
685  *  @param priv          Private driver information structure
686  *  @param ppbuffer      Output parameter: Pointer to the TLV output buffer,
687  *                       modified on return to point after the appended 11h TLVs
688  *  @param band          Band on which we are joining the BSS
689  *  @param channel       Channel on which we are joining the BSS
690  *  @param p11h_bss_info Pointer to the 11h BSS information for this network
691  *                       that was parsed out of the scan response.
692  *
693  *  @return              Integer number of bytes appended to the TLV output
694  *                       buffer (ppbuffer)
695  */
696 static t_u32
wlan_11h_process_infra_join(mlan_private * priv,t_u8 ** ppbuffer,t_u8 band,t_u32 channel,wlan_11h_bss_info_t * p11h_bss_info)697 wlan_11h_process_infra_join(mlan_private *priv,
698 			    t_u8 **ppbuffer,
699 			    t_u8 band,
700 			    t_u32 channel, wlan_11h_bss_info_t *p11h_bss_info)
701 {
702 	MrvlIEtypesHeader_t ie_header;
703 	IEEEtypes_SupportedChannels_t sup_chan_ie;
704 	t_u32 ret_len = 0;
705 	t_u16 sup_chan_len = 0;
706 
707 	ENTER();
708 
709 	/* Null Checks */
710 	if ((ppbuffer == MNULL) || (((t_u8 *)(*ppbuffer)) == MNULL)) {
711 		LEAVE();
712 		return 0;
713 	}
714 
715 	ret_len +=
716 		wlan_11h_set_local_power_constraint_tlv(ppbuffer, (t_u8)channel,
717 							(t_u8)p11h_bss_info->
718 							power_constraint.
719 							local_constraint,
720 							(t_u8)priv->adapter->
721 							state_11h.
722 							min_tx_power_capability,
723 							(t_u8)priv->adapter->
724 							state_11h.
725 							max_tx_power_capability);
726 
727 	/* Setup the Supported Channels IE */
728 	sup_chan_len = wlan_11h_set_supp_channels_ie(priv, band, &sup_chan_ie);
729 
730 	/*
731 	 * If we returned a valid Supported Channels IE, wrap and append it
732 	 */
733 	if (sup_chan_len) {
734 		/* Wrap the supported channels IE with a passthrough TLV type */
735 		ie_header.type = wlan_cpu_to_le16(TLV_TYPE_PASSTHROUGH);
736 		ie_header.len = wlan_cpu_to_le16(sup_chan_len);
737 		memcpy(priv->adapter, *ppbuffer, &ie_header, sizeof(ie_header));
738 
739 		/*
740 		 * Increment the return size and the return buffer
741 		 * pointer param
742 		 */
743 		*ppbuffer += sizeof(ie_header);
744 		ret_len += sizeof(ie_header);
745 
746 		/*
747 		 * Copy the supported channels IE to the output buf,
748 		 * advance pointer
749 		 */
750 		memcpy(priv->adapter, *ppbuffer, &sup_chan_ie, sup_chan_len);
751 		*ppbuffer += sup_chan_len;
752 		ret_len += sup_chan_len;
753 	}
754 
755 	LEAVE();
756 	return ret_len;
757 }
758 
759 /**
760  *  @brief Utility function to process a start or join to an adhoc network
761  *
762  *  Add the elements to the TLV buffer needed in the start/join adhoc commands:
763  *       - IBSS DFS IE
764  *       - Quiet IE
765  *
766  *  Also send the local constraint to the firmware in a TPC_INFO command.
767  *
768  *  @param priv          Private driver information structure
769  *  @param ppbuffer      Output parameter: Pointer to the TLV output buffer,
770  *                       modified on return to point after the appended 11h TLVs
771  *  @param channel       Channel on which we are starting/joining the IBSS
772  *  @param p11h_bss_info Pointer to the 11h BSS information for this network
773  *                       that was parsed out of the scan response.  NULL
774  *                       indicates we are starting the adhoc network
775  *
776  *  @return              Integer number of bytes appended to the TLV output
777  *                       buffer (ppbuffer)
778  */
779 static t_u32
wlan_11h_process_adhoc(mlan_private * priv,t_u8 ** ppbuffer,t_u32 channel,wlan_11h_bss_info_t * p11h_bss_info)780 wlan_11h_process_adhoc(mlan_private *priv,
781 		       t_u8 **ppbuffer,
782 		       t_u32 channel, wlan_11h_bss_info_t *p11h_bss_info)
783 {
784 	IEEEtypes_IBSS_DFS_t dfs_elem;
785 	t_u32 size_appended;
786 	t_u32 ret_len = 0;
787 	t_s8 local_constraint = 0;
788 	mlan_adapter *adapter = priv->adapter;
789 
790 	ENTER();
791 
792 #ifdef STA_SUPPORT
793 	/* Format our own IBSS DFS Element.  Include our channel map fields */
794 	wlan_11h_set_ibss_dfs_ie(priv, &dfs_elem);
795 #endif
796 
797 	if (p11h_bss_info) {
798 		/*
799 		 * Copy the DFS Owner/Recovery Interval from the BSS
800 		 * we are joining
801 		 */
802 		memcpy(adapter, dfs_elem.dfs_owner,
803 		       p11h_bss_info->ibss_dfs.dfs_owner,
804 		       sizeof(dfs_elem.dfs_owner));
805 		dfs_elem.dfs_recovery_interval =
806 			p11h_bss_info->ibss_dfs.dfs_recovery_interval;
807 	}
808 
809 	/* Append the dfs element to the TLV buffer */
810 	size_appended = wlan_11h_convert_ieee_to_mrvl_ie(adapter,
811 							 (t_u8 *)*ppbuffer,
812 							 (t_u8 *)&dfs_elem);
813 
814 	HEXDUMP("11h: IBSS-DFS", (t_u8 *)*ppbuffer, size_appended);
815 	*ppbuffer += size_appended;
816 	ret_len += size_appended;
817 
818 	/*
819 	 * Check to see if we are joining a network.  Join is indicated by the
820 	 *   BSS Info pointer being valid (not NULL)
821 	 */
822 	if (p11h_bss_info) {
823 		/*
824 		 * If there was a quiet element, include it in
825 		 * adhoc join command
826 		 */
827 		if (p11h_bss_info->quiet.element_id == QUIET) {
828 			size_appended
829 				=
830 				wlan_11h_convert_ieee_to_mrvl_ie(adapter,
831 								 (t_u8 *)
832 								 *ppbuffer,
833 								 (t_u8 *)
834 								 &p11h_bss_info->
835 								 quiet);
836 			HEXDUMP("11h: Quiet", (t_u8 *)*ppbuffer, size_appended);
837 			*ppbuffer += size_appended;
838 			ret_len += size_appended;
839 		}
840 
841 		/* Copy the local constraint from the network */
842 		local_constraint =
843 			p11h_bss_info->power_constraint.local_constraint;
844 	} else {
845 		/*
846 		 * If we are the adhoc starter, we can add a quiet element
847 		 */
848 		if (adapter->state_11h.quiet_ie.quiet_period) {
849 			size_appended =
850 				wlan_11h_convert_ieee_to_mrvl_ie(adapter,
851 								 (t_u8 *)
852 								 *ppbuffer,
853 								 (t_u8 *)
854 								 &adapter->
855 								 state_11h.
856 								 quiet_ie);
857 			HEXDUMP("11h: Quiet", (t_u8 *)*ppbuffer, size_appended);
858 			*ppbuffer += size_appended;
859 			ret_len += size_appended;
860 		}
861 		/* Use the local_constraint configured in the driver state */
862 		local_constraint = adapter->state_11h.usr_def_power_constraint;
863 	}
864 
865 	PRINTM(MINFO, "WEILIE 1: ppbuffer = %p\n", *ppbuffer);
866 
867 	ret_len +=
868 		wlan_11h_set_local_power_constraint_tlv(ppbuffer, (t_u8)channel,
869 							(t_u8)local_constraint,
870 							(t_u8)priv->adapter->
871 							state_11h.
872 							min_tx_power_capability,
873 							(t_u8)priv->adapter->
874 							state_11h.
875 							max_tx_power_capability);
876 	PRINTM(MINFO, "WEILIE 2: ppbuffer = %p\n", *ppbuffer);
877 
878 	LEAVE();
879 	return ret_len;
880 }
881 
882 /**
883  *  @brief Return whether the driver has enabled 11h for the interface
884  *
885  *  Association/Join commands are dynamic in that they enable 11h in the
886  *    driver/firmware when they are detected in the existing BSS.
887  *
888  *  @param priv  Private driver information structure
889  *
890  *  @return
891  *    - MTRUE if 11h is enabled
892  *    - MFALSE otherwise
893  */
894 static t_bool
wlan_11h_is_enabled(mlan_private * priv)895 wlan_11h_is_enabled(mlan_private *priv)
896 {
897 	ENTER();
898 	LEAVE();
899 	return priv->intf_state_11h.is_11h_enabled;
900 }
901 
902 /**
903  *  @brief Return whether the device has activated slave radar detection.
904  *
905  *  @param priv  Private driver information structure
906  *
907  *  @return
908  *    - MTRUE if slave radar detection is enabled in firmware
909  *    - MFALSE otherwise
910  */
911 static t_bool
wlan_11h_is_slave_radar_det_active(mlan_private * priv)912 wlan_11h_is_slave_radar_det_active(mlan_private *priv)
913 {
914 	ENTER();
915 	LEAVE();
916 	return priv->adapter->state_11h.is_slave_radar_det_active;
917 }
918 
919 /**
920  *  @brief Return whether the slave interface is active, and on DFS channel.
921  *  priv is assumed to already be a dfs slave interface, doesn't check this.
922  *
923  *  @param priv  Private driver information structure
924  *
925  *  @return
926  *    - MTRUE if priv is slave, and meets both conditions
927  *    - MFALSE otherwise
928  */
929 static t_bool
wlan_11h_is_slave_active_on_dfs_chan(mlan_private * priv)930 wlan_11h_is_slave_active_on_dfs_chan(mlan_private *priv)
931 {
932 	t_bool ret = MFALSE;
933 
934 	ENTER();
935 	if ((priv->media_connected == MTRUE) &&
936 	    (priv->curr_bss_params.band & BAND_A) &&
937 	    wlan_11h_radar_detect_required(priv,
938 					   priv->curr_bss_params.bss_descriptor.
939 					   channel))
940 		ret = MTRUE;
941 
942 	LEAVE();
943 	return ret;
944 }
945 
946 /**
947  *  @brief Return whether the master interface is active, and on DFS channel.
948  *  priv is assumed to already be a dfs master interface, doesn't check this.
949  *
950  *  @param priv  Private driver information structure
951  *
952  *  @return
953  *    - MTRUE if priv is master, and meets both conditions
954  *    - MFALSE otherwise
955  */
956 static t_bool
wlan_11h_is_master_active_on_dfs_chan(mlan_private * priv)957 wlan_11h_is_master_active_on_dfs_chan(mlan_private *priv)
958 {
959 	t_bool ret = MFALSE;
960 
961 	ENTER();
962 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) {
963 		/* Ad-hoc creator */
964 		if (((priv->media_connected == MTRUE)
965 		     || (priv->adhoc_state == ADHOC_STARTING)) &&
966 		    (priv->adapter->adhoc_start_band & BAND_A) &&
967 		    wlan_11h_radar_detect_required(priv, priv->adhoc_channel))
968 			ret = MTRUE;
969 	} else if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
970 		/* UAP */
971 #ifdef UAP_SUPPORT
972 		if ((priv->uap_bss_started == MTRUE) &&
973 		    (priv->uap_state_chan_cb.bandcfg.chanBand == BAND_5GHZ) &&
974 		    wlan_11h_radar_detect_required(priv,
975 						   priv->uap_state_chan_cb.
976 						   channel))
977 			ret = MTRUE;
978 #endif
979 	}
980 	LEAVE();
981 	return ret;
982 }
983 
984 /**
985  *  @brief Determine if priv is DFS Master interface
986  *
987  *  @param priv Pointer to mlan_private
988  *
989  *  @return MTRUE or MFALSE
990  */
991 static t_bool
wlan_11h_is_dfs_master(mlan_private * priv)992 wlan_11h_is_dfs_master(mlan_private *priv)
993 {
994 	t_bool ret = MFALSE;
995 
996 	ENTER();
997 	/* UAP: all are master */
998 	if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP)
999 		ret = MTRUE;
1000 
1001 	/* STA: only ad-hoc creator is master */
1002 	else if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
1003 		 (priv->bss_mode == MLAN_BSS_MODE_IBSS) &&
1004 		 (priv->adhoc_state == ADHOC_STARTED ||
1005 		  priv->adhoc_state == ADHOC_STARTING))
1006 		ret = MTRUE;
1007 
1008 	/* all other cases = slave interface */
1009 	LEAVE();
1010 	return ret;
1011 }
1012 
1013 /* Need this as function to pass to wlan_count_priv_cond() */
1014 /**
1015  *  @brief Determine if priv is DFS Slave interface
1016  *
1017  *  @param priv Pointer to mlan_private
1018  *
1019  *  @return MTRUE or MFALSE
1020  */
1021 
1022 static t_bool
wlan_11h_is_dfs_slave(mlan_private * priv)1023 wlan_11h_is_dfs_slave(mlan_private *priv)
1024 {
1025 	t_bool ret = MFALSE;
1026 	ENTER();
1027 	ret = !wlan_11h_is_dfs_master(priv);
1028 	LEAVE();
1029 	return ret;
1030 }
1031 
1032 /**
1033  *  @brief This function checks if interface is active.
1034  *
1035  *  @param pmpriv       A pointer to mlan_private structure
1036  *
1037  *  @return             MTRUE or MFALSE
1038  */
1039 t_bool
wlan_is_intf_active(mlan_private * pmpriv)1040 wlan_is_intf_active(mlan_private *pmpriv)
1041 {
1042 	t_bool ret = MFALSE;
1043 	ENTER();
1044 
1045 #ifdef UAP_SUPPORT
1046 	if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP)
1047 		/*
1048 		 * NOTE: UAP's media_connected == true only after first STA
1049 		 * associated. Need different variable to tell if UAP
1050 		 * has been started.
1051 		 */
1052 		ret = pmpriv->uap_bss_started;
1053 	else
1054 #endif
1055 	if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA)
1056 		ret = pmpriv->media_connected;
1057 
1058 	LEAVE();
1059 	return ret;
1060 }
1061 
1062 /**
1063  *  @brief This function gets current radar detect flags
1064  *
1065  *  @param pmadapter    A pointer to mlan_adapter structure
1066  *
1067  *  @return             11H MIB setting for radar detect
1068  */
1069 static t_u32
wlan_11h_get_current_radar_detect_flags(mlan_adapter * pmadapter)1070 wlan_11h_get_current_radar_detect_flags(mlan_adapter *pmadapter)
1071 {
1072 	t_u32 radar_det_flags = 0;
1073 
1074 	ENTER();
1075 	if (pmadapter->state_11h.is_master_radar_det_active)
1076 		radar_det_flags |= MASTER_RADAR_DET_MASK;
1077 	if (pmadapter->state_11h.is_slave_radar_det_active)
1078 		radar_det_flags |= SLAVE_RADAR_DET_MASK;
1079 
1080 	PRINTM(MINFO, "%s: radar_det_state_curr=0x%x\n",
1081 	       __func__, radar_det_flags);
1082 
1083 	LEAVE();
1084 	return radar_det_flags;
1085 }
1086 
1087 /**
1088  *  @brief This function checks if radar detect flags have/should be changed.
1089  *
1090  *  @param pmadapter    A pointer to mlan_adapter structure
1091  *  @param pnew_state   Output param with new state, if return MTRUE.
1092  *
1093  *  @return             MTRUE (need update) or MFALSE (no change in flags)
1094  */
1095 static t_bool
wlan_11h_check_radar_det_state(mlan_adapter * pmadapter,OUT t_u32 * pnew_state)1096 wlan_11h_check_radar_det_state(mlan_adapter *pmadapter, OUT t_u32 *pnew_state)
1097 {
1098 	t_u32 radar_det_state_new = 0;
1099 	t_bool ret;
1100 
1101 	ENTER();
1102 	PRINTM(MINFO, "%s: master_radar_det_pending=%d, "
1103 	       " slave_radar_det_pending=%d\n", __func__,
1104 	       pmadapter->state_11h.master_radar_det_enable_pending,
1105 	       pmadapter->state_11h.slave_radar_det_enable_pending);
1106 
1107 	/* new state comes from evaluating interface states & pending starts */
1108 	if (pmadapter->state_11h.master_radar_det_enable_pending ||
1109 	    (wlan_count_priv_cond(pmadapter,
1110 				  wlan_11h_is_master_active_on_dfs_chan,
1111 				  wlan_11h_is_dfs_master) > 0))
1112 		radar_det_state_new |= MASTER_RADAR_DET_MASK;
1113 	if (pmadapter->state_11h.slave_radar_det_enable_pending ||
1114 	    (wlan_count_priv_cond(pmadapter,
1115 				  wlan_11h_is_slave_active_on_dfs_chan,
1116 				  wlan_11h_is_dfs_slave) > 0))
1117 		radar_det_state_new |= SLAVE_RADAR_DET_MASK;
1118 
1119 	PRINTM(MINFO, "%s: radar_det_state_new=0x%x\n",
1120 	       __func__, radar_det_state_new);
1121 
1122 	/* now compare flags with current state */
1123 	ret = (wlan_11h_get_current_radar_detect_flags(pmadapter)
1124 	       != radar_det_state_new) ? MTRUE : MFALSE;
1125 	if (ret)
1126 		*pnew_state = radar_det_state_new;
1127 
1128 	LEAVE();
1129 	return ret;
1130 }
1131 
1132 /**
1133  *  @brief Prepare ioctl for add/remove CHAN_SW IE - RADAR_DETECTED event handling
1134  *
1135  *  @param pmadapter        Pointer to mlan_adapter
1136  *  @param pioctl_req       Pointer to completed mlan_ioctl_req (allocated inside)
1137  *  @param is_adding_ie     CHAN_SW IE is to be added (MTRUE), or removed (MFALSE)
1138  *
1139  *  @return                 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1140  */
1141 static mlan_status
wlan_11h_prepare_custom_ie_chansw(IN mlan_adapter * pmadapter,OUT mlan_ioctl_req ** ppioctl_req,IN t_bool is_adding_ie)1142 wlan_11h_prepare_custom_ie_chansw(IN mlan_adapter *pmadapter,
1143 				  OUT mlan_ioctl_req **ppioctl_req,
1144 				  IN t_bool is_adding_ie)
1145 {
1146 	mlan_ioctl_req *pioctl_req = MNULL;
1147 	mlan_ds_misc_cfg *pds_misc_cfg = MNULL;
1148 	custom_ie *pcust_chansw_ie = MNULL;
1149 	IEEEtypes_ChanSwitchAnn_t *pchansw_ie = MNULL;
1150 	mlan_status ret;
1151 
1152 	ENTER();
1153 
1154 	if (pmadapter == MNULL || ppioctl_req == MNULL) {
1155 		LEAVE();
1156 		return MLAN_STATUS_FAILURE;
1157 	}
1158 
1159 	/* allocate buffer for mlan_ioctl_req and mlan_ds_misc_cfg */
1160 	/* FYI - will be freed as part of cmd_response handler */
1161 	ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
1162 					       sizeof(mlan_ioctl_req) +
1163 					       sizeof(mlan_ds_misc_cfg),
1164 					       MLAN_MEM_DEF,
1165 					       (t_u8 **)&pioctl_req);
1166 	if ((ret != MLAN_STATUS_SUCCESS) || !pioctl_req) {
1167 		PRINTM(MERROR, "%s(): Could not allocate ioctl req\n",
1168 		       __func__);
1169 		LEAVE();
1170 		return MLAN_STATUS_FAILURE;
1171 	}
1172 	pds_misc_cfg = (mlan_ds_misc_cfg *)((t_u8 *)pioctl_req +
1173 					    sizeof(mlan_ioctl_req));
1174 
1175 	/* prepare mlan_ioctl_req */
1176 	memset(pmadapter, pioctl_req, 0x00, sizeof(mlan_ioctl_req));
1177 	pioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
1178 	pioctl_req->action = MLAN_ACT_SET;
1179 	pioctl_req->pbuf = (t_u8 *)pds_misc_cfg;
1180 	pioctl_req->buf_len = sizeof(mlan_ds_misc_cfg);
1181 
1182 	/* prepare mlan_ds_misc_cfg */
1183 	memset(pmadapter, pds_misc_cfg, 0x00, sizeof(mlan_ds_misc_cfg));
1184 	pds_misc_cfg->sub_command = MLAN_OID_MISC_CUSTOM_IE;
1185 	pds_misc_cfg->param.cust_ie.type = TLV_TYPE_MGMT_IE;
1186 	pds_misc_cfg->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE);
1187 
1188 	/* configure custom_ie api settings */
1189 	pcust_chansw_ie =
1190 		(custom_ie *)&pds_misc_cfg->param.cust_ie.ie_data_list[0];
1191 	pcust_chansw_ie->ie_index = 0xffff;	/* Auto index */
1192 	pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ChanSwitchAnn_t);
1193 	pcust_chansw_ie->mgmt_subtype_mask = (is_adding_ie)
1194 		? MBIT(8) | MBIT(5)	/* add IE for BEACON | PROBE_RSP */
1195 		: 0;		/* remove IE */
1196 
1197 	/* prepare CHAN_SW IE inside ioctl */
1198 	pchansw_ie = (IEEEtypes_ChanSwitchAnn_t *)pcust_chansw_ie->ie_buffer;
1199 	pchansw_ie->element_id = CHANNEL_SWITCH_ANN;
1200 	pchansw_ie->len =
1201 		sizeof(IEEEtypes_ChanSwitchAnn_t) - sizeof(IEEEtypes_Header_t);
1202 	pchansw_ie->chan_switch_mode = 1;	/* STA should not transmit */
1203 	pchansw_ie->new_channel_num = pmadapter->state_rdh.new_channel;
1204 
1205 	pchansw_ie->chan_switch_count = pmadapter->dfs_cs_count;
1206 	PRINTM(MCMD_D, "New Channel = %d Channel switch count = %d\n",
1207 	       pmadapter->state_rdh.new_channel, pchansw_ie->chan_switch_count);
1208 
1209 	pds_misc_cfg->param.cust_ie.len += pcust_chansw_ie->ie_length;
1210 	DBG_HEXDUMP(MCMD_D, "11h: custom_ie containing CHAN_SW IE",
1211 		    (t_u8 *)pcust_chansw_ie, pds_misc_cfg->param.cust_ie.len);
1212 
1213 	/* assign output pointer before returning */
1214 	*ppioctl_req = pioctl_req;
1215 	LEAVE();
1216 	return MLAN_STATUS_SUCCESS;
1217 }
1218 
1219 #ifdef UAP_SUPPORT
1220 /** Bits 2,3 of band config define the band width */
1221 #define UAP_BAND_WIDTH_MASK 0x0C
1222 
1223 /**
1224  *  @brief Check if start channel 165 is allowed to operate in
1225  *  previous uAP channel's band config
1226  *
1227  *  @param start_chn     Random Start channel choosen after radar detection
1228  *  @param uap_band_cfg  Private driver uAP band configuration information structure
1229  *
1230  *  @return MFALSE if the channel is not allowed in given band
1231  */
1232 static t_bool
wlan_11h_is_band_valid(t_u8 start_chn,Band_Config_t uap_band_cfg)1233 wlan_11h_is_band_valid(t_u8 start_chn, Band_Config_t uap_band_cfg)
1234 {
1235 
1236 	/* if band width is not 20MHZ (either 40 or 80MHz)
1237 	 * return MFALSE, 165 is not allowed in bands other than 20MHZ
1238 	 */
1239 	if (start_chn == 165 && (uap_band_cfg.chanWidth != CHAN_BW_20MHZ)) {
1240 		return MFALSE;
1241 	}
1242 	return MTRUE;
1243 }
1244 
1245 /**
1246  *  @brief Retrieve a randomly selected starting channel if needed for 11h
1247  *
1248  *  If 11h is enabled and 5GHz band is selected in band_config
1249  *    return a random channel in A band, else one from BG band.
1250  *
1251  *  @param priv          Private driver information structure
1252  *  @param uap_band_cfg  Private driver information structure
1253  *
1254  *  @return      Starting channel
1255  */
1256 static t_u8
wlan_11h_get_uap_start_channel(mlan_private * priv,Band_Config_t uap_band_cfg)1257 wlan_11h_get_uap_start_channel(mlan_private *priv, Band_Config_t uap_band_cfg)
1258 {
1259 	t_u8 start_chn;
1260 	mlan_adapter *adapter = priv->adapter;
1261 	t_u32 region;
1262 	t_u32 rand_entry;
1263 	region_chan_t *chn_tbl;
1264 	t_u8 rand_tries = 0;
1265 
1266 	/*TODO:  right now mostly a copy of wlan_11h_get_adhoc_start_channel.
1267 	 *       Improve to be more specfic to UAP, e.g.
1268 	 *       1. take into account COUNTRY_CODE -> region_code
1269 	 *       2. check domain_info for value channels
1270 	 */
1271 	ENTER();
1272 
1273 	/*
1274 	 * Set start_chn to the Default.
1275 	 * Used if 11h is disabled or the band
1276 	 * does not require 11h support.
1277 	 */
1278 	start_chn = DEFAULT_AD_HOC_CHANNEL;
1279 
1280 	/*
1281 	 * Check that we are looking for a channel in the A Band
1282 	 */
1283 	if (uap_band_cfg.chanBand == BAND_5GHZ) {
1284 		/*
1285 		 * Set default to the A Band default.
1286 		 * Used if random selection fails
1287 		 * or if 11h is not enabled
1288 		 */
1289 		start_chn = DEFAULT_AD_HOC_CHANNEL_A;
1290 
1291 		/*
1292 		 * Check that 11h is enabled in the driver
1293 		 */
1294 		if (wlan_11h_is_enabled(priv)) {
1295 			/*
1296 			 * Search the region_channel tables for a channel table
1297 			 * that is marked for the A Band.
1298 			 */
1299 			for (region = 0; (region < MAX_REGION_CHANNEL_NUM);
1300 			     region++) {
1301 				chn_tbl = &adapter->region_channel[region];
1302 
1303 				/* Check if table is valid and marked for A Band */
1304 				if (chn_tbl->valid
1305 				    && chn_tbl->region == adapter->region_code
1306 				    && chn_tbl->band & BAND_A) {
1307 					/*
1308 					 * Set the start channel.  Get a random
1309 					 * number and use it to pick an entry
1310 					 * in the table between 0 and the number
1311 					 * of channels in the table (NumCFP).
1312 					 */
1313 					rand_entry =
1314 						wlan_11h_get_random_num(adapter)
1315 						% chn_tbl->num_cfp;
1316 					start_chn =
1317 						(t_u8)chn_tbl->pcfp[rand_entry].
1318 						channel;
1319 					/* Loop until a non-dfs channel is found with compatible band
1320 					 * bounded by chn_tbl->num_cfp entries in the channel table
1321 					 */
1322 					while ((wlan_11h_is_channel_under_nop
1323 						(adapter, start_chn) ||
1324 						((adapter->state_rdh.stage ==
1325 						  RDH_GET_INFO_CHANNEL) &&
1326 						 wlan_11h_radar_detect_required
1327 						 (priv, start_chn)) ||
1328 						!(wlan_11h_is_band_valid
1329 						  (start_chn, uap_band_cfg))) &&
1330 					       (++rand_tries <
1331 						chn_tbl->num_cfp)) {
1332 						rand_entry++;
1333 						rand_entry =
1334 							rand_entry %
1335 							chn_tbl->num_cfp;
1336 						start_chn =
1337 							(t_u8)chn_tbl->
1338 							pcfp[rand_entry].
1339 							channel;
1340 						PRINTM(MINFO,
1341 						       "start chan=%d rand_entry=%d\n",
1342 						       start_chn, rand_entry);
1343 					}
1344 
1345 					if (rand_tries == chn_tbl->num_cfp) {
1346 						PRINTM(MERROR,
1347 						       "Failed to get UAP start channel\n");
1348 						start_chn = 0;
1349 					}
1350 				}
1351 			}
1352 		}
1353 	}
1354 
1355 	PRINTM(MCMD_D, "11h: UAP Get Start Channel %d\n", start_chn);
1356 	LEAVE();
1357 	return start_chn;
1358 }
1359 #endif /* UAP_SUPPORT */
1360 
1361 #ifdef DEBUG_LEVEL1
1362 static const char *DFS_TS_REPR_STRINGS[] = { "",
1363 	"NOP_start",
1364 	"CAC_completed"
1365 };
1366 #endif
1367 
1368 /**
1369  *  @brief Search for a dfs timestamp in the list with desired channel.
1370  *
1371  *  Assumes there will only be one timestamp per channel in the list.
1372  *
1373  *  @param pmadapter  Pointer to mlan_adapter
1374  *  @param channel    Channel number
1375  *
1376  *  @return           Pointer to timestamp if found, or MNULL
1377  */
1378 static wlan_dfs_timestamp_t *
wlan_11h_find_dfs_timestamp(mlan_adapter * pmadapter,t_u8 channel)1379 wlan_11h_find_dfs_timestamp(mlan_adapter *pmadapter, t_u8 channel)
1380 {
1381 	wlan_dfs_timestamp_t *pts = MNULL, *pts_found = MNULL;
1382 
1383 	ENTER();
1384 	pts = (wlan_dfs_timestamp_t *)util_peek_list(pmadapter->pmoal_handle,
1385 						     &pmadapter->state_dfs.
1386 						     dfs_ts_head, MNULL, MNULL);
1387 
1388 	while (pts &&
1389 	       pts !=
1390 	       (wlan_dfs_timestamp_t *)&pmadapter->state_dfs.dfs_ts_head) {
1391 		PRINTM(MINFO,
1392 		       "dfs_timestamp(@ %p) - chan=%d, repr=%d(%s),"
1393 		       " time(sec.usec)=%lu.%06lu\n", pts, pts->channel,
1394 		       pts->represents, DFS_TS_REPR_STRINGS[pts->represents],
1395 		       pts->ts_sec, pts->ts_usec);
1396 
1397 		if (pts->channel == channel) {
1398 			pts_found = pts;
1399 			break;
1400 		}
1401 		pts = pts->pnext;
1402 	}
1403 
1404 	LEAVE();
1405 	return pts_found;
1406 }
1407 
1408 /**
1409  *  @brief Removes dfs timestamp from list.
1410  *
1411  *  @param pmadapter  Pointer to mlan_adapter
1412  *  @param pdfs_ts    Pointer to dfs_timestamp to remove
1413  */
1414 static t_void
wlan_11h_remove_dfs_timestamp(mlan_adapter * pmadapter,wlan_dfs_timestamp_t * pdfs_ts)1415 wlan_11h_remove_dfs_timestamp(mlan_adapter *pmadapter,
1416 			      wlan_dfs_timestamp_t *pdfs_ts)
1417 {
1418 	ENTER();
1419 	/* dequeue and delete timestamp */
1420 	util_unlink_list(pmadapter->pmoal_handle,
1421 			 &pmadapter->state_dfs.dfs_ts_head,
1422 			 (pmlan_linked_list)pdfs_ts, MNULL, MNULL);
1423 	pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
1424 					(t_u8 *)pdfs_ts);
1425 	LEAVE();
1426 }
1427 
1428 /**
1429  *  @brief Add a dfs timestamp to the list
1430  *
1431  *  Assumes there will only be one timestamp per channel in the list,
1432  *  and that timestamp modes (represents) are mutually exclusive.
1433  *
1434  *  @param pmadapter  Pointer to mlan_adapter
1435  *  @param repr       Timestamp 'represents' value (see _dfs_timestamp_repr_e)
1436  *  @param channel    Channel number
1437  *
1438  *  @return           Pointer to timestamp if found, or MNULL
1439  */
1440 static mlan_status
wlan_11h_add_dfs_timestamp(mlan_adapter * pmadapter,t_u8 repr,t_u8 channel)1441 wlan_11h_add_dfs_timestamp(mlan_adapter *pmadapter, t_u8 repr, t_u8 channel)
1442 {
1443 	wlan_dfs_timestamp_t *pdfs_ts = MNULL;
1444 	mlan_status ret = MLAN_STATUS_SUCCESS;
1445 
1446 	ENTER();
1447 	pdfs_ts = wlan_11h_find_dfs_timestamp(pmadapter, channel);
1448 
1449 	if (!pdfs_ts) {
1450 		/* need to allocate new timestamp */
1451 		ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
1452 						       sizeof
1453 						       (wlan_dfs_timestamp_t),
1454 						       MLAN_MEM_DEF,
1455 						       (t_u8 **)&pdfs_ts);
1456 		if ((ret != MLAN_STATUS_SUCCESS) || !pdfs_ts) {
1457 			PRINTM(MERROR, "%s(): Could not allocate dfs_ts\n",
1458 			       __func__);
1459 			LEAVE();
1460 			return MLAN_STATUS_FAILURE;
1461 		}
1462 
1463 		memset(pmadapter, (t_u8 *)pdfs_ts, 0,
1464 		       sizeof(wlan_dfs_timestamp_t));
1465 
1466 		util_enqueue_list_tail(pmadapter->pmoal_handle,
1467 				       &pmadapter->state_dfs.dfs_ts_head,
1468 				       (pmlan_linked_list)pdfs_ts, MNULL,
1469 				       MNULL);
1470 		pdfs_ts->channel = channel;
1471 	}
1472 	/* (else, use existing timestamp for channel; see assumptions above) */
1473 
1474 	/* update params */
1475 	pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
1476 						  &pdfs_ts->ts_sec,
1477 						  &pdfs_ts->ts_usec);
1478 	pdfs_ts->represents = repr;
1479 
1480 	PRINTM(MCMD_D, "11h: add/update dfs_timestamp - chan=%d, repr=%d(%s),"
1481 	       " time(sec.usec)=%lu.%06lu\n", pdfs_ts->channel,
1482 	       pdfs_ts->represents, DFS_TS_REPR_STRINGS[pdfs_ts->represents],
1483 	       pdfs_ts->ts_sec, pdfs_ts->ts_usec);
1484 
1485 	LEAVE();
1486 	return ret;
1487 }
1488 
1489 /********************************************************
1490 			Global functions
1491 ********************************************************/
1492 
1493 /**
1494  *  @brief Return whether the device has activated master radar detection.
1495  *
1496  *  @param priv  Private driver information structure
1497  *
1498  *  @return
1499  *    - MTRUE if master radar detection is enabled in firmware
1500  *    - MFALSE otherwise
1501  */
1502 t_bool
wlan_11h_is_master_radar_det_active(mlan_private * priv)1503 wlan_11h_is_master_radar_det_active(mlan_private *priv)
1504 {
1505 	ENTER();
1506 	LEAVE();
1507 	return priv->adapter->state_11h.is_master_radar_det_active;
1508 }
1509 
1510 /**
1511  *  @brief Configure master radar detection.
1512  *  Call wlan_11h_check_update_radar_det_state() afterwards
1513  *    to push this to firmware.
1514  *
1515  *  @param priv  Private driver information structure
1516  *  @param enable Whether to enable or disable master radar detection
1517  *
1518  *  @return  MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1519  *
1520  *  @sa wlan_11h_check_update_radar_det_state
1521  */
1522 mlan_status
wlan_11h_config_master_radar_det(mlan_private * priv,t_bool enable)1523 wlan_11h_config_master_radar_det(mlan_private *priv, t_bool enable)
1524 {
1525 	mlan_status ret = MLAN_STATUS_FAILURE;
1526 
1527 	/* Force disable master radar detection on in-AP interfaces */
1528 	if (priv->adapter->dfs_repeater)
1529 		enable = MFALSE;
1530 
1531 	ENTER();
1532 	if (wlan_11h_is_dfs_master(priv) &&
1533 	    priv->adapter->init_para.dfs_master_radar_det_en) {
1534 		priv->adapter->state_11h.master_radar_det_enable_pending =
1535 			enable;
1536 		ret = MLAN_STATUS_SUCCESS;
1537 	}
1538 
1539 	LEAVE();
1540 	return ret;
1541 }
1542 
1543 /**
1544  *  @brief Configure slave radar detection.
1545  *  Call wlan_11h_check_update_radar_det_state() afterwards
1546  *    to push this to firmware.
1547  *
1548  *  @param priv  Private driver information structure
1549  *  @param enable Whether to enable or disable slave radar detection
1550  *
1551  *  @return  MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1552  *
1553  *  @sa wlan_11h_check_update_radar_det_state
1554  */
1555 mlan_status
wlan_11h_config_slave_radar_det(mlan_private * priv,t_bool enable)1556 wlan_11h_config_slave_radar_det(mlan_private *priv, t_bool enable)
1557 {
1558 	mlan_status ret = MLAN_STATUS_FAILURE;
1559 
1560 	/* Force disable radar detection on STA interfaces */
1561 	if (priv->adapter->dfs_repeater)
1562 		enable = MFALSE;
1563 
1564 	ENTER();
1565 	if (wlan_11h_is_dfs_slave(priv) &&
1566 	    priv->adapter->init_para.dfs_slave_radar_det_en) {
1567 		priv->adapter->state_11h.slave_radar_det_enable_pending =
1568 			enable;
1569 		ret = MLAN_STATUS_SUCCESS;
1570 	}
1571 	LEAVE();
1572 	return ret;
1573 }
1574 
1575 /**
1576  *  @brief Checks all interfaces and determines if radar_detect flag states
1577  *         have/should be changed.  If so, sends SNMP_MIB 11H command to FW.
1578  *         Call this function on any interface enable/disable/channel change.
1579  *
1580  *  @param pmpriv  Pointer to mlan_private structure
1581  *
1582  *  @return        MLAN_STATUS_SUCCESS (update or not)
1583  *              or MLAN_STATUS_FAILURE (cmd failure)
1584  *
1585  *  @sa    wlan_11h_check_radar_det_state
1586  */
1587 mlan_status
wlan_11h_check_update_radar_det_state(mlan_private * pmpriv)1588 wlan_11h_check_update_radar_det_state(mlan_private *pmpriv)
1589 {
1590 	t_u32 new_radar_det_state = 0;
1591 	t_u32 mib_11h = 0;
1592 	mlan_status ret = MLAN_STATUS_SUCCESS;
1593 
1594 	ENTER();
1595 
1596 	if (wlan_11h_check_radar_det_state(pmpriv->adapter,
1597 					   &new_radar_det_state)) {
1598 		PRINTM(MCMD_D, "%s: radar_det_state being updated.\n",
1599 		       __func__);
1600 
1601 		mib_11h |= new_radar_det_state;
1602 		/* keep priv's existing 11h state */
1603 		if (pmpriv->intf_state_11h.is_11h_active)
1604 			mib_11h |= ENABLE_11H_MASK;
1605 
1606 		/* Send cmd to FW to enable/disable 11h function in firmware */
1607 		ret = wlan_prepare_cmd(pmpriv,
1608 				       HostCmd_CMD_802_11_SNMP_MIB,
1609 				       HostCmd_ACT_GEN_SET,
1610 				       Dot11H_i, MNULL, &mib_11h);
1611 		if (ret)
1612 			ret = MLAN_STATUS_FAILURE;
1613 	}
1614 
1615 	/* updated state sent OR no change, thus no longer pending */
1616 	pmpriv->adapter->state_11h.master_radar_det_enable_pending = MFALSE;
1617 	pmpriv->adapter->state_11h.slave_radar_det_enable_pending = MFALSE;
1618 
1619 	LEAVE();
1620 	return ret;
1621 }
1622 
1623 /**
1624  *  @brief Query 11h firmware enabled state.
1625  *
1626  *  Return whether the firmware currently has 11h extensions enabled
1627  *
1628  *  @param priv  Private driver information structure
1629  *
1630  *  @return
1631  *    - MTRUE if 11h has been activated in the firmware
1632  *    - MFALSE otherwise
1633  *
1634  *  @sa wlan_11h_activate
1635  */
1636 t_bool
wlan_11h_is_active(mlan_private * priv)1637 wlan_11h_is_active(mlan_private *priv)
1638 {
1639 	ENTER();
1640 	LEAVE();
1641 	return priv->intf_state_11h.is_11h_active;
1642 }
1643 
1644 /**
1645  *  @brief Enable the transmit interface and record the state.
1646  *
1647  *  @param priv  Private driver information structure
1648  *
1649  *  @return      N/A
1650  */
1651 t_void
wlan_11h_tx_enable(mlan_private * priv)1652 wlan_11h_tx_enable(mlan_private *priv)
1653 {
1654 	ENTER();
1655 	if (priv->intf_state_11h.tx_disabled) {
1656 		if (priv->media_connected == MTRUE) {
1657 			wlan_recv_event(priv, MLAN_EVENT_ID_FW_START_TX, MNULL);
1658 			priv->intf_state_11h.tx_disabled = MFALSE;
1659 		}
1660 	}
1661 	LEAVE();
1662 }
1663 
1664 /**
1665  *  @brief Disable the transmit interface and record the state.
1666  *
1667  *  @param priv  Private driver information structure
1668  *
1669  *  @return      N/A
1670  */
1671 t_void
wlan_11h_tx_disable(mlan_private * priv)1672 wlan_11h_tx_disable(mlan_private *priv)
1673 {
1674 	ENTER();
1675 	if (!priv->intf_state_11h.tx_disabled) {
1676 		if (priv->media_connected == MTRUE) {
1677 			priv->intf_state_11h.tx_disabled = MTRUE;
1678 			wlan_recv_event(priv, MLAN_EVENT_ID_FW_STOP_TX, MNULL);
1679 		}
1680 	}
1681 	LEAVE();
1682 }
1683 
1684 /**
1685  *  @brief Enable or Disable the 11h extensions in the firmware
1686  *
1687  *  @param priv         Private driver information structure
1688  *  @param pioctl_buf   A pointer to MLAN IOCTL Request buffer
1689  *  @param flag         Enable 11h if MTRUE, disable otherwise
1690  *
1691  *  @return      MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
1692  */
1693 mlan_status
wlan_11h_activate(mlan_private * priv,t_void * pioctl_buf,t_bool flag)1694 wlan_11h_activate(mlan_private *priv, t_void *pioctl_buf, t_bool flag)
1695 {
1696 	t_u32 enable = flag & ENABLE_11H_MASK;
1697 	mlan_status ret = MLAN_STATUS_SUCCESS;
1698 
1699 	ENTER();
1700 	/* add bits for master/slave radar detect into enable. */
1701 	enable |= wlan_11h_get_current_radar_detect_flags(priv->adapter);
1702 
1703 	/* Whenever repeater mode is on make sure
1704 	 * we do not enable master or slave radar det mode.
1705 	 * HW will not detect radar in dfs_repeater mode.
1706 	 */
1707 	if (priv->adapter->dfs_repeater) {
1708 		enable &= ~(MASTER_RADAR_DET_MASK | SLAVE_RADAR_DET_MASK);
1709 	}
1710 
1711 	/*
1712 	 * Send cmd to FW to enable/disable 11h function in firmware
1713 	 */
1714 	ret = wlan_prepare_cmd(priv,
1715 			       HostCmd_CMD_802_11_SNMP_MIB,
1716 			       HostCmd_ACT_GEN_SET,
1717 			       Dot11H_i, (t_void *)pioctl_buf, &enable);
1718 	if (ret)
1719 		ret = MLAN_STATUS_FAILURE;
1720 	else
1721 		/* Set boolean flag in driver 11h state */
1722 		priv->intf_state_11h.is_11h_active = flag;
1723 
1724 	PRINTM(MINFO, "11h: %s\n", flag ? "Activate" : "Deactivate");
1725 
1726 	LEAVE();
1727 	return ret;
1728 }
1729 
1730 /**
1731  *  @brief Initialize the 11h parameters and enable 11h when starting an IBSS
1732  *
1733  *  @param adapter mlan_adapter structure
1734  *
1735  *  @return      N/A
1736  */
1737 t_void
wlan_11h_init(mlan_adapter * adapter)1738 wlan_11h_init(mlan_adapter *adapter)
1739 {
1740 	wlan_11h_device_state_t *pstate_11h = &adapter->state_11h;
1741 	IEEEtypes_Quiet_t *pquiet = &adapter->state_11h.quiet_ie;
1742 	wlan_dfs_device_state_t *pstate_dfs = &adapter->state_dfs;
1743 	wlan_radar_det_hndlg_state_t *pstate_rdh = &adapter->state_rdh;
1744 #ifdef DFS_TESTING_SUPPORT
1745 	wlan_dfs_testing_settings_t *pdfs_test = &adapter->dfs_test_params;
1746 #endif
1747 
1748 	ENTER();
1749 
1750 	/* Initialize 11H struct */
1751 	pstate_11h->usr_def_power_constraint = WLAN_11H_TPC_POWERCONSTRAINT;
1752 	pstate_11h->min_tx_power_capability = WLAN_11H_TPC_POWERCAPABILITY_MIN;
1753 	pstate_11h->max_tx_power_capability = WLAN_11H_TPC_POWERCAPABILITY_MAX;
1754 
1755 	pstate_11h->recvd_chanswann_event = MFALSE;
1756 	pstate_11h->master_radar_det_enable_pending = MFALSE;
1757 	pstate_11h->slave_radar_det_enable_pending = MFALSE;
1758 	pstate_11h->is_master_radar_det_active = MFALSE;
1759 	pstate_11h->is_slave_radar_det_active = MFALSE;
1760 
1761 	/*Initialize quiet_ie */
1762 	memset(adapter, pquiet, 0, sizeof(IEEEtypes_Quiet_t));
1763 	pquiet->element_id = QUIET;
1764 	pquiet->len =
1765 		(sizeof(pquiet->quiet_count) + sizeof(pquiet->quiet_period)
1766 		 + sizeof(pquiet->quiet_duration)
1767 		 + sizeof(pquiet->quiet_offset));
1768 
1769 	/* Initialize DFS struct */
1770 	pstate_dfs->dfs_check_pending = MFALSE;
1771 	pstate_dfs->dfs_radar_found = MFALSE;
1772 	pstate_dfs->dfs_check_channel = 0;
1773 	pstate_dfs->dfs_report_time_sec = 0;
1774 	util_init_list((pmlan_linked_list)&pstate_dfs->dfs_ts_head);
1775 
1776 	/* Initialize RDH struct */
1777 	pstate_rdh->stage = RDH_OFF;
1778 	pstate_rdh->priv_list_count = 0;
1779 	pstate_rdh->priv_curr_idx = 0;
1780 	pstate_rdh->curr_channel = 0;
1781 	pstate_rdh->new_channel = 0;
1782 	memset(adapter, &(pstate_rdh->uap_band_cfg), 0,
1783 	       sizeof(pstate_rdh->uap_band_cfg));
1784 	pstate_rdh->max_bcn_dtim_ms = 0;
1785 	memset(adapter, pstate_rdh->priv_list, 0,
1786 	       sizeof(pstate_rdh->priv_list));
1787 
1788 	/* Initialize dfs channel switch count */
1789 #define DFS_CS_COUNT 5
1790 	adapter->dfs_cs_count = DFS_CS_COUNT;
1791 
1792 #ifdef DFS_TESTING_SUPPORT
1793 	/* Initialize DFS testing struct */
1794 	pdfs_test->user_cac_period_msec = 0;
1795 	pdfs_test->user_nop_period_sec = 0;
1796 	pdfs_test->no_channel_change_on_radar = MFALSE;
1797 	pdfs_test->fixed_new_channel_on_radar = 0;
1798 #endif
1799 
1800 	LEAVE();
1801 }
1802 
1803 /**
1804  *  @brief Cleanup for the 11h parameters that allocated memory, etc.
1805  *
1806  *  @param adapter mlan_adapter structure
1807  *
1808  *  @return      N/A
1809  */
1810 t_void
wlan_11h_cleanup(mlan_adapter * adapter)1811 wlan_11h_cleanup(mlan_adapter *adapter)
1812 {
1813 	wlan_dfs_device_state_t *pstate_dfs = &adapter->state_dfs;
1814 	wlan_dfs_timestamp_t *pdfs_ts;
1815 
1816 	ENTER();
1817 
1818 	/* cleanup dfs_timestamp list */
1819 	pdfs_ts = (wlan_dfs_timestamp_t *)util_peek_list(adapter->pmoal_handle,
1820 							 &pstate_dfs->
1821 							 dfs_ts_head, MNULL,
1822 							 MNULL);
1823 	while (pdfs_ts) {
1824 		util_unlink_list(adapter->pmoal_handle,
1825 				 &pstate_dfs->dfs_ts_head,
1826 				 (pmlan_linked_list)pdfs_ts, MNULL, MNULL);
1827 		adapter->callbacks.moal_mfree(adapter->pmoal_handle,
1828 					      (t_u8 *)pdfs_ts);
1829 
1830 		pdfs_ts =
1831 			(wlan_dfs_timestamp_t *)util_peek_list(adapter->
1832 							       pmoal_handle,
1833 							       &pstate_dfs->
1834 							       dfs_ts_head,
1835 							       MNULL, MNULL);
1836 	}
1837 
1838 	LEAVE();
1839 }
1840 
1841 /**
1842  *  @brief Initialize the 11h parameters and enable 11h when starting an IBSS
1843  *
1844  *  @param pmpriv Pointer to mlan_private structure
1845  *
1846  *  @return      N/A
1847  */
1848 t_void
wlan_11h_priv_init(mlan_private * pmpriv)1849 wlan_11h_priv_init(mlan_private *pmpriv)
1850 {
1851 	wlan_11h_interface_state_t *pistate_11h = &pmpriv->intf_state_11h;
1852 
1853 	ENTER();
1854 
1855 	pistate_11h->is_11h_enabled = MTRUE;
1856 	pistate_11h->is_11h_active = MFALSE;
1857 	pistate_11h->adhoc_auto_sel_chan = MTRUE;
1858 	pistate_11h->tx_disabled = MFALSE;
1859 	pistate_11h->dfs_slave_csa_chan = 0;
1860 	pistate_11h->dfs_slave_csa_expire_at_sec = 0;
1861 
1862 	LEAVE();
1863 }
1864 
1865 /**
1866  *  @brief Retrieve a randomly selected starting channel if needed for 11h
1867  *
1868  *  If 11h is enabled and an A-Band channel start band preference
1869  *    configured in the driver, the start channel must be random in order
1870  *    to meet with
1871  *
1872  *  @param priv  Private driver information structure
1873  *
1874  *  @return      Starting channel
1875  */
1876 t_u8
wlan_11h_get_adhoc_start_channel(mlan_private * priv)1877 wlan_11h_get_adhoc_start_channel(mlan_private *priv)
1878 {
1879 	t_u8 start_chn;
1880 	mlan_adapter *adapter = priv->adapter;
1881 	t_u32 region;
1882 	t_u32 rand_entry;
1883 	region_chan_t *chn_tbl;
1884 	t_u8 rand_tries = 0;
1885 
1886 	ENTER();
1887 
1888 	/*
1889 	 * Set start_chn to the Default.  Used if 11h is disabled or the band
1890 	 *   does not require 11h support.
1891 	 */
1892 	start_chn = DEFAULT_AD_HOC_CHANNEL;
1893 
1894 	/*
1895 	 * Check that we are looking for a channel in the A Band
1896 	 */
1897 	if ((adapter->adhoc_start_band & BAND_A)
1898 	    || (adapter->adhoc_start_band & BAND_AN)
1899 		) {
1900 		/*
1901 		 * Set default to the A Band default.
1902 		 * Used if random selection fails
1903 		 * or if 11h is not enabled
1904 		 */
1905 		start_chn = DEFAULT_AD_HOC_CHANNEL_A;
1906 
1907 		/*
1908 		 * Check that 11h is enabled in the driver
1909 		 */
1910 		if (wlan_11h_is_enabled(priv)) {
1911 			/*
1912 			 * Search the region_channel tables for a channel table
1913 			 *   that is marked for the A Band.
1914 			 */
1915 			for (region = 0; (region < MAX_REGION_CHANNEL_NUM);
1916 			     region++) {
1917 				chn_tbl = &adapter->region_channel[region];
1918 
1919 				/* Check if table is valid and marked for A Band */
1920 				if (chn_tbl->valid
1921 				    && chn_tbl->region == adapter->region_code
1922 				    && chn_tbl->band & BAND_A) {
1923 					/*
1924 					 * Set the start channel.  Get a random
1925 					 * number and use it to pick an entry
1926 					 * in the table between 0 and the number
1927 					 * of channels in the table (NumCFP).
1928 					 */
1929 					do {
1930 						rand_entry =
1931 							wlan_11h_get_random_num
1932 							(adapter) %
1933 							chn_tbl->num_cfp;
1934 						start_chn =
1935 							(t_u8)chn_tbl->
1936 							pcfp[rand_entry].
1937 							channel;
1938 					} while ((wlan_11h_is_channel_under_nop
1939 						  (adapter, start_chn) ||
1940 						  ((adapter->state_rdh.stage ==
1941 						    RDH_GET_INFO_CHANNEL) &&
1942 						   wlan_11h_radar_detect_required
1943 						   (priv, start_chn)))
1944 						 && (++rand_tries <
1945 						     MAX_RANDOM_CHANNEL_RETRIES));
1946 				}
1947 			}
1948 		}
1949 	}
1950 
1951 	PRINTM(MINFO, "11h: %s: AdHoc Channel set to %u\n",
1952 	       wlan_11h_is_enabled(priv) ? "Enabled" : "Disabled", start_chn);
1953 
1954 	LEAVE();
1955 	return start_chn;
1956 }
1957 
1958 /**
1959  *  @brief Retrieve channel closed for operation by Channel Switch Announcement
1960  *
1961  *  After receiving CSA, we must not transmit in any form on the original
1962  *    channel for a certain duration.  This checks the time, and returns
1963  *    the channel if valid.
1964  *
1965  *  @param priv  Private driver information structure
1966  *
1967  *  @return      Closed channel, else 0
1968  */
1969 t_u8
wlan_11h_get_csa_closed_channel(mlan_private * priv)1970 wlan_11h_get_csa_closed_channel(mlan_private *priv)
1971 {
1972 	t_u32 sec, usec;
1973 
1974 	ENTER();
1975 
1976 	if (!priv->intf_state_11h.dfs_slave_csa_chan) {
1977 		LEAVE();
1978 		return 0;
1979 	}
1980 
1981 	/* have csa channel, check if expired or not */
1982 	priv->adapter->callbacks.moal_get_system_time(priv->adapter->
1983 						      pmoal_handle, &sec,
1984 						      &usec);
1985 	if (sec > priv->intf_state_11h.dfs_slave_csa_expire_at_sec) {
1986 		/* expired:  remove channel from blacklist table, and clear vars */
1987 		wlan_set_chan_blacklist(priv, BAND_A,
1988 					priv->intf_state_11h.dfs_slave_csa_chan,
1989 					MFALSE);
1990 		priv->intf_state_11h.dfs_slave_csa_chan = 0;
1991 		priv->intf_state_11h.dfs_slave_csa_expire_at_sec = 0;
1992 	}
1993 
1994 	LEAVE();
1995 	return priv->intf_state_11h.dfs_slave_csa_chan;
1996 }
1997 
1998 /**
1999  *  @brief Check if the current region's regulations require the input channel
2000  *         to be scanned for radar.
2001  *
2002  *  Based on statically defined requirements for sub-bands per regulatory
2003  *    agency requirements.
2004  *
2005  *  Used in adhoc start to determine if channel availability check is required
2006  *
2007  *  @param priv    Private driver information structure
2008  *  @param channel Channel to determine radar detection requirements
2009  *
2010  *  @return
2011  *    - MTRUE if radar detection is required
2012  *    - MFALSE otherwise
2013  */
2014 /**  @sa wlan_11h_issue_radar_detect
2015  */
2016 t_bool
wlan_11h_radar_detect_required(mlan_private * priv,t_u8 channel)2017 wlan_11h_radar_detect_required(mlan_private *priv, t_u8 channel)
2018 {
2019 	t_bool required = MFALSE;
2020 
2021 	ENTER();
2022 
2023 	/*
2024 	 * No checks for 11h or measurement code being enabled is placed here
2025 	 * since regulatory requirements exist whether we support them or not.
2026 	 */
2027 
2028 	required = wlan_get_cfp_radar_detect(priv, channel);
2029 
2030 	if (!priv->adapter->region_code)
2031 		PRINTM(MINFO, "11h: Radar detection in CFP code[BG:%#x, A:%#x] "
2032 		       "is %srequired for channel %d\n",
2033 		       priv->adapter->cfp_code_bg, priv->adapter->cfp_code_a,
2034 		       (required ? "" : "not "), channel);
2035 	else
2036 		PRINTM(MINFO, "11h: Radar detection in region %#02x "
2037 		       "is %srequired for channel %d\n",
2038 		       priv->adapter->region_code, (required ? "" : "not "),
2039 		       channel);
2040 
2041 	if (required == MTRUE && priv->media_connected == MTRUE
2042 	    && priv->curr_bss_params.bss_descriptor.channel == channel) {
2043 		required = MFALSE;
2044 
2045 		PRINTM(MINFO, "11h: Radar detection not required. "
2046 		       "Already operating on the channel\n");
2047 	}
2048 
2049 	LEAVE();
2050 	return required;
2051 }
2052 
2053 /**
2054  *  @brief Perform a radar measurement if required on given channel
2055  *
2056  *  Check to see if the provided channel requires a channel availability
2057  *    check (60 second radar detection measurement).  If required, perform
2058  *    measurement, stalling calling thread until the measurement completes
2059  *    and then report result.
2060  *
2061  *  Used when starting an adhoc or AP network.
2062  *
2063  *  @param priv         Private driver information structure
2064  *  @param pioctl_req   Pointer to IOCTL request buffer
2065  *  @param channel      Channel on which to perform radar measurement
2066  *  @param bandcfg      Channel Band config structure
2067  *
2068  *  @return
2069  *    - MTRUE  if radar measurement request was successfully issued
2070  *    - MFALSE if radar detection is not required
2071  *    - < 0 for error during radar detection (if performed)
2072  *
2073  *  @sa wlan_11h_radar_detect_required
2074  */
2075 t_s32
wlan_11h_issue_radar_detect(mlan_private * priv,pmlan_ioctl_req pioctl_req,t_u8 channel,Band_Config_t bandcfg)2076 wlan_11h_issue_radar_detect(mlan_private *priv,
2077 			    pmlan_ioctl_req pioctl_req,
2078 			    t_u8 channel, Band_Config_t bandcfg)
2079 {
2080 	t_s32 ret;
2081 	HostCmd_DS_CHAN_RPT_REQ chan_rpt_req;
2082 	mlan_adapter *pmadapter = priv->adapter;
2083 	mlan_ds_11h_cfg *ds_11hcfg = MNULL;
2084 
2085 	ENTER();
2086 
2087 	ret = wlan_11h_radar_detect_required(priv, channel);
2088 	if (ret) {
2089 		/* Prepare and issue CMD_CHAN_RPT_REQ. */
2090 		memset(priv->adapter, &chan_rpt_req, 0x00,
2091 		       sizeof(chan_rpt_req));
2092 
2093 		chan_rpt_req.chan_desc.startFreq = START_FREQ_11A_BAND;
2094 
2095 		if (pmadapter->chanrpt_param_bandcfg) {
2096 			chan_rpt_req.chan_desc.bandcfg = bandcfg;
2097 		} else {
2098 			*((t_u8 *)&chan_rpt_req.chan_desc.bandcfg) =
2099 				(t_u8)bandcfg.chanWidth;
2100 		}
2101 
2102 		chan_rpt_req.chan_desc.chanNum = channel;
2103 		chan_rpt_req.millisec_dwell_time =
2104 			WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION;
2105 
2106 		/* ETSI new requirement for ch 120, 124 and 128 */
2107 		if (wlan_is_etsi_country(pmadapter, pmadapter->country_code)) {
2108 			if (channel == 120 || channel == 124 || channel == 128) {
2109 				chan_rpt_req.millisec_dwell_time =
2110 					WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION *
2111 					10;
2112 			}
2113 			if (channel == 116 &&
2114 			    ((bandcfg.chanWidth == CHAN_BW_40MHZ)
2115 			    )) {
2116 				chan_rpt_req.millisec_dwell_time =
2117 					WLAN_11H_CHANNEL_AVAIL_CHECK_DURATION *
2118 					10;
2119 			}
2120 		}
2121 
2122 		/* Save dwell time information to be used later in moal */
2123 		if (pioctl_req) {
2124 			ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
2125 			if (!ds_11hcfg->param.chan_rpt_req.host_based) {
2126 				ds_11hcfg->param.chan_rpt_req.
2127 					millisec_dwell_time =
2128 					chan_rpt_req.millisec_dwell_time;
2129 			}
2130 		}
2131 #ifdef DFS_TESTING_SUPPORT
2132 		if (priv->adapter->dfs_test_params.user_cac_period_msec) {
2133 			PRINTM(MCMD_D,
2134 			       "dfs_testing - user CAC period=%d (msec)\n",
2135 			       priv->adapter->dfs_test_params.
2136 			       user_cac_period_msec);
2137 			chan_rpt_req.millisec_dwell_time =
2138 				priv->adapter->dfs_test_params.
2139 				user_cac_period_msec;
2140 		}
2141 #endif
2142 
2143 		PRINTM(MMSG, "11h: issuing DFS Radar check for channel=%d."
2144 		       "  Please wait for response...\n", channel);
2145 
2146 		ret = wlan_prepare_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST,
2147 				       HostCmd_ACT_GEN_SET, 0,
2148 				       (t_void *)pioctl_req,
2149 				       (t_void *)&chan_rpt_req);
2150 	}
2151 
2152 	LEAVE();
2153 	return ret;
2154 }
2155 
2156 /**
2157  *  @brief Checks if a radar measurement was performed on channel,
2158  *         and if so, whether radar was detected on it.
2159  *
2160  *  Used when starting an adhoc network.
2161  *
2162  *  @param priv         Private driver information structure
2163  *  @param chan         Channel to check upon
2164  *
2165  *  @return
2166  *    - MLAN_STATUS_SUCCESS if no radar on channel
2167  *    - MLAN_STATUS_FAILURE if radar was found on channel
2168  *    - (TBD??) MLAN_STATUS_PENDING if radar report NEEDS TO BE REISSUED
2169  *
2170  *  @sa wlan_11h_issue_radar_detect
2171  *  @sa wlan_11h_process_start
2172  */
2173 mlan_status
wlan_11h_check_chan_report(mlan_private * priv,t_u8 chan)2174 wlan_11h_check_chan_report(mlan_private *priv, t_u8 chan)
2175 {
2176 	mlan_status ret = MLAN_STATUS_SUCCESS;
2177 	wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
2178 	t_u32 sec, usec;
2179 
2180 	ENTER();
2181 
2182 	/* check report we hold is valid or not */
2183 	priv->adapter->callbacks.moal_get_system_time(priv->adapter->
2184 						      pmoal_handle, &sec,
2185 						      &usec);
2186 
2187 	PRINTM(MINFO, "11h: %s()\n", __func__);
2188 	PRINTM(MINFO, "- sec_now=%d, sec_report=%d.\n",
2189 	       sec, pstate_dfs->dfs_report_time_sec);
2190 	PRINTM(MINFO, "- rpt_channel=%d, rpt_radar=%d.\n",
2191 	       pstate_dfs->dfs_check_channel, pstate_dfs->dfs_radar_found);
2192 
2193 	if ((!pstate_dfs->dfs_check_pending) &&
2194 	    (chan == pstate_dfs->dfs_check_channel) &&
2195 	    ((sec - pstate_dfs->dfs_report_time_sec) <
2196 	     MAX_DFS_REPORT_USABLE_AGE_SEC)) {
2197 		/* valid and not out-dated, check if radar */
2198 		if (pstate_dfs->dfs_radar_found) {
2199 			PRINTM(MMSG, "Radar was detected on channel %d.\n",
2200 			       chan);
2201 			ret = MLAN_STATUS_FAILURE;
2202 		}
2203 	} else {
2204 		/* When Cache is not valid. This is required during extending cache
2205 		 * validity during bss_stop
2206 		 */
2207 		pstate_dfs->dfs_check_channel = 0;
2208 
2209 		/*TODO:  reissue report request if not pending.
2210 		 *       BUT HOW to make the code wait for it???
2211 		 * For now, just fail since we don't have the info. */
2212 
2213 		ret = MLAN_STATUS_PENDING;
2214 	}
2215 
2216 	LEAVE();
2217 	return ret;
2218 }
2219 
2220 /**
2221  *  @brief Process an TLV buffer for a pending BSS Adhoc start command.
2222  *
2223  *  Activate 11h functionality in the firmware if driver has is enabled
2224  *    for 11h (configured by the application via IOCTL).
2225  *
2226  *  @param priv          Private driver information structure
2227  *  @param ppbuffer      Output parameter: Pointer to the TLV output buffer,
2228  *                       modified on return to point after the appended 11h TLVs
2229  *  @param pcap_info     Pointer to the capability info for the BSS to join
2230  *  @param channel       Channel on which we are starting the IBSS
2231  *  @param p11h_bss_info Input/Output parameter: Pointer to the 11h BSS
2232  *                       information for this network that we are establishing.
2233  *                       11h sensed flag set on output if warranted.
2234  *
2235  *  @return
2236  *      - MLAN_STATUS_SUCCESS if 11h is disabled
2237  *      - Integer number of bytes appended to the TLV output buffer (ppbuffer)
2238  *      - < 0 for error (e.g. radar detected on channel)
2239  */
2240 t_s32
wlan_11h_process_start(mlan_private * priv,t_u8 ** ppbuffer,IEEEtypes_CapInfo_t * pcap_info,t_u32 channel,wlan_11h_bss_info_t * p11h_bss_info)2241 wlan_11h_process_start(mlan_private *priv,
2242 		       t_u8 **ppbuffer,
2243 		       IEEEtypes_CapInfo_t *pcap_info,
2244 		       t_u32 channel, wlan_11h_bss_info_t *p11h_bss_info)
2245 {
2246 	mlan_adapter *adapter = priv->adapter;
2247 	t_s32 ret = MLAN_STATUS_SUCCESS;
2248 	t_bool is_dfs_chan = MFALSE;
2249 
2250 	ENTER();
2251 	if (wlan_11h_is_enabled(priv)
2252 	    && ((adapter->adhoc_start_band & BAND_A)
2253 		|| (adapter->adhoc_start_band & BAND_AN)
2254 	    )
2255 		) {
2256 		if (!wlan_11d_is_enabled(priv)) {
2257 			/* No use having 11h enabled without 11d enabled */
2258 			wlan_11d_enable(priv, MNULL, ENABLE_11D);
2259 #ifdef STA_SUPPORT
2260 			wlan_11d_create_dnld_countryinfo(priv,
2261 							 adapter->
2262 							 adhoc_start_band);
2263 #endif
2264 		}
2265 
2266 		/*
2267 		 * Activate 11h functions in firmware,
2268 		 * turns on capability bit
2269 		 */
2270 		wlan_11h_activate(priv, MNULL, MTRUE);
2271 		pcap_info->spectrum_mgmt = MTRUE;
2272 
2273 		/* If using a DFS channel, enable radar detection. */
2274 		is_dfs_chan = wlan_11h_radar_detect_required(priv, channel);
2275 		if (is_dfs_chan) {
2276 			if (!wlan_11h_is_master_radar_det_active(priv))
2277 				wlan_11h_config_master_radar_det(priv, MTRUE);
2278 		}
2279 		wlan_11h_check_update_radar_det_state(priv);
2280 
2281 		/* Set flag indicating this BSS we are starting is using 11h */
2282 		p11h_bss_info->sensed_11h = MTRUE;
2283 
2284 		if (is_dfs_chan) {
2285 			/* check if this channel is under NOP */
2286 			if (wlan_11h_is_channel_under_nop(adapter, channel))
2287 				ret = MLAN_STATUS_FAILURE;
2288 			/* check last channel report, if this channel is free of radar */
2289 			if (ret == MLAN_STATUS_SUCCESS)
2290 				ret = wlan_11h_check_chan_report(priv, channel);
2291 		}
2292 		if (ret == MLAN_STATUS_SUCCESS)
2293 			ret = wlan_11h_process_adhoc(priv, ppbuffer, channel,
2294 						     MNULL);
2295 		else
2296 			ret = MLAN_STATUS_FAILURE;
2297 	} else {
2298 		/* Deactivate 11h functions in the firmware */
2299 		wlan_11h_activate(priv, MNULL, MFALSE);
2300 		pcap_info->spectrum_mgmt = MFALSE;
2301 		wlan_11h_check_update_radar_det_state(priv);
2302 	}
2303 	LEAVE();
2304 	return ret;
2305 }
2306 
2307 /**
2308  *  @brief Process an TLV buffer for a pending BSS Join command for
2309  *         both adhoc and infra networks
2310  *
2311  *  The TLV command processing for a BSS join for either adhoc or
2312  *    infrastructure network is performed with this function.  The
2313  *    capability bits are inspected for the IBSS flag and the appropriate
2314  *    local routines are called to setup the necessary TLVs.
2315  *
2316  *  Activate 11h functionality in the firmware if the spectrum management
2317  *    capability bit is found in the network information for the BSS we are
2318  *    joining.
2319  *
2320  *  @param priv          Private driver information structure
2321  *  @param ppbuffer      Output parameter: Pointer to the TLV output buffer,
2322  *                       modified on return to point after the appended 11h TLVs
2323  *  @param pcap_info     Pointer to the capability info for the BSS to join
2324  *  @param band          Band on which we are joining the BSS
2325  *  @param channel       Channel on which we are joining the BSS
2326  *  @param p11h_bss_info Pointer to the 11h BSS information for this
2327  *                       network that was parsed out of the scan response.
2328  *
2329  *  @return              Integer number of bytes appended to the TLV output
2330  *                       buffer (ppbuffer), MLAN_STATUS_FAILURE (-1),
2331  *                       or MLAN_STATUS_SUCCESS (0)
2332  */
2333 t_s32
wlan_11h_process_join(mlan_private * priv,t_u8 ** ppbuffer,IEEEtypes_CapInfo_t * pcap_info,t_u8 band,t_u32 channel,wlan_11h_bss_info_t * p11h_bss_info)2334 wlan_11h_process_join(mlan_private *priv,
2335 		      t_u8 **ppbuffer,
2336 		      IEEEtypes_CapInfo_t *pcap_info,
2337 		      t_u8 band,
2338 		      t_u32 channel, wlan_11h_bss_info_t *p11h_bss_info)
2339 {
2340 	t_s32 ret = 0;
2341 
2342 	ENTER();
2343 
2344 	if (priv->media_connected == MTRUE) {
2345 		if (wlan_11h_is_active(priv) == p11h_bss_info->sensed_11h) {
2346 			/*
2347 			 * Assume DFS parameters are the same for roaming as long as
2348 			 * the current & next APs have the same spectrum mgmt capability
2349 			 * bit setting
2350 			 */
2351 			ret = MLAN_STATUS_SUCCESS;
2352 
2353 		} else {
2354 			/* No support for roaming between DFS/non-DFS yet */
2355 			ret = MLAN_STATUS_FAILURE;
2356 		}
2357 
2358 		LEAVE();
2359 		return ret;
2360 	}
2361 
2362 	if (p11h_bss_info->sensed_11h) {
2363 		if (!wlan_11d_is_enabled(priv)) {
2364 			/* No use having 11h enabled without 11d enabled */
2365 			wlan_11d_enable(priv, MNULL, ENABLE_11D);
2366 #ifdef STA_SUPPORT
2367 			wlan_11d_parse_dnld_countryinfo(priv,
2368 							priv->
2369 							pattempted_bss_desc);
2370 #endif
2371 		}
2372 		/*
2373 		 * Activate 11h functions in firmware,
2374 		 * turns on capability bit
2375 		 */
2376 		wlan_11h_activate(priv, MNULL, MTRUE);
2377 		pcap_info->spectrum_mgmt = MTRUE;
2378 
2379 		/* If using a DFS channel, enable radar detection. */
2380 		if ((band & BAND_A) &&
2381 		    wlan_11h_radar_detect_required(priv, channel)) {
2382 			if (!wlan_11h_is_slave_radar_det_active(priv))
2383 				wlan_11h_config_slave_radar_det(priv, MTRUE);
2384 		}
2385 		wlan_11h_check_update_radar_det_state(priv);
2386 
2387 		if (pcap_info->ibss) {
2388 			PRINTM(MINFO, "11h: Adhoc join: Sensed\n");
2389 			ret = wlan_11h_process_adhoc(priv, ppbuffer, channel,
2390 						     p11h_bss_info);
2391 		} else {
2392 			PRINTM(MINFO, "11h: Infra join: Sensed\n");
2393 			ret = wlan_11h_process_infra_join(priv, ppbuffer, band,
2394 							  channel,
2395 							  p11h_bss_info);
2396 		}
2397 	} else {
2398 		/* Deactivate 11h functions in the firmware */
2399 		wlan_11h_activate(priv, MNULL, MFALSE);
2400 		pcap_info->spectrum_mgmt = MFALSE;
2401 		wlan_11h_check_update_radar_det_state(priv);
2402 	}
2403 
2404 	LEAVE();
2405 	return ret;
2406 }
2407 
2408 /**
2409  *
2410  *  @brief  Prepare the HostCmd_DS_Command structure for an 11h command.
2411  *
2412  *  Use the Command field to determine if the command being set up is for
2413  *     11h and call one of the local command handlers accordingly for:
2414  *
2415  *        - HostCmd_CMD_802_11_TPC_ADAPT_REQ
2416  *        - HostCmd_CMD_802_11_TPC_INFO
2417  *        - HostCmd_CMD_802_11_CHAN_SW_ANN
2418  */
2419 /**       - HostCmd_CMD_CHAN_REPORT_REQUEST
2420  */
2421 /**
2422  *  @param priv      Private driver information structure
2423  *  @param pcmd_ptr  Output parameter: Pointer to the command being prepared
2424  *                   for the firmware
2425  *  @param pinfo_buf Void buffer pass through with data necessary for a
2426  *                   specific command type
2427  */
2428 /**  @return          MLAN_STATUS_SUCCESS, MLAN_STATUS_FAILURE
2429  *                    or MLAN_STATUS_PENDING
2430  */
2431 /**  @sa wlan_11h_cmd_tpc_request
2432  *  @sa wlan_11h_cmd_tpc_info
2433  *  @sa wlan_11h_cmd_chan_sw_ann
2434  */
2435 /** @sa wlan_11h_cmd_chan_report_req
2436  */
2437 mlan_status
wlan_11h_cmd_process(mlan_private * priv,HostCmd_DS_COMMAND * pcmd_ptr,const t_void * pinfo_buf)2438 wlan_11h_cmd_process(mlan_private *priv,
2439 		     HostCmd_DS_COMMAND *pcmd_ptr, const t_void *pinfo_buf)
2440 {
2441 	mlan_status ret = MLAN_STATUS_SUCCESS;
2442 
2443 	ENTER();
2444 	switch (pcmd_ptr->command) {
2445 	case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
2446 		ret = wlan_11h_cmd_tpc_request(priv, pcmd_ptr, pinfo_buf);
2447 		break;
2448 	case HostCmd_CMD_802_11_TPC_INFO:
2449 		ret = wlan_11h_cmd_tpc_info(priv, pcmd_ptr, pinfo_buf);
2450 		break;
2451 	case HostCmd_CMD_802_11_CHAN_SW_ANN:
2452 		ret = wlan_11h_cmd_chan_sw_ann(priv, pcmd_ptr, pinfo_buf);
2453 		break;
2454 	case HostCmd_CMD_CHAN_REPORT_REQUEST:
2455 		ret = wlan_11h_cmd_chan_rpt_req(priv, pcmd_ptr, pinfo_buf);
2456 		break;
2457 	default:
2458 		ret = MLAN_STATUS_FAILURE;
2459 	}
2460 
2461 	pcmd_ptr->command = wlan_cpu_to_le16(pcmd_ptr->command);
2462 	pcmd_ptr->size = wlan_cpu_to_le16(pcmd_ptr->size);
2463 
2464 	LEAVE();
2465 	return ret;
2466 }
2467 
2468 /**
2469  *  @brief Handle the command response from the firmware if from an 11h command
2470  *
2471  *  Use the Command field to determine if the command response being
2472  *    is for 11h.  Call the local command response handler accordingly for:
2473  *
2474  *        - HostCmd_CMD_802_11_TPC_ADAPT_REQ
2475  *        - HostCmd_CMD_802_11_TPC_INFO
2476  *        - HostCmd_CMD_802_11_CHAN_SW_ANN
2477  */
2478 /**       - HostCmd_CMD_CHAN_REPORT_REQUEST
2479  */
2480 /**
2481  *  @param priv  Private driver information structure
2482  *  @param resp  HostCmd_DS_COMMAND struct returned from the firmware
2483  *               command
2484  *
2485  *  @return      MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2486  */
2487 mlan_status
wlan_11h_cmdresp_process(mlan_private * priv,const HostCmd_DS_COMMAND * resp)2488 wlan_11h_cmdresp_process(mlan_private *priv, const HostCmd_DS_COMMAND *resp)
2489 {
2490 	mlan_status ret = MLAN_STATUS_SUCCESS;
2491 
2492 	ENTER();
2493 	switch (resp->command) {
2494 	case HostCmd_CMD_802_11_TPC_ADAPT_REQ:
2495 		HEXDUMP("11h: TPC REQUEST Rsp:", (t_u8 *)resp,
2496 			(t_u32)resp->size);
2497 		memcpy(priv->adapter, priv->adapter->curr_cmd->pdata_buf,
2498 		       &resp->params.tpc_req,
2499 		       sizeof(HostCmd_DS_802_11_TPC_ADAPT_REQ));
2500 		break;
2501 
2502 	case HostCmd_CMD_802_11_TPC_INFO:
2503 		HEXDUMP("11h: TPC INFO Rsp Data:", (t_u8 *)resp,
2504 			(t_u32)resp->size);
2505 		break;
2506 
2507 	case HostCmd_CMD_802_11_CHAN_SW_ANN:
2508 		PRINTM(MINFO, "11h: Ret ChSwAnn: Sz=%u, Seq=%u, Ret=%u\n",
2509 		       resp->size, resp->seq_num, resp->result);
2510 		break;
2511 
2512 	case HostCmd_CMD_CHAN_REPORT_REQUEST:
2513 		priv->adapter->state_dfs.dfs_check_priv = priv;
2514 		priv->adapter->state_dfs.dfs_check_pending = MTRUE;
2515 
2516 		if (resp->params.chan_rpt_req.millisec_dwell_time == 0) {
2517 			/* from wlan_11h_ioctl_dfs_cancel_chan_report */
2518 			priv->adapter->state_dfs.dfs_check_pending = MFALSE;
2519 			priv->adapter->state_dfs.dfs_check_priv = MNULL;
2520 			priv->adapter->state_dfs.dfs_check_channel = 0;
2521 			PRINTM(MINFO, "11h: Cancelling Chan Report \n");
2522 		} else {
2523 			PRINTM(MERROR,
2524 			       "11h: Ret ChanRptReq.  Set dfs_check_pending and wait"
2525 			       " for EVENT_CHANNEL_REPORT.\n");
2526 		}
2527 
2528 		break;
2529 
2530 	default:
2531 		ret = MLAN_STATUS_FAILURE;
2532 	}
2533 
2534 	LEAVE();
2535 	return ret;
2536 }
2537 
2538 /**
2539  *  @brief Process an element from a scan response, copy relevant info for 11h
2540  *
2541  *  @param pmadapter Pointer to mlan_adapter
2542  *  @param p11h_bss_info Output parameter: Pointer to the 11h BSS information
2543  *                       for the network that is being processed
2544  *  @param pelement      Pointer to the current IE we are inspecting for 11h
2545  *                       relevance
2546  *
2547  *  @return              MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2548  */
2549 mlan_status
wlan_11h_process_bss_elem(mlan_adapter * pmadapter,wlan_11h_bss_info_t * p11h_bss_info,const t_u8 * pelement)2550 wlan_11h_process_bss_elem(mlan_adapter *pmadapter,
2551 			  wlan_11h_bss_info_t *p11h_bss_info,
2552 			  const t_u8 *pelement)
2553 {
2554 	mlan_status ret = MLAN_STATUS_SUCCESS;
2555 	t_u8 element_len = *((t_u8 *)pelement + 1);
2556 
2557 	ENTER();
2558 	switch (*pelement) {
2559 	case POWER_CONSTRAINT:
2560 		PRINTM(MINFO, "11h: Power Constraint IE Found\n");
2561 		p11h_bss_info->sensed_11h = MTRUE;
2562 		memcpy(pmadapter, &p11h_bss_info->power_constraint, pelement,
2563 		       MIN((element_len + sizeof(IEEEtypes_Header_t)),
2564 			   sizeof(IEEEtypes_PowerConstraint_t)));
2565 		p11h_bss_info->power_constraint.len =
2566 			MIN(element_len, (sizeof(IEEEtypes_PowerConstraint_t)
2567 					  - sizeof(IEEEtypes_Header_t)));
2568 		break;
2569 
2570 	case POWER_CAPABILITY:
2571 		PRINTM(MINFO, "11h: Power Capability IE Found\n");
2572 		p11h_bss_info->sensed_11h = MTRUE;
2573 		memcpy(pmadapter, &p11h_bss_info->power_capability, pelement,
2574 		       MIN((element_len + sizeof(IEEEtypes_Header_t)),
2575 			   sizeof(IEEEtypes_PowerCapability_t)));
2576 		p11h_bss_info->power_capability.len =
2577 			MIN(element_len, (sizeof(IEEEtypes_PowerCapability_t)
2578 					  - sizeof(IEEEtypes_Header_t)));
2579 		break;
2580 
2581 	case TPC_REPORT:
2582 		PRINTM(MINFO, "11h: Tpc Report IE Found\n");
2583 		p11h_bss_info->sensed_11h = MTRUE;
2584 		memcpy(pmadapter, &p11h_bss_info->tpc_report, pelement,
2585 		       MIN((element_len + sizeof(IEEEtypes_Header_t)),
2586 			   sizeof(IEEEtypes_TPCReport_t)));
2587 		p11h_bss_info->tpc_report.len =
2588 			MIN(element_len, (sizeof(IEEEtypes_TPCReport_t)
2589 					  - sizeof(IEEEtypes_Header_t)));
2590 		break;
2591 
2592 	case CHANNEL_SWITCH_ANN:
2593 		PRINTM(MINFO, "11h: Channel Switch Ann IE Found\n");
2594 		p11h_bss_info->sensed_11h = MTRUE;
2595 		memcpy(pmadapter, &p11h_bss_info->chan_switch_ann, pelement,
2596 		       MIN((element_len + sizeof(IEEEtypes_Header_t)),
2597 			   sizeof(IEEEtypes_ChanSwitchAnn_t)));
2598 		p11h_bss_info->chan_switch_ann.len =
2599 			MIN(element_len, (sizeof(IEEEtypes_ChanSwitchAnn_t)
2600 					  - sizeof(IEEEtypes_Header_t)));
2601 		break;
2602 
2603 	case QUIET:
2604 		PRINTM(MINFO, "11h: Quiet IE Found\n");
2605 		p11h_bss_info->sensed_11h = MTRUE;
2606 		memcpy(pmadapter, &p11h_bss_info->quiet, pelement,
2607 		       MIN((element_len + sizeof(IEEEtypes_Header_t)),
2608 			   sizeof(IEEEtypes_Quiet_t)));
2609 		p11h_bss_info->quiet.len =
2610 			MIN(element_len, (sizeof(IEEEtypes_Quiet_t)
2611 					  - sizeof(IEEEtypes_Header_t)));
2612 		break;
2613 
2614 	case IBSS_DFS:
2615 		PRINTM(MINFO, "11h: Ibss Dfs IE Found\n");
2616 		p11h_bss_info->sensed_11h = MTRUE;
2617 		memcpy(pmadapter, &p11h_bss_info->ibss_dfs, pelement,
2618 		       MIN((element_len + sizeof(IEEEtypes_Header_t)),
2619 			   sizeof(IEEEtypes_IBSS_DFS_t)));
2620 		p11h_bss_info->ibss_dfs.len =
2621 			MIN(element_len, (sizeof(IEEEtypes_IBSS_DFS_t)
2622 					  - sizeof(IEEEtypes_Header_t)));
2623 		break;
2624 
2625 	case SUPPORTED_CHANNELS:
2626 	case TPC_REQUEST:
2627 		/*
2628 		 * These elements are not in beacons/probe responses.
2629 		 * Included here to cover set of enumerated 11h elements.
2630 		 */
2631 		break;
2632 
2633 	default:
2634 		ret = MLAN_STATUS_FAILURE;
2635 	}
2636 
2637 	LEAVE();
2638 	return ret;
2639 }
2640 
2641 /**
2642  *  @brief Driver handling for CHANNEL_SWITCH_ANN event
2643  *
2644  *  @param priv Pointer to mlan_private
2645  *
2646  *  @return MLAN_STATUS_SUCCESS, MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
2647  */
2648 mlan_status
wlan_11h_handle_event_chanswann(mlan_private * priv)2649 wlan_11h_handle_event_chanswann(mlan_private *priv)
2650 {
2651 	mlan_status ret = MLAN_STATUS_SUCCESS;
2652 #ifdef STA_SUPPORT
2653 	mlan_deauth_param deauth_param;
2654 #endif
2655 	t_u32 sec, usec;
2656 
2657 	ENTER();
2658 	priv->adapter->state_11h.recvd_chanswann_event = MTRUE;
2659 
2660 	/* unlikely:  clean up previous csa if still on-going */
2661 	if (priv->intf_state_11h.dfs_slave_csa_chan) {
2662 		wlan_set_chan_blacklist(priv, BAND_A,
2663 					priv->intf_state_11h.dfs_slave_csa_chan,
2664 					MFALSE);
2665 	}
2666 
2667 	/* record channel and time of occurence */
2668 	priv->intf_state_11h.dfs_slave_csa_chan =
2669 		priv->curr_bss_params.bss_descriptor.channel;
2670 	priv->adapter->callbacks.moal_get_system_time(priv->adapter->
2671 						      pmoal_handle, &sec,
2672 						      &usec);
2673 	priv->intf_state_11h.dfs_slave_csa_expire_at_sec =
2674 		sec + DFS_CHAN_MOVE_TIME;
2675 
2676 #ifdef STA_SUPPORT
2677 	/* do directed deauth.  recvd_chanswann_event flag will cause different reason code */
2678 	PRINTM(MINFO, "11h: handle_event_chanswann() - sending deauth\n");
2679 	memcpy(priv->adapter, deauth_param.mac_addr,
2680 	       &priv->curr_bss_params.bss_descriptor.mac_address,
2681 	       MLAN_MAC_ADDR_LENGTH);
2682 	deauth_param.reason_code = DEF_DEAUTH_REASON_CODE;
2683 	ret = wlan_disconnect(priv, MNULL, &deauth_param);
2684 
2685 	/* clear region table so next scan will be all passive */
2686 	PRINTM(MINFO, "11h: handle_event_chanswann() - clear region table\n");
2687 	wlan_11d_clear_parsedtable(priv);
2688 
2689 	/* add channel to blacklist table */
2690 	PRINTM(MINFO,
2691 	       "11h: handle_event_chanswann() - scan blacklist csa channel\n");
2692 	wlan_set_chan_blacklist(priv, BAND_A,
2693 				priv->intf_state_11h.dfs_slave_csa_chan, MTRUE);
2694 #endif
2695 
2696 	priv->adapter->state_11h.recvd_chanswann_event = MFALSE;
2697 	LEAVE();
2698 	return ret;
2699 }
2700 
2701 #ifdef DFS_TESTING_SUPPORT
2702 /**
2703  *  @brief 802.11h DFS Testing configuration
2704  *
2705  *  @param pmadapter    Pointer to mlan_adapter
2706  *  @param pioctl_req   Pointer to mlan_ioctl_req
2707  *
2708  *  @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2709  */
2710 mlan_status
wlan_11h_ioctl_dfs_testing(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)2711 wlan_11h_ioctl_dfs_testing(pmlan_adapter pmadapter, pmlan_ioctl_req pioctl_req)
2712 {
2713 	mlan_ds_11h_cfg *ds_11hcfg = MNULL;
2714 	mlan_ds_11h_dfs_testing *dfs_test = MNULL;
2715 	wlan_dfs_testing_settings_t *pdfs_test_params = MNULL;
2716 
2717 	ENTER();
2718 
2719 	ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
2720 	dfs_test = &ds_11hcfg->param.dfs_testing;
2721 	pdfs_test_params = &pmadapter->dfs_test_params;
2722 
2723 	if (pioctl_req->action == MLAN_ACT_GET) {
2724 		dfs_test->usr_cac_period_msec =
2725 			pdfs_test_params->user_cac_period_msec;
2726 		dfs_test->usr_nop_period_sec =
2727 			pdfs_test_params->user_nop_period_sec;
2728 		dfs_test->usr_no_chan_change =
2729 			pdfs_test_params->no_channel_change_on_radar;
2730 		dfs_test->usr_fixed_new_chan =
2731 			pdfs_test_params->fixed_new_channel_on_radar;
2732 	} else {
2733 		pdfs_test_params->user_cac_period_msec =
2734 			dfs_test->usr_cac_period_msec;
2735 		pdfs_test_params->user_nop_period_sec =
2736 			dfs_test->usr_nop_period_sec;
2737 		pdfs_test_params->no_channel_change_on_radar =
2738 			dfs_test->usr_no_chan_change;
2739 		pdfs_test_params->fixed_new_channel_on_radar =
2740 			dfs_test->usr_fixed_new_chan;
2741 	}
2742 
2743 	LEAVE();
2744 	return MLAN_STATUS_SUCCESS;
2745 }
2746 
2747 /**
2748  *  @brief 802.11h IOCTL to handle channel NOP status check
2749  *  @brief If given channel is under NOP, return a new non-dfs
2750  *  @brief channel
2751  *
2752  *  @param pmadapter    Pointer to mlan_adapter
2753  *  @param pioctl_req   Pointer to mlan_ioctl_req
2754  *
2755  *  @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2756  */
2757 mlan_status
wlan_11h_ioctl_get_channel_nop_info(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)2758 wlan_11h_ioctl_get_channel_nop_info(pmlan_adapter pmadapter,
2759 				    pmlan_ioctl_req pioctl_req)
2760 {
2761 	pmlan_private pmpriv = pmadapter->priv[pioctl_req->bss_index];
2762 	mlan_ds_11h_cfg *ds_11hcfg = MNULL;
2763 	t_s32 ret = MLAN_STATUS_FAILURE;
2764 	mlan_ds_11h_chan_nop_info *ch_nop_info = MNULL;
2765 
2766 	ENTER();
2767 
2768 	if (pioctl_req) {
2769 		ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
2770 		ch_nop_info = &ds_11hcfg->param.ch_nop_info;
2771 
2772 		if (pioctl_req->action == MLAN_ACT_GET) {
2773 			ch_nop_info->chan_under_nop =
2774 				wlan_11h_is_channel_under_nop(pmadapter,
2775 							      ch_nop_info->
2776 							      curr_chan);
2777 			if (ch_nop_info->chan_under_nop) {
2778 				wlan_11h_switch_non_dfs_chan(pmpriv,
2779 							     &ch_nop_info->
2780 							     new_chan.channel);
2781 				if (ch_nop_info->chan_width == CHAN_BW_40MHZ)
2782 					wlan_11h_update_bandcfg(&ch_nop_info->
2783 								new_chan.
2784 								bandcfg,
2785 								ch_nop_info->
2786 								new_chan.
2787 								channel);
2788 			}
2789 		}
2790 		ret = MLAN_STATUS_SUCCESS;
2791 	}
2792 
2793 	LEAVE();
2794 	return ret;
2795 }
2796 #endif /* DFS_TESTING_SUPPORT */
2797 
2798 /**
2799  *  @brief 802.11h DFS Channel Switch Count Configuration
2800  *
2801  *  @param pmadapter    Pointer to mlan_adapter
2802  *  @param pioctl_req   Pointer to mlan_ioctl_req
2803  *
2804  *  @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2805  */
2806 mlan_status
wlan_11h_ioctl_chan_switch_count(pmlan_adapter pmadapter,pmlan_ioctl_req pioctl_req)2807 wlan_11h_ioctl_chan_switch_count(pmlan_adapter pmadapter,
2808 				 pmlan_ioctl_req pioctl_req)
2809 {
2810 	mlan_ds_11h_cfg *ds_11hcfg = MNULL;
2811 	t_s32 ret = MLAN_STATUS_FAILURE;
2812 
2813 	ENTER();
2814 
2815 	if (pioctl_req) {
2816 		ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
2817 
2818 		if (pioctl_req->action == MLAN_ACT_GET) {
2819 			ds_11hcfg->param.cs_count = pmadapter->dfs_cs_count;
2820 		} else {
2821 			pmadapter->dfs_cs_count = ds_11hcfg->param.cs_count;
2822 		}
2823 		ret = MLAN_STATUS_SUCCESS;
2824 	}
2825 
2826 	LEAVE();
2827 	return ret;
2828 }
2829 
2830 /**
2831  *  @brief 802.11h DFS cancel chan report
2832  *
2833  *  @param priv         Pointer to mlan_private
2834  *  @param pioctl_req   Pointer to mlan_ioctl_req
2835  *
2836  *  @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2837  */
2838 mlan_status
wlan_11h_ioctl_dfs_cancel_chan_report(mlan_private * priv,pmlan_ioctl_req pioctl_req)2839 wlan_11h_ioctl_dfs_cancel_chan_report(mlan_private *priv,
2840 				      pmlan_ioctl_req pioctl_req)
2841 {
2842 	mlan_ds_11h_cfg *ds_11hcfg = MNULL;
2843 	HostCmd_DS_CHAN_RPT_REQ *chan_rpt_req = MNULL;
2844 	t_s32 ret;
2845 
2846 	ENTER();
2847 
2848 	ds_11hcfg = (mlan_ds_11h_cfg *)pioctl_req->pbuf;
2849 
2850 	chan_rpt_req =
2851 		(HostCmd_DS_CHAN_RPT_REQ *)&ds_11hcfg->param.chan_rpt_req;
2852 
2853 	ret = wlan_prepare_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST,
2854 			       HostCmd_ACT_GEN_SET, 0,
2855 			       (t_void *)pioctl_req, (t_void *)chan_rpt_req);
2856 
2857 	if (ret == MLAN_STATUS_SUCCESS)
2858 		ret = MLAN_STATUS_PENDING;
2859 
2860 	LEAVE();
2861 	return ret;
2862 }
2863 
2864 /**
2865  *  @brief Check if channel is under NOP (Non-Occupancy Period)
2866  *  If so, the channel should not be used until the period expires.
2867  *
2868  *  @param pmadapter  Pointer to mlan_adapter
2869  *  @param channel    Channel number
2870  *
2871  *  @return MTRUE or MFALSE
2872  */
2873 t_bool
wlan_11h_is_channel_under_nop(mlan_adapter * pmadapter,t_u8 channel)2874 wlan_11h_is_channel_under_nop(mlan_adapter *pmadapter, t_u8 channel)
2875 {
2876 	wlan_dfs_timestamp_t *pdfs_ts = MNULL;
2877 	t_u32 now_sec, now_usec;
2878 	t_bool ret = MFALSE;
2879 
2880 	ENTER();
2881 	pdfs_ts = wlan_11h_find_dfs_timestamp(pmadapter, channel);
2882 
2883 	if (pdfs_ts && (pdfs_ts->channel == channel)
2884 	    && (pdfs_ts->represents == DFS_TS_REPR_NOP_START)) {
2885 		/* found NOP_start timestamp entry on channel */
2886 		pmadapter->callbacks.moal_get_system_time(pmadapter->
2887 							  pmoal_handle,
2888 							  &now_sec, &now_usec);
2889 #ifdef DFS_TESTING_SUPPORT
2890 		if (pmadapter->dfs_test_params.user_nop_period_sec) {
2891 			PRINTM(MCMD_D,
2892 			       "dfs_testing - user NOP period=%d (sec)\n",
2893 			       pmadapter->dfs_test_params.user_nop_period_sec);
2894 			if ((now_sec - pdfs_ts->ts_sec) <=
2895 			    pmadapter->dfs_test_params.user_nop_period_sec) {
2896 				ret = MTRUE;
2897 			}
2898 		} else
2899 #endif
2900 		{
2901 			if ((now_sec - pdfs_ts->ts_sec) <=
2902 			    WLAN_11H_NON_OCCUPANCY_PERIOD)
2903 				ret = MTRUE;
2904 		}
2905 
2906 		/* if entry is expired, remove it */
2907 		if (!ret)
2908 			wlan_11h_remove_dfs_timestamp(pmadapter, pdfs_ts);
2909 		else
2910 			PRINTM(MMSG,
2911 			       "11h: channel %d is under NOP - can't use.\n",
2912 			       channel);
2913 	}
2914 
2915 	LEAVE();
2916 	return ret;
2917 }
2918 
2919 /**
2920  *  @brief Driver handling for CHANNEL_REPORT_RDY event
2921  *  This event will have the channel report data appended.
2922  *
2923  *  @param priv     Pointer to mlan_private
2924  *  @param pevent   Pointer to mlan_event
2925  *
2926  *  @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
2927  */
2928 mlan_status
wlan_11h_handle_event_chanrpt_ready(mlan_private * priv,mlan_event * pevent)2929 wlan_11h_handle_event_chanrpt_ready(mlan_private *priv, mlan_event *pevent)
2930 {
2931 	mlan_status ret = MLAN_STATUS_SUCCESS;
2932 	HostCmd_DS_CHAN_RPT_RSP *pchan_rpt_rsp;
2933 	MrvlIEtypes_Data_t *ptlv;
2934 	MeasRptBasicMap_t *pmeas_rpt_basic;
2935 	t_u8 *pbuffer;
2936 	t_s32 evt_len;
2937 	t_u16 tlv_len;
2938 	t_u32 sec, usec;
2939 	wlan_dfs_device_state_t *pstate_dfs = &priv->adapter->state_dfs;
2940 
2941 	ENTER();
2942 	pchan_rpt_rsp = (HostCmd_DS_CHAN_RPT_RSP *)&pevent->event_buf;
2943 	DBG_HEXDUMP(MCMD_D, "11h: Event ChanRptReady (HostCmd_DS_CHAN_RPT_RSP)",
2944 		    (t_u8 *)pchan_rpt_rsp, pevent->event_len);
2945 
2946 	if (wlan_le32_to_cpu(pchan_rpt_rsp->cmd_result) ==
2947 	    MLAN_CMD_RESULT_SUCCESS) {
2948 		pbuffer = (t_u8 *)&pchan_rpt_rsp->tlv_buffer;
2949 		evt_len = pevent->event_len;
2950 		evt_len -=
2951 			sizeof(HostCmd_DS_CHAN_RPT_RSP) -
2952 			sizeof(pchan_rpt_rsp->tlv_buffer);
2953 
2954 		while (evt_len >= sizeof(MrvlIEtypesHeader_t)) {
2955 			ptlv = (MrvlIEtypes_Data_t *)pbuffer;
2956 			tlv_len = wlan_le16_to_cpu(ptlv->header.len);
2957 
2958 			switch (wlan_le16_to_cpu(ptlv->header.type)) {
2959 			case TLV_TYPE_CHANRPT_11H_BASIC:
2960 				pmeas_rpt_basic =
2961 					(MeasRptBasicMap_t *)&ptlv->data;
2962 				if (pmeas_rpt_basic->radar) {
2963 					pstate_dfs->dfs_radar_found = MTRUE;
2964 					PRINTM(MMSG,
2965 					       "RADAR Detected on channel %d!\n",
2966 					       pstate_dfs->dfs_check_channel);
2967 					/* add channel to NOP list */
2968 					wlan_11h_add_dfs_timestamp(priv->
2969 								   adapter,
2970 								   DFS_TS_REPR_NOP_START,
2971 								   pstate_dfs->
2972 								   dfs_check_channel);
2973 				}
2974 				break;
2975 
2976 			default:
2977 				break;
2978 			}
2979 
2980 			pbuffer += (tlv_len + sizeof(ptlv->header));
2981 			evt_len -= (tlv_len + sizeof(ptlv->header));
2982 			evt_len = (evt_len > 0) ? evt_len : 0;
2983 		}
2984 	} else {
2985 		ret = MLAN_STATUS_FAILURE;
2986 	}
2987 
2988 	/* Update DFS structure. */
2989 	priv->adapter->callbacks.moal_get_system_time(priv->adapter->
2990 						      pmoal_handle, &sec,
2991 						      &usec);
2992 	pstate_dfs->dfs_report_time_sec = sec;
2993 	pstate_dfs->dfs_check_pending = MFALSE;
2994 	pstate_dfs->dfs_check_priv = MNULL;
2995 
2996 	LEAVE();
2997 	return ret;
2998 }
2999 
3000 /**
3001  *  @brief Check if RADAR_DETECTED handling is blocking data tx
3002  *
3003  *  @param pmadapter    Pointer to mlan_adapter
3004  *
3005  *  @return MTRUE or MFALSE
3006  */
3007 t_bool
wlan_11h_radar_detected_tx_blocked(mlan_adapter * pmadapter)3008 wlan_11h_radar_detected_tx_blocked(mlan_adapter *pmadapter)
3009 {
3010 	if (pmadapter->state_rdh.tx_block)
3011 		return MTRUE;
3012 	switch (pmadapter->state_rdh.stage) {
3013 	case RDH_OFF:
3014 	case RDH_CHK_INTFS:
3015 	case RDH_STOP_TRAFFIC:
3016 		return MFALSE;
3017 	}
3018 	return MTRUE;
3019 }
3020 
3021 /**
3022  *  @brief Callback for RADAR_DETECTED event driver handling
3023  *
3024  *  @param priv    Void pointer to mlan_private
3025  *
3026  *  @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3027  */
3028 mlan_status
wlan_11h_radar_detected_callback(t_void * priv)3029 wlan_11h_radar_detected_callback(t_void *priv)
3030 {
3031 	mlan_status ret;
3032 	ENTER();
3033 	ret = wlan_11h_radar_detected_handling(((mlan_private *)(priv))->
3034 					       adapter, (mlan_private *)priv);
3035 	LEAVE();
3036 	return ret;
3037 }
3038 
3039 /**
3040  *  @brief Function for handling sta disconnect event in dfs_repeater mode
3041  *
3042  *  @param pmadapter	pointer to mlan_adapter
3043  *
3044  *  @return NONE
3045  */
3046 void
wlan_dfs_rep_disconnect(mlan_adapter * pmadapter)3047 wlan_dfs_rep_disconnect(mlan_adapter *pmadapter)
3048 {
3049 	mlan_private *priv_list[MLAN_MAX_BSS_NUM];
3050 	mlan_private *pmpriv = MNULL;
3051 	t_u8 pcount, i;
3052 
3053 	memset(pmadapter, priv_list, 0x00, sizeof(priv_list));
3054 	pcount = wlan_get_privs_by_cond(pmadapter, wlan_is_intf_active,
3055 					priv_list);
3056 
3057 	/* Stop all the active BSSes */
3058 	for (i = 0; i < pcount; i++) {
3059 		pmpriv = priv_list[i];
3060 
3061 		if (GET_BSS_ROLE(pmpriv) != MLAN_BSS_ROLE_UAP)
3062 			continue;
3063 
3064 		if (wlan_11h_radar_detect_required(pmpriv,
3065 						   pmadapter->dfsr_channel)) {
3066 			wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_BSS_STOP,
3067 					 HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
3068 		}
3069 	}
3070 }
3071 
3072 /**
3073  *  @brief Function for handling sta BW change event in dfs_repeater mode
3074  *
3075  *  @param pmadapter	pointer to mlan_adapter
3076  *
3077  *  @return NONE
3078  */
3079 void
wlan_dfs_rep_bw_change(mlan_adapter * pmadapter)3080 wlan_dfs_rep_bw_change(mlan_adapter *pmadapter)
3081 {
3082 	mlan_private *priv_list[MLAN_MAX_BSS_NUM];
3083 	mlan_private *pmpriv = MNULL;
3084 	t_u8 pcount, i;
3085 
3086 	memset(pmadapter, priv_list, 0x00, sizeof(priv_list));
3087 	pcount = wlan_get_privs_by_cond(pmadapter, wlan_is_intf_active,
3088 					priv_list);
3089 	if (pcount == 1) {
3090 		pmpriv = priv_list[0];
3091 		if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
3092 			PRINTM(MMSG, "dfs-repeater: BW change detected\n"
3093 			       "no active priv's, skip event handling.\n");
3094 			return;
3095 		}
3096 	}
3097 
3098 	/* Stop all the active BSSes */
3099 	for (i = 0; i < pcount; i++) {
3100 		pmpriv = priv_list[i];
3101 
3102 		if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
3103 
3104 			/* Check if uAPs running on non-dfs channel. If they do
3105 			 * then there is no need to restart the uAPs
3106 			 */
3107 			if (!wlan_11h_radar_detect_required(pmpriv,
3108 							    pmadapter->
3109 							    dfsr_channel))
3110 				return;
3111 
3112 			wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_BSS_STOP,
3113 					 HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
3114 		}
3115 	}
3116 
3117 	/* Start all old active BSSes */
3118 	for (i = 0; i < pcount; i++) {
3119 		pmpriv = priv_list[i];
3120 
3121 		if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
3122 			wlan_prepare_cmd(pmpriv, HOST_CMD_APCMD_BSS_START,
3123 					 HostCmd_ACT_GEN_SET, 0, MNULL, MNULL);
3124 		}
3125 	}
3126 }
3127 
3128 /**
3129  *  @brief Update band config for the new channel
3130  *
3131  *  @param uap_band_cfg  uap's old channel's band configuration
3132  *  @param new_channel   new channel that the device is switching to
3133  *
3134  *  @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
3135  */
3136 void
wlan_11h_update_bandcfg(IN Band_Config_t * uap_band_cfg,IN t_u8 new_channel)3137 wlan_11h_update_bandcfg(IN Band_Config_t *uap_band_cfg, IN t_u8 new_channel)
3138 {
3139 	t_u8 chan_offset;
3140 	ENTER();
3141 
3142 	/* Update the channel offset for 20MHz, 40MHz and 80MHz
3143 	 * Clear the channel bandwidth for 20MHz
3144 	 * since channel switch could be happening from 40/80MHz to 20MHz
3145 	 */
3146 	chan_offset = wlan_get_second_channel_offset(new_channel);
3147 	uap_band_cfg->chan2Offset = chan_offset;
3148 
3149 	if (!chan_offset) {	/* 40MHz/80MHz */
3150 		PRINTM(MCMD_D, "20MHz channel, clear channel bandwidth\n");
3151 		uap_band_cfg->chanWidth = CHAN_BW_20MHZ;
3152 	}
3153 	LEAVE();
3154 }
3155 
3156 /**
3157  * @brief Get priv current index -- this is used to enter correct rdh_state during radar handling
3158  *
3159  * @param pmpriv           Pointer to mlan_private
3160  * @param pstate_rdh       Pointer to radar detected state handler
3161  *
3162  * @return                 MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
3163  */
3164 mlan_status
wlan_11h_get_priv_curr_idx(mlan_private * pmpriv,wlan_radar_det_hndlg_state_t * pstate_rdh)3165 wlan_11h_get_priv_curr_idx(mlan_private *pmpriv,
3166 			   wlan_radar_det_hndlg_state_t *pstate_rdh)
3167 {
3168 	t_bool found = MFALSE;
3169 	ENTER();
3170 
3171 	PRINTM(MINFO, "%s:pmpriv =%p\n", __func__, pmpriv);
3172 	while ((++pstate_rdh->priv_curr_idx) < pstate_rdh->priv_list_count) {
3173 		if (pmpriv == pstate_rdh->priv_list[pstate_rdh->priv_curr_idx]) {
3174 			PRINTM(MINFO, "found matching priv: priv_idx=%d\n",
3175 			       pstate_rdh->priv_curr_idx);
3176 			found = MTRUE;
3177 			break;
3178 		}
3179 	}
3180 	return (found == MTRUE) ? MLAN_STATUS_SUCCESS : MLAN_STATUS_FAILURE;
3181 }
3182 
3183 /**
3184  *  @brief Driver handling for RADAR_DETECTED event
3185  *
3186  *  @param pmadapter    Pointer to mlan_adapter
3187  *  @param pmpriv       Pointer to mlan_private
3188  *
3189  *  @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
3190  */
3191 mlan_status
wlan_11h_radar_detected_handling(mlan_adapter * pmadapter,mlan_private * pmpriv)3192 wlan_11h_radar_detected_handling(mlan_adapter *pmadapter, mlan_private *pmpriv)
3193 {
3194 #ifdef DEBUG_LEVEL1
3195 	const char *rdh_stage_str[] = {
3196 		"RDH_OFF",
3197 		"RDH_CHK_INTFS",
3198 		"RDH_STOP_TRAFFIC",
3199 		"RDH_GET_INFO_CHANNEL",
3200 		"RDH_GET_INFO_BEACON_DTIM",
3201 		"RDH_SET_CUSTOM_IE",
3202 		"RDH_REM_CUSTOM_IE",
3203 		"RDH_STOP_INTFS",
3204 		"RDH_SET_NEW_CHANNEL",
3205 		"RDH_RESTART_INTFS",
3206 		"RDH_RESTART_TRAFFIC"
3207 	};
3208 #endif
3209 
3210 	mlan_status ret = MLAN_STATUS_SUCCESS;
3211 	t_u32 i;
3212 	wlan_radar_det_hndlg_state_t *pstate_rdh = &pmadapter->state_rdh;
3213 
3214 	ENTER();
3215 
3216 	if (!pmpriv) {
3217 		PRINTM(MERROR, "Invalid radar priv -- Exit radar handling\n");
3218 		LEAVE();
3219 		return MLAN_STATUS_FAILURE;
3220 	}
3221 
3222 	switch (pstate_rdh->stage) {
3223 	case RDH_CHK_INTFS:
3224 		PRINTM(MCMD_D, "%s(): stage(%d)=%s\n",
3225 		       __func__, pstate_rdh->stage,
3226 		       rdh_stage_str[pstate_rdh->stage]);
3227 
3228 		/* get active interfaces */
3229 		memset(pmadapter, pstate_rdh->priv_list, 0x00,
3230 		       sizeof(pstate_rdh->priv_list));
3231 		pstate_rdh->priv_list_count = wlan_get_privs_by_cond(pmadapter,
3232 								     wlan_is_intf_active,
3233 								     pstate_rdh->
3234 								     priv_list);
3235 		PRINTM(MCMD_D, "%s():  priv_list_count = %d\n", __func__,
3236 		       pstate_rdh->priv_list_count);
3237 		for (i = 0; i < pstate_rdh->priv_list_count; i++)
3238 			PRINTM(MINFO, "%s():  priv_list[%d] = %p\n",
3239 			       __func__, i, pstate_rdh->priv_list[i]);
3240 
3241 		if (pstate_rdh->priv_list_count == 0) {
3242 			/* no interfaces active... nothing to do */
3243 			PRINTM(MMSG, "11h: Radar Detected - no active priv's,"
3244 			       " skip event handling.\n");
3245 			pstate_rdh->stage = RDH_OFF;
3246 			PRINTM(MCMD_D, "%s(): finished - stage(%d)=%s\n",
3247 			       __func__, pstate_rdh->stage,
3248 			       rdh_stage_str[pstate_rdh->stage]);
3249 			break;	/* EXIT CASE */
3250 		}
3251 
3252 		/* else: start handling */
3253 		pstate_rdh->curr_channel = 0;
3254 		pstate_rdh->new_channel = 0;
3255 		memset(pmadapter, &(pstate_rdh->uap_band_cfg), 0,
3256 		       sizeof(pstate_rdh->uap_band_cfg));
3257 		pstate_rdh->max_bcn_dtim_ms = 0;
3258 		pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
3259 		pstate_rdh->stage = RDH_STOP_TRAFFIC;
3260 		/* FALL THROUGH TO NEXT STAGE */
3261 
3262 	case RDH_STOP_TRAFFIC:
3263 		PRINTM(MCMD_D, "%s(): stage(%d)=%s\n",
3264 		       __func__, pstate_rdh->stage,
3265 		       rdh_stage_str[pstate_rdh->stage]);
3266 
3267 		PRINTM(MMSG,
3268 		       "11h: Radar Detected - stopping host tx traffic.\n");
3269 		for (i = 0; i < pstate_rdh->priv_list_count; i++)
3270 			wlan_11h_tx_disable(pstate_rdh->priv_list[i]);
3271 
3272 		pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
3273 		pstate_rdh->stage = RDH_GET_INFO_CHANNEL;
3274 		/* FALL THROUGH TO NEXT STAGE */
3275 
3276 	case RDH_GET_INFO_CHANNEL:
3277 		PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
3278 		       __func__, pstate_rdh->stage,
3279 		       rdh_stage_str[pstate_rdh->stage],
3280 		       pstate_rdh->priv_curr_idx);
3281 
3282 		/* here, prefer STA info over UAP info - one less CMD to send */
3283 		if (pstate_rdh->priv_curr_idx == RDH_STAGE_FIRST_ENTRY_PRIV_IDX) {
3284 #ifdef UAP_SUPPORT
3285 			if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
3286 				ret = wlan_11h_get_priv_curr_idx(pmpriv,
3287 								 pstate_rdh);
3288 				if (ret != MLAN_STATUS_SUCCESS) {
3289 					PRINTM(MERROR,
3290 					       "Unable to locate pmpriv in current active priv_list\n");
3291 					break;	/* EXIT CASE */
3292 				}
3293 
3294 				/* send cmd to get first UAP's info */
3295 				pmpriv->uap_state_chan_cb.pioctl_req_curr =
3296 					MNULL;
3297 				pmpriv->uap_state_chan_cb.get_chan_callback =
3298 					wlan_11h_radar_detected_callback;
3299 				ret = wlan_uap_get_channel(pmpriv);
3300 				break;	/* EXIT CASE */
3301 			} else
3302 #endif
3303 			{
3304 				/* Assume all STAs on same channel, find first STA */
3305 				MASSERT(pstate_rdh->priv_list_count > 0);
3306 				for (i = 0; i < pstate_rdh->priv_list_count;
3307 				     i++) {
3308 					pmpriv = pstate_rdh->priv_list[i];
3309 					if (GET_BSS_ROLE(pmpriv) ==
3310 					    MLAN_BSS_ROLE_STA)
3311 						break;
3312 				}
3313 				/* STA info kept in driver, just copy */
3314 				pstate_rdh->curr_channel =
3315 					pmpriv->curr_bss_params.bss_descriptor.
3316 					channel;
3317 			}
3318 		}
3319 #ifdef UAP_SUPPORT
3320 		else if (pstate_rdh->priv_curr_idx <
3321 			 pstate_rdh->priv_list_count) {
3322 			/* repeat entry: UAP return with info */
3323 			pstate_rdh->curr_channel =
3324 				pmpriv->uap_state_chan_cb.channel;
3325 			pstate_rdh->uap_band_cfg =
3326 				pmpriv->uap_state_chan_cb.bandcfg;
3327 			PRINTM(MCMD_D,
3328 			       "%s(): uap_band_cfg=0x%02x curr_chan=%d, curr_idx=%d bss_role=%d\n",
3329 			       __func__, pstate_rdh->uap_band_cfg,
3330 			       pstate_rdh->curr_channel,
3331 			       pstate_rdh->priv_curr_idx, GET_BSS_ROLE(pmpriv));
3332 		}
3333 #endif
3334 
3335 		/* add channel to NOP list */
3336 		wlan_11h_add_dfs_timestamp(pmadapter, DFS_TS_REPR_NOP_START,
3337 					   pstate_rdh->curr_channel);
3338 
3339 		/* choose new channel (!= curr channel) and move on */
3340 #ifdef UAP_SUPPORT
3341 		if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP)
3342 			pstate_rdh->new_channel =
3343 				wlan_11h_get_uap_start_channel(pmpriv,
3344 							       pmpriv->
3345 							       uap_state_chan_cb.
3346 							       bandcfg);
3347 		else
3348 #endif
3349 			pstate_rdh->new_channel =
3350 				wlan_11h_get_adhoc_start_channel(pmpriv);
3351 
3352 		if (!pstate_rdh->new_channel || (pstate_rdh->new_channel == pstate_rdh->curr_channel)) {	/* report error */
3353 			PRINTM(MERROR,
3354 			       "%s():  ERROR - Failed to choose new_chan"
3355 			       " (!= curr_chan) !!\n", __func__);
3356 #ifdef UAP_SUPPORT
3357 			if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
3358 				ret = wlan_prepare_cmd(pmpriv,
3359 						       HOST_CMD_APCMD_BSS_STOP,
3360 						       HostCmd_ACT_GEN_SET, 0,
3361 						       MNULL, MNULL);
3362 				PRINTM(MERROR,
3363 				       "STOP UAP and exit radar handling...\n");
3364 				pstate_rdh->stage = RDH_OFF;
3365 				break;	/* leads to exit case */
3366 			}
3367 #endif
3368 		}
3369 #ifdef DFS_TESTING_SUPPORT
3370 		if (!pmadapter->dfs_test_params.no_channel_change_on_radar &&
3371 		    pmadapter->dfs_test_params.fixed_new_channel_on_radar) {
3372 			PRINTM(MCMD_D, "dfs_testing - user fixed new_chan=%d\n",
3373 			       pmadapter->dfs_test_params.
3374 			       fixed_new_channel_on_radar);
3375 			pstate_rdh->new_channel =
3376 				pmadapter->dfs_test_params.
3377 				fixed_new_channel_on_radar;
3378 		}
3379 		/* applies to DFS with ECSA support */
3380 		if (pmadapter->dfs_test_params.no_channel_change_on_radar) {
3381 			pstate_rdh->new_channel = pstate_rdh->curr_channel;
3382 		}
3383 #endif
3384 		PRINTM(MCMD_D, "%s():  curr_chan=%d, new_chan=%d\n",
3385 		       __func__, pstate_rdh->curr_channel,
3386 		       pstate_rdh->new_channel);
3387 
3388 		pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
3389 		pstate_rdh->stage = RDH_GET_INFO_BEACON_DTIM;
3390 		/* FALL THROUGH TO NEXT STAGE */
3391 
3392 	case RDH_GET_INFO_BEACON_DTIM:
3393 		PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
3394 		       __func__, pstate_rdh->stage,
3395 		       rdh_stage_str[pstate_rdh->stage],
3396 		       pstate_rdh->priv_curr_idx);
3397 
3398 #ifdef UAP_SUPPORT
3399 		/* check all intfs in this stage to find longest period */
3400 		/* UAP intf callback returning with info */
3401 		if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count) {
3402 			t_u16 bcn_dtim_msec;
3403 			pmpriv = pstate_rdh->priv_list[pstate_rdh->
3404 						       priv_curr_idx];
3405 			PRINTM(MCMD_D, "%s():  uap.bcn_pd=%d, uap.dtim_pd=%d\n",
3406 			       __func__,
3407 			       pmpriv->uap_state_chan_cb.beacon_period,
3408 			       pmpriv->uap_state_chan_cb.dtim_period);
3409 			bcn_dtim_msec =
3410 				(pmpriv->uap_state_chan_cb.beacon_period *
3411 				 pmpriv->uap_state_chan_cb.dtim_period);
3412 			if (bcn_dtim_msec > pstate_rdh->max_bcn_dtim_ms)
3413 				pstate_rdh->max_bcn_dtim_ms = bcn_dtim_msec;
3414 		}
3415 #endif
3416 
3417 		/* check next intf */
3418 		while ((++pstate_rdh->priv_curr_idx) <
3419 		       pstate_rdh->priv_list_count) {
3420 			pmpriv = pstate_rdh->priv_list[pstate_rdh->
3421 						       priv_curr_idx];
3422 
3423 #ifdef UAP_SUPPORT
3424 			if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
3425 				pmpriv->uap_state_chan_cb.pioctl_req_curr =
3426 					MNULL;
3427 				pmpriv->uap_state_chan_cb.get_chan_callback =
3428 					wlan_11h_radar_detected_callback;
3429 				ret = wlan_uap_get_beacon_dtim(pmpriv);
3430 				break;	/* leads to exit case */
3431 			} else
3432 #endif
3433 			{	/* get STA info from driver and compare here */
3434 				t_u16 bcn_pd_msec = 100;
3435 				t_u16 dtim_pd_msec = 1;
3436 				t_u16 bcn_dtim_msec;
3437 
3438 				/* adhoc creator */
3439 				if (wlan_11h_is_dfs_master(pmpriv)) {
3440 					bcn_pd_msec = pmpriv->beacon_period;
3441 				} else {
3442 					bcn_pd_msec =
3443 						pmpriv->curr_bss_params.
3444 						bss_descriptor.beacon_period;
3445 					/* if (priv->bss_mode != MLAN_BSS_MODE_IBSS) */
3446 					/* TODO: mlan_scan.c needs to parse TLV 0x05 (TIM) for dtim_period */
3447 				}
3448 				PRINTM(MCMD_D,
3449 				       "%s():  sta.bcn_pd=%d, sta.dtim_pd=%d\n",
3450 				       __func__, bcn_pd_msec, dtim_pd_msec);
3451 				bcn_dtim_msec = (bcn_pd_msec * dtim_pd_msec);
3452 				if (bcn_dtim_msec > pstate_rdh->max_bcn_dtim_ms)
3453 					pstate_rdh->max_bcn_dtim_ms =
3454 						bcn_dtim_msec;
3455 			}
3456 		}
3457 
3458 		if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count)
3459 			break;	/* EXIT CASE (for UAP) */
3460 		/* else */
3461 		pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
3462 		pstate_rdh->stage = RDH_SET_CUSTOM_IE;
3463 		/* FALL THROUGH TO NEXT STAGE */
3464 
3465 	case RDH_SET_CUSTOM_IE:
3466 		PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
3467 		       __func__, pstate_rdh->stage,
3468 		       rdh_stage_str[pstate_rdh->stage],
3469 		       pstate_rdh->priv_curr_idx);
3470 
3471 		/* add CHAN_SW IE - firmware will accept on any interface, and apply to all */
3472 		if (pstate_rdh->priv_curr_idx == RDH_STAGE_FIRST_ENTRY_PRIV_IDX) {
3473 			mlan_ioctl_req *pioctl_req = MNULL;
3474 
3475 			ret = wlan_11h_prepare_custom_ie_chansw(pmadapter,
3476 								&pioctl_req,
3477 								MTRUE);
3478 			if ((ret != MLAN_STATUS_SUCCESS) || !pioctl_req) {
3479 				PRINTM(MERROR,
3480 				       "%s(): Error in preparing CHAN_SW IE.\n",
3481 				       __func__);
3482 				break;	/* EXIT CASE */
3483 			}
3484 
3485 			PRINTM(MMSG,
3486 			       "11h: Radar Detected - adding CHAN_SW IE to interfaces.\n");
3487 			ret = wlan_11h_get_priv_curr_idx(pmpriv, pstate_rdh);
3488 			if (ret != MLAN_STATUS_SUCCESS) {
3489 				PRINTM(MERROR,
3490 				       "Unable to locate pmpriv in current active priv_list\n");
3491 				break;	/* EXIT CASE */
3492 			}
3493 
3494 			pioctl_req->bss_index = pmpriv->bss_index;
3495 			ret = wlan_misc_ioctl_custom_ie_list(pmadapter,
3496 							     pioctl_req,
3497 							     MFALSE);
3498 			if (ret != MLAN_STATUS_SUCCESS &&
3499 			    ret != MLAN_STATUS_PENDING) {
3500 				PRINTM(MERROR,
3501 				       "%s(): Could not set IE for priv=%p [priv_bss_idx=%d]!\n",
3502 				       __func__, pmpriv, pmpriv->bss_index);
3503 				/* TODO: how to handle this error case??  ignore & continue? */
3504 			}
3505 			/* free ioctl buffer memory before we leave */
3506 			pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
3507 							(t_u8 *)pioctl_req);
3508 			break;	/* EXIT CASE */
3509 		}
3510 		/* else */
3511 		pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
3512 		pstate_rdh->stage = RDH_REM_CUSTOM_IE;
3513 		/* FALL THROUGH TO NEXT STAGE */
3514 
3515 	case RDH_REM_CUSTOM_IE:
3516 		PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
3517 		       __func__, pstate_rdh->stage,
3518 		       rdh_stage_str[pstate_rdh->stage],
3519 		       pstate_rdh->priv_curr_idx);
3520 
3521 		/* remove CHAN_SW IE - firmware will accept on any interface,
3522 		   and apply to all */
3523 		if (pstate_rdh->priv_curr_idx == RDH_STAGE_FIRST_ENTRY_PRIV_IDX) {
3524 			mlan_ioctl_req *pioctl_req = MNULL;
3525 
3526 			/*
3527 			 * first entry to this stage, do delay
3528 			 * DFS requires a minimum of 5 chances for clients to hear this IE.
3529 			 * Use delay:  5 beacons <= (BCN_DTIM_MSEC*5) <= 3 seconds).
3530 			 */
3531 			t_u16 delay_ms = MAX(MIN_RDH_CHAN_SW_IE_PERIOD_MSEC,
3532 					     MIN((4 *
3533 						  pstate_rdh->max_bcn_dtim_ms),
3534 						 MAX_RDH_CHAN_SW_IE_PERIOD_MSEC));
3535 			PRINTM(MMSG,
3536 			       "11h: Radar Detected - delay %d ms for FW to"
3537 			       " broadcast CHAN_SW IE.\n", delay_ms);
3538 			wlan_mdelay(pmadapter, delay_ms);
3539 			PRINTM(MMSG,
3540 			       "11h: Radar Detected - delay over, removing"
3541 			       " CHAN_SW IE from interfaces.\n");
3542 
3543 			ret = wlan_11h_prepare_custom_ie_chansw(pmadapter,
3544 								&pioctl_req,
3545 								MFALSE);
3546 			if ((ret != MLAN_STATUS_SUCCESS) || !pioctl_req) {
3547 				PRINTM(MERROR,
3548 				       "%s(): Error in preparing CHAN_SW IE.\n",
3549 				       __func__);
3550 				break;	/* EXIT CASE */
3551 			}
3552 
3553 			ret = wlan_11h_get_priv_curr_idx(pmpriv, pstate_rdh);
3554 			if (ret != MLAN_STATUS_SUCCESS) {
3555 				PRINTM(MERROR,
3556 				       "Unable to locate pmpriv in current active priv_list\n");
3557 				break;	/* EXIT CASE */
3558 			}
3559 
3560 			pioctl_req->bss_index = pmpriv->bss_index;
3561 			ret = wlan_misc_ioctl_custom_ie_list(pmadapter,
3562 							     pioctl_req,
3563 							     MFALSE);
3564 			if (ret != MLAN_STATUS_SUCCESS &&
3565 			    ret != MLAN_STATUS_PENDING) {
3566 				PRINTM(MERROR,
3567 				       "%s(): Could not remove IE for priv=%p [priv_bss_idx=%d]!\n",
3568 				       __func__, pmpriv, pmpriv->bss_index);
3569 				/* TODO: hiow to handle this error case??  ignore & continue? */
3570 			}
3571 			/* free ioctl buffer memory before we leave */
3572 			pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
3573 							(t_u8 *)pioctl_req);
3574 			break;	/* EXIT CASE */
3575 		}
3576 		/* else */
3577 		pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
3578 		pstate_rdh->stage = RDH_STOP_INTFS;
3579 		/* FALL THROUGH TO NEXT STAGE */
3580 
3581 	case RDH_STOP_INTFS:
3582 		PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
3583 		       __func__, pstate_rdh->stage,
3584 		       rdh_stage_str[pstate_rdh->stage],
3585 		       pstate_rdh->priv_curr_idx);
3586 
3587 		/* issues one cmd (DEAUTH/ADHOC_STOP/BSS_STOP) to each intf */
3588 		while ((++pstate_rdh->priv_curr_idx) <
3589 		       pstate_rdh->priv_list_count) {
3590 			pmpriv = pstate_rdh->priv_list[pstate_rdh->
3591 						       priv_curr_idx];
3592 #ifdef UAP_SUPPORT
3593 			if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
3594 				ret = wlan_prepare_cmd(pmpriv,
3595 						       HOST_CMD_APCMD_BSS_STOP,
3596 						       HostCmd_ACT_GEN_SET, 0,
3597 						       MNULL, MNULL);
3598 				break;	/* leads to exit case */
3599 			}
3600 #endif
3601 #ifdef STA_SUPPORT
3602 			if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
3603 				if (wlan_11h_is_dfs_master(pmpriv)) {
3604 					/* Save ad-hoc creator state before stop clears it */
3605 					pmpriv->adhoc_state_prev =
3606 						pmpriv->adhoc_state;
3607 				}
3608 				if (pmpriv->media_connected == MTRUE) {
3609 					wlan_disconnect(pmpriv, MNULL, MNULL);
3610 					break;	/* leads to exit case */
3611 				}
3612 			}
3613 #endif
3614 		}
3615 
3616 		if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count ||
3617 		    ret == MLAN_STATUS_FAILURE)
3618 			break;	/* EXIT CASE */
3619 		/* else */
3620 		pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
3621 		pstate_rdh->stage = RDH_SET_NEW_CHANNEL;
3622 
3623 #ifdef DFS_TESTING_SUPPORT
3624 		if (pmadapter->dfs_test_params.no_channel_change_on_radar) {
3625 			PRINTM(MCMD_D,
3626 			       "dfs_testing - no channel change on radar."
3627 			       "  Overwrite new_chan = curr_chan.\n");
3628 			pstate_rdh->new_channel = pstate_rdh->curr_channel;
3629 			pstate_rdh->priv_curr_idx =
3630 				RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
3631 			pstate_rdh->stage = RDH_RESTART_INTFS;
3632 			goto rdh_restart_intfs;	/* skip next stage */
3633 		}
3634 #endif
3635 		/* FALL THROUGH TO NEXT STAGE */
3636 
3637 	case RDH_SET_NEW_CHANNEL:
3638 		PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
3639 		       __func__, pstate_rdh->stage,
3640 		       rdh_stage_str[pstate_rdh->stage],
3641 		       pstate_rdh->priv_curr_idx);
3642 
3643 		/* only set new channel for UAP intfs */
3644 		while ((++pstate_rdh->priv_curr_idx) <
3645 		       pstate_rdh->priv_list_count) {
3646 			pmpriv = pstate_rdh->priv_list[pstate_rdh->
3647 						       priv_curr_idx];
3648 #ifdef UAP_SUPPORT
3649 			if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
3650 
3651 				pmpriv->uap_state_chan_cb.pioctl_req_curr =
3652 					MNULL;
3653 				pmpriv->uap_state_chan_cb.get_chan_callback =
3654 					wlan_11h_radar_detected_callback;
3655 
3656 				/* DFS only in 5GHz */
3657 				wlan_11h_update_bandcfg(&pstate_rdh->
3658 							uap_band_cfg,
3659 							pstate_rdh->
3660 							new_channel);
3661 				PRINTM(MCMD_D,
3662 				       "RDH_SET_NEW_CHANNEL: uAP band config = 0x%x channel=%d\n",
3663 				       pstate_rdh->uap_band_cfg,
3664 				       pstate_rdh->new_channel);
3665 
3666 				ret = wlan_uap_set_channel(pmpriv,
3667 							   pstate_rdh->
3668 							   uap_band_cfg,
3669 							   pstate_rdh->
3670 							   new_channel);
3671 				break;	/* leads to exit case */
3672 			}
3673 #endif
3674 		}
3675 
3676 		if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count ||
3677 		    ret == MLAN_STATUS_FAILURE)
3678 			break;	/* EXIT CASE (for UAP) */
3679 		/* else */
3680 		pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
3681 		pstate_rdh->stage = RDH_RESTART_INTFS;
3682 		/* FALL THROUGH TO NEXT STAGE */
3683 
3684 	case RDH_RESTART_INTFS:
3685 #ifdef DFS_TESTING_SUPPORT
3686 rdh_restart_intfs:
3687 #endif
3688 		PRINTM(MCMD_D, "%s(): stage(%d)=%s, priv_idx=%d\n",
3689 		       __func__, pstate_rdh->stage,
3690 		       rdh_stage_str[pstate_rdh->stage],
3691 		       pstate_rdh->priv_curr_idx);
3692 
3693 		/* can only restart master intfs */
3694 		while ((++pstate_rdh->priv_curr_idx) <
3695 		       pstate_rdh->priv_list_count) {
3696 			pmpriv = pstate_rdh->priv_list[pstate_rdh->
3697 						       priv_curr_idx];
3698 #ifdef UAP_SUPPORT
3699 			if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_UAP) {
3700 				if (wlan_11h_radar_detect_required(pmpriv,
3701 								   pstate_rdh->
3702 								   new_channel))
3703 				{
3704 					/* Radar detection is required for this channel,
3705 					   make sure 11h is activated in the firmware */
3706 					ret = wlan_11h_activate(pmpriv, MNULL,
3707 								MTRUE);
3708 					ret = wlan_11h_config_master_radar_det
3709 						(pmpriv, MTRUE);
3710 					ret = wlan_11h_check_update_radar_det_state(pmpriv);
3711 				}
3712 				ret = wlan_prepare_cmd(pmpriv,
3713 						       HOST_CMD_APCMD_BSS_START,
3714 						       HostCmd_ACT_GEN_SET, 0,
3715 						       MNULL, MNULL);
3716 				break;	/* leads to exit case */
3717 			}
3718 #endif
3719 #ifdef STA_SUPPORT
3720 			if (GET_BSS_ROLE(pmpriv) == MLAN_BSS_ROLE_STA) {
3721 				/* Check previous state to find former
3722 				 * Ad-hoc creator interface. Set new
3723 				 * state to Starting, so it'll be seen
3724 				 * as a DFS master. */
3725 				if (pmpriv->adhoc_state_prev == ADHOC_STARTED) {
3726 					pmpriv->adhoc_state = ADHOC_STARTING;
3727 					pmpriv->adhoc_state_prev = ADHOC_IDLE;
3728 				}
3729 				if (wlan_11h_is_dfs_master(pmpriv)) {
3730 					/* set new adhoc channel here */
3731 					pmpriv->adhoc_channel =
3732 						pstate_rdh->new_channel;
3733 					if (wlan_11h_radar_detect_required
3734 					    (pmpriv, pstate_rdh->new_channel)) {
3735 						/* Radar detection is required for this channel,
3736 						   make sure 11h is activated in the firmware */
3737 						ret = wlan_11h_activate(pmpriv,
3738 									MNULL,
3739 									MTRUE);
3740 						if (ret)
3741 							break;
3742 						ret = wlan_11h_config_master_radar_det(pmpriv, MTRUE);
3743 						if (ret)
3744 							break;
3745 						ret = wlan_11h_check_update_radar_det_state(pmpriv);
3746 						if (ret)
3747 							break;
3748 					}
3749 					ret = wlan_prepare_cmd(pmpriv,
3750 							       HostCmd_CMD_802_11_AD_HOC_START,
3751 							       HostCmd_ACT_GEN_SET,
3752 							       0, MNULL,
3753 							       &pmpriv->
3754 							       adhoc_last_start_ssid);
3755 					break;	/* leads to exit case */
3756 				}
3757 
3758 				/* NOTE:  DON'T reconnect slave STA intfs - infra/adhoc_joiner
3759 				 *   Do we want to return to same AP/network (on radar channel)?
3760 				 *   If want to connect back, depend on either:
3761 				 *     1. driver's reassoc thread
3762 				 *     2. wpa_supplicant, or other user-space app
3763 				 */
3764 			}
3765 #endif
3766 		}
3767 
3768 		if (pstate_rdh->priv_curr_idx < pstate_rdh->priv_list_count ||
3769 		    ret == MLAN_STATUS_FAILURE)
3770 			break;	/* EXIT CASE (for UAP) */
3771 		/* else */
3772 		pstate_rdh->priv_curr_idx = RDH_STAGE_FIRST_ENTRY_PRIV_IDX;
3773 		pstate_rdh->stage = RDH_RESTART_TRAFFIC;
3774 		/* FALL THROUGH TO NEXT STAGE */
3775 
3776 	case RDH_RESTART_TRAFFIC:
3777 		PRINTM(MCMD_D, "%s(): stage(%d)=%s\n",
3778 		       __func__, pstate_rdh->stage,
3779 		       rdh_stage_str[pstate_rdh->stage]);
3780 		/* remove custome ie */
3781 		if (pmadapter->ecsa_enable) {
3782 			mlan_ioctl_req *pioctl_req = MNULL;
3783 			ret = wlan_11h_prepare_custom_ie_chansw(pmadapter,
3784 								&pioctl_req,
3785 								MFALSE);
3786 			if ((ret != MLAN_STATUS_SUCCESS) || !pioctl_req) {
3787 				PRINTM(MERROR,
3788 				       "%s(): Error in preparing CHAN_SW IE.\n",
3789 				       __func__);
3790 				break;	/* EXIT CASE */
3791 			}
3792 
3793 			pmpriv = pstate_rdh->priv_list[0];
3794 			pstate_rdh->priv_curr_idx = 0;
3795 			pioctl_req->bss_index = pmpriv->bss_index;
3796 			ret = wlan_misc_ioctl_custom_ie_list(pmadapter,
3797 							     pioctl_req,
3798 							     MFALSE);
3799 			if (ret != MLAN_STATUS_SUCCESS &&
3800 			    ret != MLAN_STATUS_PENDING) {
3801 				PRINTM(MERROR,
3802 				       "%s(): Could not set IE for priv=%p [priv_bss_idx=%d]!\n",
3803 				       __func__, pmpriv, pmpriv->bss_index);
3804 				/* TODO: hiow to handle this error case??  ignore & continue? */
3805 			}
3806 			/* free ioctl buffer memory before we leave */
3807 			pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
3808 							(t_u8 *)pioctl_req);
3809 		}
3810 		/* continue traffic for reactivated interfaces */
3811 		PRINTM(MMSG,
3812 		       "11h: Radar Detected - restarting host tx traffic.\n");
3813 		for (i = 0; i < pstate_rdh->priv_list_count; i++)
3814 			wlan_11h_tx_enable(pstate_rdh->priv_list[i]);
3815 
3816 		pstate_rdh->stage = RDH_OFF;	/* DONE! */
3817 		PRINTM(MCMD_D, "%s(): finished - stage(%d)=%s\n",
3818 		       __func__, pstate_rdh->stage,
3819 		       rdh_stage_str[pstate_rdh->stage]);
3820 
3821 		break;
3822 
3823 	default:
3824 		pstate_rdh->stage = RDH_OFF;	/* cancel RDH to unblock Tx packets */
3825 		break;
3826 	}
3827 
3828 	LEAVE();
3829 	return ret;
3830 }
3831 
3832 /**
3833  *  @brief DFS Event Preprocessing.
3834  *  Operates directly on pmadapter variables.
3835  *
3836  *  1. EVENT_RADAR_DETECTED comes from firmware without specific
3837  *     bss_num/bss_type.  Find it an appropriate interface and
3838  *     update event_cause field in event_buf.
3839  *
3840  *  @param pmadapter    Pointer to mlan_adapter
3841  *
3842  *  @return    MLAN_STATUS_SUCCESS (update successful)
3843  *          or MLAN_STATUS_FAILURE (no change)
3844  */
3845 mlan_status
wlan_11h_dfs_event_preprocessing(mlan_adapter * pmadapter)3846 wlan_11h_dfs_event_preprocessing(mlan_adapter *pmadapter)
3847 {
3848 	mlan_status ret = MLAN_STATUS_FAILURE;
3849 	mlan_private *pmpriv = MNULL;
3850 	mlan_private *priv_list[MLAN_MAX_BSS_NUM];
3851 
3852 	ENTER();
3853 	switch (pmadapter->event_cause & EVENT_ID_MASK) {
3854 	case EVENT_RADAR_DETECTED:
3855 		/* find active intf:  prefer dfs_master over dfs_slave */
3856 		if (wlan_get_privs_by_two_cond(pmadapter,
3857 					       wlan_11h_is_master_active_on_dfs_chan,
3858 					       wlan_11h_is_dfs_master,
3859 					       MTRUE, priv_list)) {
3860 			pmpriv = priv_list[0];
3861 			PRINTM(MINFO, "%s: found dfs_master priv=%p\n",
3862 			       __func__, pmpriv);
3863 		} else if (wlan_get_privs_by_two_cond(pmadapter,
3864 						      wlan_11h_is_slave_active_on_dfs_chan,
3865 						      wlan_11h_is_dfs_slave,
3866 						      MTRUE, priv_list)) {
3867 			pmpriv = priv_list[0];
3868 			PRINTM(MINFO, "%s: found dfs_slave priv=%p\n",
3869 			       __func__, pmpriv);
3870 		} else if (pmadapter->state_dfs.dfs_check_pending) {
3871 			pmpriv = (mlan_private *)(pmadapter->state_dfs.
3872 						  dfs_check_priv);
3873 			PRINTM(MINFO, "%s: found dfs priv=%p\n", __func__,
3874 			       pmpriv);
3875 		}
3876 
3877 		/* update event_cause if we found an appropriate priv */
3878 		if (pmpriv) {
3879 			pmlan_buffer pmevbuf = pmadapter->pmlan_buffer_event;
3880 			t_u32 new_event_cause =
3881 				pmadapter->event_cause & EVENT_ID_MASK;
3882 			new_event_cause |=
3883 				((GET_BSS_NUM(pmpriv) & 0xff) << 16) |
3884 				((pmpriv->bss_type & 0xff) << 24);
3885 			PRINTM(MINFO, "%s: priv - bss_num=%d, bss_type=%d\n",
3886 			       __func__, GET_BSS_NUM(pmpriv), pmpriv->bss_type);
3887 			memcpy(pmadapter, pmevbuf->pbuf + pmevbuf->data_offset,
3888 			       &new_event_cause, sizeof(new_event_cause));
3889 			ret = MLAN_STATUS_SUCCESS;
3890 		} else {
3891 			PRINTM(MERROR,
3892 			       "Failed to find dfs master/slave priv\n");
3893 			ret = MLAN_STATUS_FAILURE;
3894 		}
3895 		break;
3896 	}
3897 
3898 	LEAVE();
3899 	return ret;
3900 }
3901 
3902 /**
3903  *  @brief try to switch to a non-dfs channel
3904  *
3905  *  @param priv    Void pointer to mlan_private
3906  *
3907  *  @param chan    pointer to channel
3908  *
3909  *  @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE or MLAN_STATUS_PENDING
3910  */
3911 mlan_status
wlan_11h_switch_non_dfs_chan(mlan_private * priv,t_u8 * chan)3912 wlan_11h_switch_non_dfs_chan(mlan_private *priv, t_u8 *chan)
3913 {
3914 	mlan_status ret = MLAN_STATUS_FAILURE;
3915 	t_u32 i;
3916 	t_u32 rand_entry;
3917 	t_u8 def_chan;
3918 	t_u8 rand_tries = 0;
3919 	region_chan_t *chn_tbl = MNULL;
3920 	pmlan_adapter pmadapter = priv->adapter;
3921 
3922 	ENTER();
3923 
3924 #ifdef DFS_TESTING_SUPPORT
3925 	if (!pmadapter->dfs_test_params.no_channel_change_on_radar &&
3926 	    pmadapter->dfs_test_params.fixed_new_channel_on_radar) {
3927 		PRINTM(MCMD_D, "dfs_testing - user fixed new_chan=%d\n",
3928 		       pmadapter->dfs_test_params.fixed_new_channel_on_radar);
3929 		*chan = pmadapter->dfs_test_params.fixed_new_channel_on_radar;
3930 
3931 		LEAVE();
3932 		return MLAN_STATUS_SUCCESS;
3933 	}
3934 #endif
3935 
3936 	/*get the channel table first */
3937 	for (i = 0; i < MAX_REGION_CHANNEL_NUM; i++) {
3938 		if (pmadapter->region_channel[i].band == BAND_A
3939 		    && pmadapter->region_channel[i].valid) {
3940 			chn_tbl = &pmadapter->region_channel[i];
3941 			break;
3942 		}
3943 	}
3944 
3945 	if (!chn_tbl || !chn_tbl->pcfp)
3946 		goto done;
3947 
3948 	do {
3949 		rand_entry =
3950 			wlan_11h_get_random_num(pmadapter) % chn_tbl->num_cfp;
3951 		def_chan = (t_u8)chn_tbl->pcfp[rand_entry].channel;
3952 		rand_tries++;
3953 	} while ((wlan_11h_is_channel_under_nop(pmadapter, def_chan) ||
3954 		  chn_tbl->pcfp[rand_entry].passive_scan_or_radar_detect ==
3955 		  MTRUE) && (rand_tries < MAX_SWITCH_CHANNEL_RETRIES));
3956 
3957 	/* meet max retries, use the lowest non-dfs channel */
3958 	if (rand_tries == MAX_SWITCH_CHANNEL_RETRIES) {
3959 		for (i = 0; i < chn_tbl->num_cfp; i++) {
3960 			if (chn_tbl->pcfp[i].passive_scan_or_radar_detect ==
3961 			    MFALSE &&
3962 			    !wlan_11h_is_channel_under_nop(pmadapter,
3963 							   (t_u8)chn_tbl->
3964 							   pcfp[i].channel)) {
3965 				def_chan = (t_u8)chn_tbl->pcfp[i].channel;
3966 				break;
3967 			}
3968 		}
3969 		if (i == chn_tbl->num_cfp)
3970 			goto done;
3971 	}
3972 
3973 	*chan = def_chan;
3974 	ret = MLAN_STATUS_SUCCESS;
3975 done:
3976 	LEAVE();
3977 	return ret;
3978 }
3979