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