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