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